Merge branch 'for-2.6.39' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 16 Mar 2011 15:22:41 +0000 (08:22 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 16 Mar 2011 15:22:41 +0000 (08:22 -0700)
* 'for-2.6.39' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu:
  percpu, x86: Add arch-specific this_cpu_cmpxchg_double() support
  percpu: Generic support for this_cpu_cmpxchg_double()
  alpha: use L1_CACHE_BYTES for cacheline size in the linker script
  percpu: align percpu readmostly subsection to cacheline

Fix up trivial conflict in arch/x86/kernel/vmlinux.lds.S due to the
percpu alignment having changed ("x86: Reduce back the alignment of the
per-CPU data section")

2053 files changed:
.gitignore
.mailmap
Documentation/ABI/testing/sysfs-platform-at91 [new file with mode: 0644]
Documentation/DocBook/drm.tmpl
Documentation/DocBook/filesystems.tmpl
Documentation/RCU/whatisRCU.txt
Documentation/devicetree/bindings/ata/fsl-sata.txt [new file with mode: 0644]
Documentation/devicetree/bindings/eeprom.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/8xxx_gpio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/led.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/ce4100-i2c.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/fsl-i2c.txt [new file with mode: 0644]
Documentation/devicetree/bindings/marvell.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/fsl-esdhc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/mmc-spi-slot.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/fsl-upm-nand.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/mtd-physmap.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/can/mpc5xxx-mscan.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/can/sja1000.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/fsl-tsec-phy.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/mdio-gpio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/phy.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pci/83xx-512x-pci.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/4xx/cpm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/4xx/emac.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/4xx/ndfc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/4xx/ppc440spe-adma.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/4xx/reboot.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/board.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/brg.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/i2c.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/pic.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/usb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/gpio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/network.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/firmware.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/par_io.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/pincfg.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/ucc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/usb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/serial.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/diu.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/dma.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/ecm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/gtm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/guts.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/lbc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/mcm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/mcu-mpc8349emitx.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/mpc5121-psc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/mpc5200.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/mpic.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/pmc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/sec.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/ssi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/nintendo/gamecube.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/nintendo/wii.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/rtc-cmos.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/fsl-spi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/spi-bus.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/fsl-usb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/usb-ehci.txt [new file with mode: 0644]
Documentation/devicetree/bindings/x86/ce4100.txt [new file with mode: 0644]
Documentation/devicetree/bindings/x86/interrupt.txt [new file with mode: 0644]
Documentation/devicetree/bindings/x86/timer.txt [new file with mode: 0644]
Documentation/devicetree/bindings/xilinx.txt [new file with mode: 0644]
Documentation/devicetree/booting-without-of.txt [new file with mode: 0644]
Documentation/feature-removal-schedule.txt
Documentation/filesystems/ntfs.txt
Documentation/hwmon/jc42
Documentation/hwmon/k10temp
Documentation/kernel-parameters.txt
Documentation/memory-barriers.txt
Documentation/networking/00-INDEX
Documentation/networking/Makefile
Documentation/networking/bonding.txt
Documentation/networking/dns_resolver.txt
Documentation/networking/ip-sysctl.txt
Documentation/powerpc/booting-without-of.txt [deleted file]
Documentation/powerpc/dts-bindings/4xx/cpm.txt [deleted file]
Documentation/powerpc/dts-bindings/4xx/emac.txt [deleted file]
Documentation/powerpc/dts-bindings/4xx/ndfc.txt [deleted file]
Documentation/powerpc/dts-bindings/4xx/ppc440spe-adma.txt [deleted file]
Documentation/powerpc/dts-bindings/4xx/reboot.txt [deleted file]
Documentation/powerpc/dts-bindings/can/sja1000.txt [deleted file]
Documentation/powerpc/dts-bindings/ecm.txt [deleted file]
Documentation/powerpc/dts-bindings/eeprom.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/83xx-512x-pci.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/8xxx_gpio.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/board.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/can.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/brg.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/i2c.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/pic.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/usb.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/gpio.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/network.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/firmware.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/par_io.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/pincfg.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/ucc.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/usb.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/cpm_qe/serial.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/diu.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/dma.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/esdhc.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/gtm.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/guts.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/i2c.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/lbc.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/mcm.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/mcu-mpc8349emitx.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/mpc5121-psc.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/mpc5200.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/mpic.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/msi-pic.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/pmc.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/sata.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/sec.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/spi.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/ssi.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/tsec.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/upm-nand.txt [deleted file]
Documentation/powerpc/dts-bindings/fsl/usb.txt [deleted file]
Documentation/powerpc/dts-bindings/gpio/gpio.txt [deleted file]
Documentation/powerpc/dts-bindings/gpio/led.txt [deleted file]
Documentation/powerpc/dts-bindings/gpio/mdio.txt [deleted file]
Documentation/powerpc/dts-bindings/marvell.txt [deleted file]
Documentation/powerpc/dts-bindings/mmc-spi-slot.txt [deleted file]
Documentation/powerpc/dts-bindings/mtd-physmap.txt [deleted file]
Documentation/powerpc/dts-bindings/nintendo/gamecube.txt [deleted file]
Documentation/powerpc/dts-bindings/nintendo/wii.txt [deleted file]
Documentation/powerpc/dts-bindings/phy.txt [deleted file]
Documentation/powerpc/dts-bindings/spi-bus.txt [deleted file]
Documentation/powerpc/dts-bindings/usb-ehci.txt [deleted file]
Documentation/powerpc/dts-bindings/xilinx.txt [deleted file]
Documentation/rtc.txt
Documentation/scheduler/sched-stats.txt
Documentation/sound/alsa/HD-Audio-Models.txt
Documentation/spinlocks.txt
Documentation/trace/ftrace-design.txt
Documentation/trace/ftrace.txt
Documentation/trace/kprobetrace.txt
Documentation/workqueue.txt
MAINTAINERS
Makefile
arch/alpha/Kconfig
arch/alpha/include/asm/fcntl.h
arch/alpha/include/asm/futex.h
arch/alpha/include/asm/rwsem.h
arch/alpha/kernel/irq.c
arch/alpha/kernel/irq_alpha.c
arch/alpha/kernel/irq_i8259.c
arch/alpha/kernel/irq_impl.h
arch/alpha/kernel/irq_pyxis.c
arch/alpha/kernel/irq_srm.c
arch/alpha/kernel/osf_sys.c
arch/alpha/kernel/sys_alcor.c
arch/alpha/kernel/sys_cabriolet.c
arch/alpha/kernel/sys_dp264.c
arch/alpha/kernel/sys_eb64p.c
arch/alpha/kernel/sys_eiger.c
arch/alpha/kernel/sys_jensen.c
arch/alpha/kernel/sys_marvel.c
arch/alpha/kernel/sys_mikasa.c
arch/alpha/kernel/sys_noritake.c
arch/alpha/kernel/sys_rawhide.c
arch/alpha/kernel/sys_rx164.c
arch/alpha/kernel/sys_sable.c
arch/alpha/kernel/sys_takara.c
arch/alpha/kernel/sys_titan.c
arch/alpha/kernel/sys_wildfire.c
arch/alpha/kernel/time.c
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/compressed/.gitignore
arch/arm/common/Kconfig
arch/arm/include/asm/futex.h
arch/arm/include/asm/hardware/cache-l2x0.h
arch/arm/include/asm/hardware/sp810.h
arch/arm/include/asm/io.h
arch/arm/include/asm/mach/arch.h
arch/arm/include/asm/memory.h
arch/arm/include/asm/pgalloc.h
arch/arm/include/asm/tlb.h
arch/arm/include/asm/tlbflush.h
arch/arm/kernel/head.S
arch/arm/kernel/hw_breakpoint.c
arch/arm/kernel/kprobes-decode.c
arch/arm/kernel/module.c
arch/arm/kernel/perf_event.c
arch/arm/kernel/pmu.c
arch/arm/kernel/ptrace.c
arch/arm/kernel/setup.c
arch/arm/kernel/signal.c
arch/arm/kernel/smp_twd.c
arch/arm/kernel/time.c
arch/arm/kernel/vmlinux.lds.S
arch/arm/mach-clps711x/include/mach/time.h
arch/arm/mach-davinci/cpufreq.c
arch/arm/mach-davinci/devices-da8xx.c
arch/arm/mach-davinci/gpio-tnetv107x.c
arch/arm/mach-davinci/include/mach/clkdev.h
arch/arm/mach-ep93xx/core.c
arch/arm/mach-ep93xx/gpio.c
arch/arm/mach-footbridge/include/mach/debug-macro.S
arch/arm/mach-imx/mach-mx25_3ds.c
arch/arm/mach-ixp4xx/common.c
arch/arm/mach-ixp4xx/include/mach/timex.h
arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
arch/arm/mach-mxs/clock-mx23.c
arch/arm/mach-mxs/clock-mx28.c
arch/arm/mach-mxs/clock.c
arch/arm/mach-mxs/gpio.c
arch/arm/mach-mxs/include/mach/clock.h
arch/arm/mach-omap1/include/mach/entry-macro.S
arch/arm/mach-omap1/irq.c
arch/arm/mach-omap1/lcd_dma.c
arch/arm/mach-omap1/time.c
arch/arm/mach-omap2/board-devkit8000.c
arch/arm/mach-omap2/board-omap4panda.c
arch/arm/mach-omap2/board-rm680.c
arch/arm/mach-omap2/clkt_dpll.c
arch/arm/mach-omap2/dma.c
arch/arm/mach-omap2/include/mach/entry-macro.S
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/mailbox.c
arch/arm/mach-omap2/mux.c
arch/arm/mach-omap2/pm-debug.c
arch/arm/mach-omap2/pm24xx.c
arch/arm/mach-omap2/pm34xx.c
arch/arm/mach-omap2/prcm_mpu44xx.h
arch/arm/mach-omap2/serial.c
arch/arm/mach-omap2/smartreflex.c
arch/arm/mach-omap2/timer-gp.c
arch/arm/mach-omap2/voltage.c
arch/arm/mach-pxa/colibri-evalboard.c
arch/arm/mach-pxa/colibri-pxa300.c
arch/arm/mach-pxa/include/mach/colibri.h
arch/arm/mach-pxa/palm27x.c
arch/arm/mach-pxa/pm.c
arch/arm/mach-pxa/pxa25x.c
arch/arm/mach-pxa/tosa-bt.c
arch/arm/mach-pxa/tosa.c
arch/arm/mach-realview/Kconfig
arch/arm/mach-realview/platsmp.c
arch/arm/mach-s3c2440/Kconfig
arch/arm/mach-s3c2440/include/mach/gta02.h
arch/arm/mach-s3c64xx/clock.c
arch/arm/mach-s3c64xx/dma.c
arch/arm/mach-s3c64xx/gpiolib.c
arch/arm/mach-s3c64xx/mach-smdk6410.c
arch/arm/mach-s3c64xx/setup-keypad.c
arch/arm/mach-s3c64xx/setup-sdhci.c
arch/arm/mach-s5p6442/include/mach/map.h
arch/arm/mach-s5p64x0/include/mach/gpio.h
arch/arm/mach-s5p64x0/include/mach/map.h
arch/arm/mach-s5pc100/include/mach/map.h
arch/arm/mach-s5pv210/include/mach/map.h
arch/arm/mach-s5pv210/mach-aquila.c
arch/arm/mach-s5pv210/mach-goni.c
arch/arm/mach-s5pv310/Kconfig
arch/arm/mach-s5pv310/include/mach/map.h
arch/arm/mach-s5pv310/include/mach/sysmmu.h
arch/arm/mach-sa1100/collie.c
arch/arm/mach-shmobile/Kconfig
arch/arm/mach-shmobile/board-ag5evm.c
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/board-g3evm.c
arch/arm/mach-shmobile/board-mackerel.c
arch/arm/mach-shmobile/clock-sh7372.c
arch/arm/mach-shmobile/clock-sh73a0.c
arch/arm/mach-shmobile/include/mach/head-ap4evb.txt
arch/arm/mach-shmobile/include/mach/head-mackerel.txt
arch/arm/mach-shmobile/intc-sh7372.c
arch/arm/mach-shmobile/intc-sh73a0.c
arch/arm/mach-spear3xx/include/mach/spear320.h
arch/arm/mach-tegra/gpio.c
arch/arm/mach-tegra/include/mach/clk.h
arch/arm/mach-tegra/include/mach/clkdev.h
arch/arm/mach-tegra/include/mach/kbc.h [new file with mode: 0644]
arch/arm/mach-tegra/irq.c
arch/arm/mach-versatile/Kconfig
arch/arm/mach-vexpress/platsmp.c
arch/arm/mach-vexpress/v2m.c
arch/arm/mm/Kconfig
arch/arm/mm/cache-l2x0.c
arch/arm/mm/init.c
arch/arm/mm/proc-v7.S
arch/arm/oprofile/common.c
arch/arm/plat-mxc/include/mach/uncompress.h
arch/arm/plat-omap/mailbox.c
arch/arm/plat-pxa/mfp.c
arch/arm/plat-s5p/Kconfig
arch/arm/plat-s5p/Makefile
arch/arm/plat-s5p/dev-uart.c
arch/arm/plat-s5p/include/plat/sysmmu.h [deleted file]
arch/arm/plat-s5p/sysmmu.c
arch/arm/plat-samsung/dev-ts.c
arch/arm/plat-samsung/dev-uart.c
arch/arm/plat-samsung/include/plat/pm.h
arch/arm/plat-spear/include/plat/uncompress.h
arch/arm/plat-spear/include/plat/vmalloc.h
arch/arm/tools/mach-types
arch/avr32/include/asm/pgalloc.h
arch/blackfin/include/asm/bfin_serial.h
arch/blackfin/kernel/time.c
arch/blackfin/lib/outs.S
arch/blackfin/mach-common/cache.S
arch/cris/arch-v10/kernel/time.c
arch/cris/arch-v32/kernel/smp.c
arch/cris/arch-v32/kernel/time.c
arch/cris/kernel/vmlinux.lds.S
arch/frv/include/asm/futex.h
arch/frv/kernel/futex.c
arch/frv/kernel/time.c
arch/h8300/kernel/time.c
arch/h8300/kernel/timer/timer8.c
arch/ia64/include/asm/futex.h
arch/ia64/include/asm/rwsem.h
arch/ia64/include/asm/xen/hypercall.h
arch/ia64/kernel/time.c
arch/ia64/xen/suspend.c
arch/ia64/xen/time.c
arch/m32r/kernel/irq.c
arch/m32r/kernel/time.c
arch/m68k/amiga/config.c
arch/m68k/atari/ataints.c
arch/m68k/atari/config.c
arch/m68k/atari/debug.c
arch/m68k/bvme6000/config.c
arch/m68k/include/asm/atarihw.h
arch/m68k/include/asm/string.h
arch/m68k/kernel/time.c
arch/m68k/lib/string.c
arch/m68k/mvme147/config.c
arch/m68k/mvme16x/config.c
arch/m68k/sun3/sun3ints.c
arch/m68knommu/kernel/time.c
arch/m68knommu/kernel/vmlinux.lds.S
arch/m68knommu/lib/Makefile
arch/m68knommu/lib/memmove.c [new file with mode: 0644]
arch/m68knommu/platform/5249/intc2.c
arch/m68knommu/platform/68328/entry.S
arch/m68knommu/platform/68360/commproc.c
arch/m68knommu/platform/68360/config.c
arch/m68knommu/platform/68360/entry.S
arch/m68knommu/platform/68360/ints.c
arch/m68knommu/platform/coldfire/entry.S
arch/microblaze/include/asm/futex.h
arch/microblaze/include/asm/irqflags.h
arch/microblaze/include/asm/pci-bridge.h
arch/microblaze/include/asm/pgtable.h
arch/microblaze/include/asm/prom.h
arch/microblaze/kernel/cpu/pvr.c
arch/microblaze/kernel/head.S
arch/microblaze/kernel/hw_exception_handler.S
arch/microblaze/kernel/prom_parse.c
arch/microblaze/kernel/setup.c
arch/microblaze/lib/fastcopy.S
arch/microblaze/pci/pci-common.c
arch/mips/Kconfig
arch/mips/alchemy/mtx-1/board_setup.c
arch/mips/alchemy/mtx-1/platform.c
arch/mips/alchemy/xxs1500/board_setup.c
arch/mips/include/asm/futex.h
arch/mips/include/asm/perf_event.h
arch/mips/kernel/ftrace.c
arch/mips/kernel/perf_event.c
arch/mips/kernel/perf_event_mipsxx.c
arch/mips/kernel/signal.c
arch/mips/kernel/signal32.c
arch/mips/kernel/smp.c
arch/mips/kernel/syscall.c
arch/mips/kernel/vpe.c
arch/mips/loongson/Kconfig
arch/mips/loongson/common/cmdline.c
arch/mips/loongson/common/machtype.c
arch/mips/math-emu/ieee754int.h
arch/mips/mm/init.c
arch/mips/mm/tlbex.c
arch/mips/pci/ops-pmcmsp.c
arch/mips/pmc-sierra/Kconfig
arch/mips/pmc-sierra/msp71xx/msp_time.c
arch/mn10300/include/asm/atomic.h
arch/mn10300/include/asm/uaccess.h
arch/mn10300/kernel/time.c
arch/mn10300/mm/cache-inv-icache.c
arch/parisc/hpux/sys_hpux.c
arch/parisc/include/asm/fcntl.h
arch/parisc/include/asm/futex.h
arch/parisc/kernel/pdc_cons.c
arch/parisc/kernel/time.c
arch/powerpc/include/asm/futex.h
arch/powerpc/include/asm/lppaca.h
arch/powerpc/include/asm/machdep.h
arch/powerpc/include/asm/mmu-book3e.h
arch/powerpc/include/asm/page.h
arch/powerpc/include/asm/pci-bridge.h
arch/powerpc/include/asm/prom.h
arch/powerpc/include/asm/rwsem.h
arch/powerpc/kernel/cpu_setup_6xx.S
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/machine_kexec.c
arch/powerpc/kernel/paca.c
arch/powerpc/kernel/pci-common.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/prom_parse.c
arch/powerpc/mm/numa.c
arch/powerpc/mm/tlb_hash64.c
arch/powerpc/platforms/cell/spufs/syscalls.c
arch/powerpc/platforms/iseries/dt.c
arch/powerpc/platforms/iseries/setup.c
arch/powerpc/platforms/pseries/lpar.c
arch/s390/Kconfig
arch/s390/boot/compressed/misc.c
arch/s390/crypto/sha_common.c
arch/s390/include/asm/atomic.h
arch/s390/include/asm/cache.h
arch/s390/include/asm/cacheflush.h
arch/s390/include/asm/futex.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/rwsem.h
arch/s390/include/asm/tlb.h
arch/s390/include/asm/uaccess.h
arch/s390/kernel/traps.c
arch/s390/lib/uaccess.h
arch/s390/lib/uaccess_pt.c
arch/s390/lib/uaccess_std.c
arch/s390/mm/pgtable.c
arch/sh/Kconfig
arch/sh/Makefile
arch/sh/boards/mach-ecovec24/setup.c
arch/sh/boot/Makefile
arch/sh/boot/compressed/Makefile
arch/sh/boot/compressed/misc.c
arch/sh/include/asm/futex-irq.h
arch/sh/include/asm/futex.h
arch/sh/include/asm/pgtable.h
arch/sh/include/asm/rwsem.h
arch/sh/include/asm/sections.h
arch/sh/kernel/cpu/sh4/setup-sh7750.c
arch/sh/kernel/topology.c
arch/sh/lib/delay.c
arch/sh/mm/cache.c
arch/sparc/include/asm/fcntl.h
arch/sparc/include/asm/futex_64.h
arch/sparc/include/asm/pcr.h
arch/sparc/include/asm/rwsem.h
arch/sparc/kernel/iommu.c
arch/sparc/kernel/pcic.c
arch/sparc/kernel/pcr.c
arch/sparc/kernel/smp_64.c
arch/sparc/kernel/time_32.c
arch/sparc/kernel/una_asm_32.S
arch/sparc/lib/atomic32.c
arch/sparc/lib/bitext.c
arch/tile/include/asm/futex.h
arch/um/Kconfig.common
arch/um/Kconfig.x86
arch/um/drivers/mconsole_kern.c
arch/um/drivers/ubd_kern.c
arch/um/kernel/irq.c
arch/x86/Kconfig
arch/x86/Kconfig.cpu
arch/x86/boot/compressed/mkpiggy.c
arch/x86/ia32/ia32entry.S
arch/x86/include/asm/acpi.h
arch/x86/include/asm/amd_nb.h
arch/x86/include/asm/apic.h
arch/x86/include/asm/apicdef.h
arch/x86/include/asm/bootparam.h
arch/x86/include/asm/ce4100.h [new file with mode: 0644]
arch/x86/include/asm/cpu.h
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/e820.h
arch/x86/include/asm/entry_arch.h
arch/x86/include/asm/frame.h
arch/x86/include/asm/futex.h
arch/x86/include/asm/hw_irq.h
arch/x86/include/asm/init.h
arch/x86/include/asm/io_apic.h
arch/x86/include/asm/ipi.h
arch/x86/include/asm/irq.h
arch/x86/include/asm/irq_controller.h [new file with mode: 0644]
arch/x86/include/asm/irq_vectors.h
arch/x86/include/asm/kdebug.h
arch/x86/include/asm/mmu_context.h
arch/x86/include/asm/mpspec.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/nmi.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/olpc_ofw.h
arch/x86/include/asm/page_types.h
arch/x86/include/asm/paravirt.h
arch/x86/include/asm/percpu.h
arch/x86/include/asm/perf_event_p4.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/prom.h
arch/x86/include/asm/rwsem.h
arch/x86/include/asm/smp.h
arch/x86/include/asm/smpboot_hooks.h
arch/x86/include/asm/system.h
arch/x86/include/asm/system_64.h [deleted file]
arch/x86/include/asm/topology.h
arch/x86/include/asm/unistd_32.h
arch/x86/include/asm/unistd_64.h
arch/x86/include/asm/uv/uv_bau.h
arch/x86/include/asm/x86_init.h
arch/x86/include/asm/xen/hypercall.h
arch/x86/include/asm/xen/page.h
arch/x86/include/asm/xen/pci.h
arch/x86/kernel/Makefile
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/acpi/sleep.c
arch/x86/kernel/alternative.c
arch/x86/kernel/amd_nb.c
arch/x86/kernel/apb_timer.c
arch/x86/kernel/aperture_64.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/apic_flat_64.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/hw_nmi.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/apic/ipi.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_cluster.c
arch/x86/kernel/apic/x2apic_phys.c
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/asm-offsets.c
arch/x86/kernel/asm-offsets_32.c
arch/x86/kernel/asm-offsets_64.c
arch/x86/kernel/check.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c
arch/x86/kernel/cpu/cpufreq/powernow-k8.c
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/mcheck/mce_amd.c
arch/x86/kernel/cpu/mtrr/main.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event_amd.c
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_intel_ds.c
arch/x86/kernel/cpu/perf_event_p4.c
arch/x86/kernel/cpu/perf_event_p6.c
arch/x86/kernel/cpu/perfctr-watchdog.c
arch/x86/kernel/devicetree.c [new file with mode: 0644]
arch/x86/kernel/dumpstack.c
arch/x86/kernel/dumpstack_64.c
arch/x86/kernel/e820.c
arch/x86/kernel/early-quirks.c
arch/x86/kernel/entry_32.S
arch/x86/kernel/entry_64.S
arch/x86/kernel/ftrace.c
arch/x86/kernel/head_32.S
arch/x86/kernel/hpet.c
arch/x86/kernel/i8259.c
arch/x86/kernel/ioport.c
arch/x86/kernel/irq.c
arch/x86/kernel/irqinit.c
arch/x86/kernel/kgdb.c
arch/x86/kernel/kprobes.c
arch/x86/kernel/microcode_amd.c
arch/x86/kernel/microcode_core.c
arch/x86/kernel/process.c
arch/x86/kernel/reboot.c
arch/x86/kernel/rtc.c
arch/x86/kernel/setup.c
arch/x86/kernel/setup_percpu.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/syscall_table_32.S
arch/x86/kernel/vmlinux.lds.S
arch/x86/kernel/x8664_ksyms_64.c
arch/x86/kernel/x86_init.c
arch/x86/kvm/svm.c
arch/x86/kvm/trace.h
arch/x86/lguest/boot.c
arch/x86/lib/atomic64_386_32.S
arch/x86/lib/atomic64_cx8_32.S
arch/x86/lib/checksum_32.S
arch/x86/lib/memmove_64.S [new file with mode: 0644]
arch/x86/lib/memmove_64.c [deleted file]
arch/x86/lib/rwsem_64.S
arch/x86/lib/semaphore_32.S
arch/x86/lib/thunk_32.S
arch/x86/lib/thunk_64.S
arch/x86/mm/Makefile
arch/x86/mm/amdtopology_64.c
arch/x86/mm/fault.c
arch/x86/mm/init.c
arch/x86/mm/init_32.c
arch/x86/mm/init_64.c
arch/x86/mm/numa.c
arch/x86/mm/numa_32.c
arch/x86/mm/numa_64.c
arch/x86/mm/numa_emulation.c [new file with mode: 0644]
arch/x86/mm/numa_internal.h [new file with mode: 0644]
arch/x86/mm/pageattr.c
arch/x86/mm/pgtable.c
arch/x86/mm/srat_32.c
arch/x86/mm/srat_64.c
arch/x86/mm/tlb.c
arch/x86/pci/amd_bus.c
arch/x86/pci/ce4100.c
arch/x86/pci/xen.c
arch/x86/platform/ce4100/ce4100.c
arch/x86/platform/ce4100/falconfalls.dts [new file with mode: 0644]
arch/x86/platform/mrst/mrst.c
arch/x86/platform/mrst/vrtc.c
arch/x86/platform/olpc/Makefile
arch/x86/platform/olpc/olpc_dt.c
arch/x86/platform/uv/tlb_uv.c
arch/x86/platform/uv/uv_irq.c
arch/x86/platform/visws/visws_quirks.c
arch/x86/xen/Kconfig
arch/x86/xen/enlighten.c
arch/x86/xen/mmu.c
arch/x86/xen/p2m.c
arch/x86/xen/setup.c
arch/x86/xen/smp.c
arch/x86/xen/suspend.c
arch/x86/xen/time.c
arch/x86/xen/xen-head.S
arch/x86/xen/xen-ops.h
arch/xtensa/include/asm/rwsem.h
arch/xtensa/kernel/time.c
block/blk-core.c
block/blk-flush.c
block/blk-lib.c
block/blk-throttle.c
block/cfq-iosched.c
block/elevator.c
block/genhd.c
block/ioctl.c
drivers/acpi/acpica/aclocal.h
drivers/acpi/acpica/evgpe.c
drivers/acpi/acpica/evxfgpe.c
drivers/acpi/debugfs.c
drivers/acpi/numa.c
drivers/acpi/osl.c
drivers/acpi/video_detect.c
drivers/acpi/wakeup.c
drivers/ata/ahci.c
drivers/ata/libata-core.c
drivers/ata/libata-scsi.c
drivers/ata/pata_hpt366.c
drivers/ata/pata_hpt37x.c
drivers/ata/pata_hpt3x2n.c
drivers/ata/pata_mpc52xx.c
drivers/atm/idt77105.c
drivers/atm/solos-pci.c
drivers/base/power/runtime.c
drivers/block/Makefile
drivers/block/aoe/Makefile
drivers/block/cciss.c
drivers/block/floppy.c
drivers/block/loop.c
drivers/block/nbd.c
drivers/block/xen-blkfront.c
drivers/bluetooth/ath3k.c
drivers/bluetooth/btusb.c
drivers/cdrom/cdrom.c
drivers/char/Makefile
drivers/char/agp/Kconfig
drivers/char/agp/amd-k7-agp.c
drivers/char/agp/amd64-agp.c
drivers/char/agp/intel-agp.c
drivers/char/agp/intel-agp.h
drivers/char/agp/intel-gtt.c
drivers/char/bfin_jtag_comm.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/mmtimer.c
drivers/char/pcmcia/cm4000_cs.c
drivers/char/pcmcia/ipwireless/main.c
drivers/char/tpm/tpm.c
drivers/char/virtio_console.c [new file with mode: 0644]
drivers/clocksource/tcb_clksrc.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_conservative.c
drivers/cpufreq/cpufreq_ondemand.c
drivers/dma/amba-pl08x.c
drivers/dma/imx-dma.c
drivers/dma/imx-sdma.c
drivers/dma/ipu/ipu_idmac.c
drivers/edac/amd64_edac.c
drivers/firmware/dmi_scan.c
drivers/gpio/langwell_gpio.c
drivers/gpio/ml_ioh_gpio.c
drivers/gpio/pca953x.c
drivers/gpio/pch_gpio.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_info.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_ringbuffer.h
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_dma.c
drivers/gpu/drm/nouveau/nouveau_drv.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_mem.c
drivers/gpu/drm/nouveau/nouveau_mm.c
drivers/gpu/drm/nouveau/nouveau_notifier.c
drivers/gpu/drm/nouveau/nouveau_pm.c
drivers/gpu/drm/nouveau/nouveau_temp.c
drivers/gpu/drm/nouveau/nv04_dfp.c
drivers/gpu/drm/nouveau/nv40_graph.c
drivers/gpu/drm/nouveau/nv50_evo.c
drivers/gpu/drm/nouveau/nv50_graph.c
drivers/gpu/drm/nouveau/nv50_instmem.c
drivers/gpu/drm/nouveau/nv50_vm.c
drivers/gpu/drm/nouveau/nvc0_graph.c
drivers/gpu/drm/nouveau/nvc0_grctx.c
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_blit_kms.c
drivers/gpu/drm/radeon/evergreen_blit_shaders.c
drivers/gpu/drm/radeon/evergreend.h
drivers/gpu/drm/radeon/mkregtable.c
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r100_track.h
drivers/gpu/drm/radeon/r200.c
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/r300_reg.h
drivers/gpu/drm/radeon/r420.c
drivers/gpu/drm/radeon/r520.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_blit.c
drivers/gpu/drm/radeon/r600_blit_kms.c
drivers/gpu/drm/radeon/r600_blit_shaders.c
drivers/gpu/drm/radeon/r600_cp.c
drivers/gpu/drm/radeon/r600_cs.c
drivers/gpu/drm/radeon/r600_reg.h
drivers/gpu/drm/radeon/r600d.h
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_drv.h
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_fb.c
drivers/gpu/drm/radeon/radeon_gem.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_legacy_crtc.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/radeon_reg.h
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/reg_srcs/r300
drivers/gpu/drm/radeon/reg_srcs/r420
drivers/gpu/drm/radeon/reg_srcs/rs600
drivers/gpu/drm/radeon/reg_srcs/rv515
drivers/gpu/drm/radeon/rs400.c
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/radeon/rs690.c
drivers/gpu/drm/radeon/rv515.c
drivers/gpu/drm/radeon/rv770.c
drivers/gpu/drm/radeon/rv770d.h
drivers/gpu/stub/Kconfig
drivers/hwmon/Kconfig
drivers/hwmon/ad7414.c
drivers/hwmon/adt7411.c
drivers/hwmon/applesmc.c
drivers/hwmon/asus_atk0110.c
drivers/hwmon/emc1403.c
drivers/hwmon/f71882fg.c
drivers/hwmon/jc42.c
drivers/hwmon/k10temp.c
drivers/hwmon/lis3lv02d.c
drivers/hwmon/lm63.c
drivers/hwmon/lm85.c
drivers/i2c/busses/i2c-eg20t.c
drivers/i2c/busses/i2c-ocores.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-stu300.c
drivers/i2c/i2c-core.c
drivers/idle/intel_idle.c
drivers/infiniband/core/sa_query.c
drivers/infiniband/core/ucma.c
drivers/infiniband/hw/amso1100/c2_vq.c
drivers/infiniband/hw/cxgb4/cm.c
drivers/infiniband/hw/cxgb4/qp.c
drivers/infiniband/hw/nes/nes_hw.c
drivers/infiniband/hw/qib/qib_iba7322.c
drivers/infiniband/hw/qib/qib_rc.c
drivers/input/gameport/gameport.c
drivers/input/input.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/tegra-kbc.c [new file with mode: 0644]
drivers/input/keyboard/tnetv107x-keypad.c
drivers/input/misc/ixp4xx-beeper.c
drivers/input/misc/rotary_encoder.c
drivers/input/mouse/synaptics.c
drivers/input/mouse/synaptics.h
drivers/input/serio/ct82c710.c
drivers/input/serio/serio.c
drivers/input/serio/serport.c
drivers/input/sparse-keymap.c
drivers/input/tablet/wacom_sys.c
drivers/input/tablet/wacom_wac.c
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/bu21013_ts.c
drivers/input/touchscreen/tnetv107x-ts.c
drivers/input/touchscreen/tps6507x-ts.c
drivers/input/touchscreen/wacom_w8001.c
drivers/isdn/hardware/eicon/istream.c
drivers/isdn/hisax/isdnl2.c
drivers/isdn/hysdn/hysdn_defs.h
drivers/isdn/hysdn/hysdn_init.c
drivers/isdn/hysdn/hysdn_net.c
drivers/isdn/hysdn/hysdn_procconf.c
drivers/isdn/icn/icn.c
drivers/leds/leds-pwm.c
drivers/md/linear.c
drivers/md/md.c
drivers/md/md.h
drivers/md/multipath.c
drivers/md/raid0.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/media/common/tuners/tda8290.c
drivers/media/dvb/dvb-usb/dib0700_devices.c
drivers/media/dvb/dvb-usb/lmedm04.c
drivers/media/dvb/frontends/dib7000m.c
drivers/media/dvb/frontends/dib7000m.h
drivers/media/dvb/mantis/mantis_pci.c
drivers/media/rc/ir-lirc-codec.c
drivers/media/rc/ir-raw.c
drivers/media/rc/keymaps/rc-rc6-mce.c
drivers/media/rc/mceusb.c
drivers/media/rc/nuvoton-cir.c
drivers/media/rc/nuvoton-cir.h
drivers/media/rc/rc-main.c
drivers/media/rc/streamzap.c
drivers/media/video/au0828/au0828-video.c
drivers/media/video/cx18/cx18-cards.c
drivers/media/video/cx18/cx18-driver.c
drivers/media/video/cx18/cx18-driver.h
drivers/media/video/cx18/cx18-dvb.c
drivers/media/video/cx23885/cx23885-i2c.c
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/gspca/zc3xx.c
drivers/media/video/hdpvr/hdpvr-core.c
drivers/media/video/hdpvr/hdpvr-i2c.c
drivers/media/video/hdpvr/hdpvr.h
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/ivtv/ivtv-irq.c
drivers/media/video/mem2mem_testdev.c
drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
drivers/media/video/s2255drv.c
drivers/media/video/saa7115.c
drivers/memstick/core/memstick.c
drivers/message/fusion/mptbase.h
drivers/message/fusion/mptctl.c
drivers/message/fusion/mptscsih.c
drivers/message/i2o/driver.c
drivers/mfd/asic3.c
drivers/mfd/davinci_voicecodec.c
drivers/mfd/tps6586x.c
drivers/mfd/ucb1x00-ts.c
drivers/mfd/wm8994-core.c
drivers/misc/bmp085.c
drivers/misc/iwmc3200top/iwmc3200top.h
drivers/misc/iwmc3200top/main.c
drivers/misc/tifm_core.c
drivers/misc/vmw_balloon.c
drivers/mmc/core/core.c
drivers/mmc/core/sdio.c
drivers/mmc/host/bfin_sdh.c
drivers/mmc/host/jz4740_mmc.c
drivers/mmc/host/mmc_spi.c
drivers/mmc/host/mmci.c
drivers/mmc/host/mmci.h
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/ushc.c
drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/chips/jedec_probe.c
drivers/mtd/maps/amd76xrom.c
drivers/mtd/mtd_blkdevs.c
drivers/mtd/nand/omap2.c
drivers/mtd/nand/r852.c
drivers/mtd/onenand/generic.c
drivers/mtd/onenand/omap2.c
drivers/mtd/sm_ftl.c
drivers/mtd/ubi/build.c
drivers/net/ariadne.c
drivers/net/atl1c/atl1c_main.c
drivers/net/benet/be_cmds.c
drivers/net/benet/be_main.c
drivers/net/bnx2.c
drivers/net/bnx2.h
drivers/net/bnx2x/bnx2x.h
drivers/net/bnx2x/bnx2x_cmn.c
drivers/net/bnx2x/bnx2x_cmn.h
drivers/net/bnx2x/bnx2x_ethtool.c
drivers/net/bnx2x/bnx2x_init.h
drivers/net/bnx2x/bnx2x_link.c
drivers/net/bnx2x/bnx2x_main.c
drivers/net/bnx2x/bnx2x_stats.c
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_3ad.h
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_main.c
drivers/net/can/Kconfig
drivers/net/can/Makefile
drivers/net/can/at91_can.c
drivers/net/can/janz-ican3.c
drivers/net/can/mcp251x.c
drivers/net/can/mscan/Kconfig
drivers/net/can/pch_can.c
drivers/net/can/softing/Kconfig [new file with mode: 0644]
drivers/net/can/softing/Makefile [new file with mode: 0644]
drivers/net/can/softing/softing.h [new file with mode: 0644]
drivers/net/can/softing/softing_cs.c [new file with mode: 0644]
drivers/net/can/softing/softing_fw.c [new file with mode: 0644]
drivers/net/can/softing/softing_main.c [new file with mode: 0644]
drivers/net/can/softing/softing_platform.h [new file with mode: 0644]
drivers/net/cnic.c
drivers/net/cxgb4/cxgb4_main.c
drivers/net/cxgb4vf/cxgb4vf_main.c
drivers/net/cxgb4vf/t4vf_hw.c
drivers/net/davinci_emac.c
drivers/net/depca.c
drivers/net/dl2k.c
drivers/net/dm9000.c
drivers/net/dnet.c
drivers/net/e1000/e1000_hw.c
drivers/net/e1000/e1000_hw.h
drivers/net/e1000/e1000_osdep.h
drivers/net/e1000e/netdev.c
drivers/net/enc28j60.c
drivers/net/ethoc.c
drivers/net/fec.c
drivers/net/forcedeth.c
drivers/net/igbvf/vf.c
drivers/net/ixgbe/ixgbe_common.c
drivers/net/ixgbe/ixgbe_fcoe.c
drivers/net/ixgbe/ixgbe_fcoe.h
drivers/net/ixgbe/ixgbe_main.c
drivers/net/ixgbe/ixgbe_sriov.c
drivers/net/ixgbe/ixgbe_x540.c
drivers/net/macb.c
drivers/net/macvtap.c
drivers/net/mlx4/main.c
drivers/net/niu.c
drivers/net/pch_gbe/pch_gbe.h
drivers/net/pch_gbe/pch_gbe_main.c
drivers/net/pcmcia/axnet_cs.c
drivers/net/pcmcia/fmvj18x_cs.c
drivers/net/r6040.c
drivers/net/r8169.c
drivers/net/sfc/ethtool.c
drivers/net/sis900.c
drivers/net/skge.c
drivers/net/smsc911x.c
drivers/net/stmmac/stmmac_main.c
drivers/net/tg3.c
drivers/net/tg3.h
drivers/net/usb/cdc_ncm.c
drivers/net/usb/dm9601.c
drivers/net/usb/hso.c
drivers/net/usb/kaweth.c
drivers/net/usb/usbnet.c
drivers/net/virtio_net.c
drivers/net/vxge/vxge-config.c
drivers/net/wireless/ath/ath5k/dma.c
drivers/net/wireless/ath/ath5k/pcu.c
drivers/net/wireless/ath/ath5k/phy.c
drivers/net/wireless/ath/ath9k/ar9002_hw.c
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/carl9170/rx.c
drivers/net/wireless/ath/carl9170/usb.c
drivers/net/wireless/ipw2x00/ipw2100.c
drivers/net/wireless/ipw2x00/ipw2100.h
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/ipw2x00/ipw2200.h
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/p54/p54pci.c
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtlwifi/efuse.c
drivers/net/wireless/rtlwifi/pci.c
drivers/net/wireless/wl1251/main.c
drivers/net/wireless/wl12xx/spi.c
drivers/net/xen-netfront.c
drivers/nfc/Kconfig
drivers/nfc/pn544.c
drivers/of/Kconfig
drivers/of/Makefile
drivers/of/of_pci.c [new file with mode: 0644]
drivers/of/pdt.c
drivers/parport/share.c
drivers/pci/pci-sysfs.c
drivers/pci/xen-pcifront.c
drivers/pcmcia/pcmcia_resource.c
drivers/pcmcia/pxa2xx_base.c
drivers/pcmcia/pxa2xx_base.h
drivers/pcmcia/pxa2xx_colibri.c
drivers/pcmcia/pxa2xx_lubbock.c
drivers/platform/x86/Kconfig
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/asus_acpi.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/intel_pmic_gpio.c
drivers/platform/x86/intel_scu_ipc.c
drivers/platform/x86/intel_scu_ipcutil.c
drivers/platform/x86/tc1100-wmi.c
drivers/platform/x86/thinkpad_acpi.c
drivers/pps/clients/pps-ktimer.c
drivers/pps/clients/pps_parport.c
drivers/pps/generators/Kconfig
drivers/pps/generators/pps_gen_parport.c
drivers/pps/kapi.c
drivers/rapidio/rio-sysfs.c
drivers/regulator/mc13xxx-regulator-core.c
drivers/regulator/wm831x-dcdc.c
drivers/rtc/Kconfig
drivers/rtc/class.c
drivers/rtc/interface.c
drivers/rtc/rtc-at32ap700x.c
drivers/rtc/rtc-at91rm9200.c
drivers/rtc/rtc-at91sam9.c
drivers/rtc/rtc-bfin.c
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-davinci.c
drivers/rtc/rtc-dev.c
drivers/rtc/rtc-ds1286.c
drivers/rtc/rtc-ds1305.c
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds1374.c
drivers/rtc/rtc-ds1511.c
drivers/rtc/rtc-ds1553.c
drivers/rtc/rtc-ds3232.c
drivers/rtc/rtc-jz4740.c
drivers/rtc/rtc-m41t80.c
drivers/rtc/rtc-m48t59.c
drivers/rtc/rtc-mc13xxx.c
drivers/rtc/rtc-mpc5121.c
drivers/rtc/rtc-mrst.c
drivers/rtc/rtc-msm6242.c
drivers/rtc/rtc-mv.c
drivers/rtc/rtc-mxc.c
drivers/rtc/rtc-nuc900.c
drivers/rtc/rtc-omap.c
drivers/rtc/rtc-pcap.c
drivers/rtc/rtc-pcf50633.c
drivers/rtc/rtc-pl030.c
drivers/rtc/rtc-pl031.c
drivers/rtc/rtc-proc.c
drivers/rtc/rtc-pxa.c
drivers/rtc/rtc-rp5c01.c
drivers/rtc/rtc-rs5c372.c
drivers/rtc/rtc-rx8025.c
drivers/rtc/rtc-s3c.c
drivers/rtc/rtc-sa1100.c
drivers/rtc/rtc-sh.c
drivers/rtc/rtc-stmp3xxx.c
drivers/rtc/rtc-test.c
drivers/rtc/rtc-twl.c
drivers/rtc/rtc-vr41xx.c
drivers/rtc/rtc-wm831x.c
drivers/rtc/rtc-wm8350.c
drivers/s390/block/dasd_alias.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/xpram.c
drivers/s390/char/keyboard.c
drivers/s390/char/tape.h
drivers/s390/char/tape_34xx.c
drivers/s390/char/tape_3590.c
drivers/s390/cio/qdio_main.c
drivers/s390/net/netiucv.c
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/smsgiucv.c
drivers/scsi/arcmsr/arcmsr.h
drivers/scsi/arcmsr/arcmsr_attr.c
drivers/scsi/arcmsr/arcmsr_hba.c
drivers/scsi/be2iscsi/be_main.c
drivers/scsi/libsas/sas_scsi_host.c
drivers/scsi/mpt2sas/mpt2sas_base.c
drivers/scsi/mpt2sas/mpt2sas_scsih.c
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_tgt_lib.c
drivers/scsi/scsi_transport_fc.c
drivers/sh/intc/chip.c
drivers/spi/pxa2xx_spi.c
drivers/spi/pxa2xx_spi_pci.c
drivers/spi/spi_sh_msiof.c
drivers/spi/xilinx_spi.c
drivers/ssb/pcmcia.c
drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c
drivers/staging/brcm80211/sys/wl_mac80211.c
drivers/staging/brcm80211/sys/wlc_mac80211.c
drivers/staging/brcm80211/sys/wlc_pub.h
drivers/staging/comedi/Kconfig
drivers/staging/comedi/drivers/mite.c
drivers/staging/comedi/drivers/ni_6527.c
drivers/staging/comedi/drivers/ni_65xx.c
drivers/staging/comedi/drivers/ni_660x.c
drivers/staging/comedi/drivers/ni_670x.c
drivers/staging/comedi/drivers/ni_labpc.c
drivers/staging/comedi/drivers/ni_pcidio.c
drivers/staging/comedi/drivers/ni_pcimio.c
drivers/staging/hv/blkvsc_drv.c
drivers/staging/hv/netvsc.c
drivers/staging/hv/netvsc_drv.c
drivers/staging/iio/adc/ad7476_core.c
drivers/staging/iio/adc/ad7887_core.c
drivers/staging/iio/adc/ad799x_core.c
drivers/staging/iio/dac/ad5446.c
drivers/staging/intel_sst/intelmid_v2_control.c
drivers/staging/lirc/lirc_zilog.c
drivers/staging/msm/msm_fb.c
drivers/staging/olpc_dcon/olpc_dcon.c
drivers/staging/rt2860/rt_main_dev.c
drivers/staging/rt2860/usb_main_dev.c
drivers/staging/rtl8712/hal_init.c
drivers/staging/rtl8712/usb_intf.c
drivers/staging/sm7xx/smtcfb.c
drivers/staging/speakup/kobjects.c
drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c
drivers/staging/tidspbridge/core/io_sm.c
drivers/staging/tidspbridge/core/tiomap3430.c
drivers/staging/tidspbridge/include/dspbridge/io_sm.h
drivers/staging/usbip/stub.h
drivers/staging/usbip/stub_dev.c
drivers/staging/usbip/stub_rx.c
drivers/staging/usbip/vhci.h
drivers/staging/usbip/vhci_hcd.c
drivers/staging/usbip/vhci_rx.c
drivers/staging/vme/bridges/Module.symvers [deleted file]
drivers/staging/xgifb/vb_setmode.c
drivers/staging/zram/zram_drv.c
drivers/target/Makefile
drivers/target/target_core_configfs.c
drivers/target/target_core_device.c
drivers/target/target_core_fabric_configfs.c
drivers/target/target_core_iblock.c
drivers/target/target_core_mib.c [deleted file]
drivers/target/target_core_mib.h [deleted file]
drivers/target/target_core_pscsi.c
drivers/target/target_core_tmr.c
drivers/target/target_core_tpg.c
drivers/target/target_core_transport.c
drivers/thermal/Kconfig
drivers/thermal/thermal_sys.c
drivers/tty/hvc/Makefile
drivers/tty/hvc/virtio_console.c [deleted file]
drivers/tty/n_gsm.c
drivers/tty/n_hdlc.c
drivers/tty/serial/68328serial.c
drivers/tty/serial/68360serial.c
drivers/tty/serial/8250.c
drivers/tty/serial/Kconfig
drivers/tty/serial/bfin_5xx.c
drivers/tty/serial/max3100.c
drivers/tty/serial/max3107.c
drivers/tty/serial/sb1250-duart.c
drivers/tty/serial/serial_cs.c
drivers/tty/sysrq.c
drivers/tty/tty_io.c
drivers/tty/vt/selection.c
drivers/tty/vt/vc_screen.c
drivers/tty/vt/vt.c
drivers/tty/vt/vt_ioctl.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-wdm.c
drivers/usb/core/endpoint.c
drivers/usb/core/hcd-pci.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/core/quirks.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/ci13xxx_udc.c
drivers/usb/gadget/ci13xxx_udc.h
drivers/usb/gadget/composite.c
drivers/usb/gadget/f_mass_storage.c
drivers/usb/gadget/f_phonet.c
drivers/usb/gadget/pch_udc.c
drivers/usb/gadget/printer.c
drivers/usb/gadget/r8a66597-udc.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-au1xxx.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-fsl.h
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-mxc.c
drivers/usb/host/ehci-omap.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-xilinx-of.c
drivers/usb/host/fsl-mph-dr-of.c
drivers/usb/host/sl811-hcd.c
drivers/usb/host/xhci-dbg.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/misc/usbled.c
drivers/usb/misc/uss720.c
drivers/usb/musb/blackfin.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_core.h
drivers/usb/musb/musb_dma.h
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/musb_gadget.h
drivers/usb/musb/musb_host.c
drivers/usb/musb/musbhsdma.h
drivers/usb/musb/omap2430.c
drivers/usb/otg/Kconfig
drivers/usb/otg/nop-usb-xceiv.c
drivers/usb/otg/ulpi.c
drivers/usb/serial/ch341.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/digi_acceleport.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/generic.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_tables.h
drivers/usb/serial/iuu_phoenix.c
drivers/usb/serial/keyspan.h
drivers/usb/serial/keyspan_pda.c
drivers/usb/serial/moto_modem.c
drivers/usb/serial/option.c
drivers/usb/serial/oti6858.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/pl2303.h
drivers/usb/serial/qcaux.c
drivers/usb/serial/siemens_mpi.c
drivers/usb/serial/sierra.c
drivers/usb/serial/spcp8x5.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/usb_debug.c
drivers/usb/serial/usb_wwan.c
drivers/usb/serial/visor.c
drivers/usb/storage/unusual_cypress.h
drivers/usb/storage/unusual_devs.h
drivers/vhost/net.c
drivers/vhost/vhost.h
drivers/video/arkfb.c
drivers/video/aty/aty128fb.c
drivers/video/aty/atyfb_base.c
drivers/video/aty/radeon_pm.c
drivers/video/backlight/ltv350qv.c
drivers/video/bf537-lq035.c
drivers/video/chipsfb.c
drivers/video/console/fbcon.c
drivers/video/console/vgacon.c
drivers/video/da8xx-fb.c
drivers/video/fbmem.c
drivers/video/fbsysfs.c
drivers/video/geode/gxfb_core.c
drivers/video/geode/lxfb_core.c
drivers/video/i810/i810_main.c
drivers/video/jz4740_fb.c
drivers/video/mx3fb.c
drivers/video/nuc900fb.c
drivers/video/nvidia/nvidia.c
drivers/video/ps3fb.c
drivers/video/pxa168fb.c
drivers/video/pxa3xx-gcu.c
drivers/video/s3fb.c
drivers/video/savage/savagefb_driver.c
drivers/video/sh_mobile_hdmi.c
drivers/video/sh_mobile_lcdcfb.c
drivers/video/sm501fb.c
drivers/video/tmiofb.c
drivers/video/via/viafbdev.c
drivers/video/vt8623fb.c
drivers/video/xen-fbfront.c
drivers/w1/masters/omap_hdq.c
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/cpwd.c
drivers/watchdog/hpwdt.c
drivers/watchdog/m548x_wdt.c [deleted file]
drivers/watchdog/m54xx_wdt.c [new file with mode: 0644]
drivers/watchdog/sbc_fitpc2_wdt.c
drivers/watchdog/sch311x_wdt.c
drivers/watchdog/w83697ug_wdt.c
drivers/xen/balloon.c
drivers/xen/events.c
drivers/xen/manage.c
drivers/xen/platform-pci.c
fs/Kconfig
fs/Makefile
fs/afs/write.c
fs/aio.c
fs/block_dev.c
fs/btrfs/acl.c
fs/btrfs/compression.c
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/export.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/extent_map.c
fs/btrfs/file-item.c
fs/btrfs/file.c
fs/btrfs/free-space-cache.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/lzo.c
fs/btrfs/ordered-data.c
fs/btrfs/print-tree.c
fs/btrfs/relocation.c
fs/btrfs/super.c
fs/btrfs/transaction.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/ceph/caps.c
fs/ceph/dir.c
fs/ceph/inode.c
fs/ceph/mds_client.c
fs/ceph/snap.c
fs/ceph/super.c
fs/ceph/xattr.c
fs/cifs/Kconfig
fs/cifs/Makefile
fs/cifs/README
fs/cifs/cifs_dfs_ref.c
fs/cifs/cifsacl.c
fs/cifs/cifsencrypt.c
fs/cifs/cifsencrypt.h [deleted file]
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/link.c
fs/cifs/md4.c [deleted file]
fs/cifs/md5.c [deleted file]
fs/cifs/md5.h [deleted file]
fs/cifs/misc.c
fs/cifs/netmisc.c
fs/cifs/readdir.c
fs/cifs/sess.c
fs/cifs/smbdes.c
fs/cifs/smbencrypt.c
fs/cifs/transport.c
fs/compat.c
fs/dcache.c
fs/dlm/lowcomms.c
fs/ecryptfs/dentry.c
fs/ecryptfs/ecryptfs_kernel.h
fs/ecryptfs/file.c
fs/ecryptfs/inode.c
fs/eventfd.c
fs/eventpoll.c
fs/exec.c
fs/exofs/inode.c
fs/exofs/namei.c
fs/exportfs/expfs.c
fs/ext2/namei.c
fs/ext3/namei.c
fs/ext3/super.c
fs/ext4/ext4.h
fs/ext4/extents.c
fs/ext4/file.c
fs/ext4/mballoc.c
fs/ext4/namei.c
fs/ext4/page-io.c
fs/ext4/super.c
fs/fat/inode.c
fs/fat/namei_vfat.c
fs/fcntl.c
fs/fhandle.c [new file with mode: 0644]
fs/file_table.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/gfs2/dentry.c
fs/gfs2/export.c
fs/gfs2/glock.c
fs/gfs2/main.c
fs/hfs/dir.c
fs/hfsplus/extents.c
fs/hfsplus/part_tbl.c
fs/hfsplus/super.c
fs/hfsplus/wrapper.c
fs/inode.c
fs/internal.h
fs/ioctl.c
fs/isofs/export.c
fs/jbd2/journal.c
fs/jbd2/transaction.c
fs/jfs/namei.c
fs/lockd/host.c
fs/minix/namei.c
fs/namei.c
fs/namespace.c
fs/nfs/callback.c
fs/nfs/callback.h
fs/nfs/callback_proc.c
fs/nfs/callback_xdr.c
fs/nfs/client.c
fs/nfs/delegation.c
fs/nfs/direct.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs3acl.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4filelayoutdev.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4xdr.c
fs/nfs/nfsroot.c
fs/nfs/pnfs.c
fs/nfs/unlink.c
fs/nfs/write.c
fs/nfs_common/nfsacl.c
fs/nfsctl.c
fs/nfsd/nfs4callback.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/state.h
fs/nfsd/vfs.c
fs/nilfs2/btnode.c
fs/nilfs2/btnode.h
fs/nilfs2/mdt.c
fs/nilfs2/namei.c
fs/nilfs2/page.c
fs/nilfs2/page.h
fs/nilfs2/segment.c
fs/nilfs2/super.c
fs/ntfs/mft.c
fs/ocfs2/dcache.c
fs/ocfs2/export.c
fs/ocfs2/journal.h
fs/ocfs2/quota.h
fs/ocfs2/quota_global.c
fs/ocfs2/refcounttree.c
fs/ocfs2/super.c
fs/open.c
fs/partitions/ldm.c
fs/partitions/mac.c
fs/partitions/osf.c
fs/posix_acl.c
fs/proc/array.c
fs/proc/base.c
fs/proc/consoles.c
fs/proc/inode.c
fs/proc/proc_devtree.c
fs/proc/proc_sysctl.c
fs/reiserfs/inode.c
fs/reiserfs/journal.c
fs/reiserfs/namei.c
fs/reiserfs/xattr.c
fs/squashfs/block.c
fs/squashfs/xz_wrapper.c
fs/squashfs/zlib_wrapper.c
fs/stat.c
fs/statfs.c
fs/super.c
fs/sysv/namei.c
fs/ubifs/dir.c
fs/udf/namei.c
fs/ufs/namei.c
fs/xfs/linux-2.6/xfs_buf.c
fs/xfs/linux-2.6/xfs_discard.c
fs/xfs/linux-2.6/xfs_export.c
fs/xfs/linux-2.6/xfs_ioctl.c
fs/xfs/quota/xfs_qm.c
fs/xfs/xfs_alloc.h
fs/xfs/xfs_bmap.c
fs/xfs/xfs_buf_item.c
fs/xfs/xfs_extfree_item.c
fs/xfs/xfs_fsops.c
fs/xfs/xfs_iomap.c
fs/xfs/xfs_log.h
fs/xfs/xfs_log_cil.c
fs/xfs/xfs_mru_cache.c
fs/xfs/xfs_trans.c
include/asm-generic/cputime.h
include/asm-generic/fcntl.h
include/asm-generic/futex.h
include/asm-generic/pgtable.h
include/asm-generic/sections.h
include/asm-generic/unistd.h
include/asm-generic/vmlinux.lds.h
include/drm/drmP.h
include/drm/drm_crtc.h
include/drm/drm_pciids.h
include/keys/rxrpc-type.h
include/linux/Kbuild
include/linux/blkdev.h
include/linux/blktrace_api.h
include/linux/caif/Kbuild [new file with mode: 0644]
include/linux/ceph/messenger.h
include/linux/cgroup.h
include/linux/cgroup_subsys.h
include/linux/console.h
include/linux/dcbnl.h
include/linux/debugobjects.h
include/linux/device.h
include/linux/exportfs.h
include/linux/fcntl.h
include/linux/file.h
include/linux/freezer.h
include/linux/fs.h
include/linux/ftrace.h
include/linux/ftrace_event.h
include/linux/gfp.h
include/linux/hrtimer.h
include/linux/huge_mm.h
include/linux/i2c.h
include/linux/input/bu21013.h
include/linux/input/matrix_keypad.h
include/linux/interrupt.h
include/linux/irq.h
include/linux/irqdesc.h
include/linux/jiffies.h
include/linux/kernel.h
include/linux/klist.h
include/linux/kthread.h
include/linux/list.h
include/linux/mfd/wm8994/core.h
include/linux/mm.h
include/linux/mmc/sh_mmcif.h
include/linux/module.h
include/linux/mroute.h
include/linux/mroute6.h
include/linux/namei.h
include/linux/netdevice.h
include/linux/nfs_fs_sb.h
include/linux/nfsacl.h
include/linux/of.h
include/linux/of_pci.h [new file with mode: 0644]
include/linux/oprofile.h
include/linux/pci_ids.h
include/linux/perf_event.h
include/linux/plist.h
include/linux/pm.h
include/linux/pm_wakeup.h
include/linux/posix-clock.h [new file with mode: 0644]
include/linux/posix-timers.h
include/linux/posix_acl.h
include/linux/ptrace.h
include/linux/res_counter.h
include/linux/ring_buffer.h
include/linux/rio_regs.h
include/linux/rtc.h
include/linux/rwlock_types.h
include/linux/rwsem-spinlock.h
include/linux/rwsem.h
include/linux/sched.h
include/linux/security.h
include/linux/spinlock_types.h
include/linux/sunrpc/bc_xprt.h
include/linux/sunrpc/sched.h
include/linux/sunrpc/svc_xprt.h
include/linux/syscalls.h
include/linux/sysctl.h
include/linux/sysrq.h
include/linux/thermal.h
include/linux/thread_info.h
include/linux/time.h
include/linux/timex.h
include/linux/tracepoint.h
include/linux/usb/cdc.h
include/linux/usb/hcd.h
include/linux/usb/msm_hsusb_hw.h
include/linux/usb/serial.h
include/linux/virtio_console.h
include/linux/workqueue.h
include/net/bluetooth/hci_core.h
include/net/genetlink.h
include/net/ipv6.h
include/net/netfilter/nf_conntrack_ecache.h
include/net/netfilter/nf_tproxy_core.h
include/net/sch_generic.h
include/net/sock.h
include/pcmcia/ds.h
include/scsi/scsi.h
include/sound/wm8903.h
include/target/target_core_base.h
include/target/target_core_transport.h
include/trace/events/block.h
include/trace/events/mce.h
include/trace/events/module.h
include/trace/events/skb.h
include/trace/ftrace.h
include/xen/events.h
include/xen/interface/io/blkif.h
include/xen/interface/xen.h
include/xen/xen-ops.h
init/Kconfig
init/calibrate.c
kernel/audit_watch.c
kernel/capability.c
kernel/cgroup.c
kernel/compat.c
kernel/cpuset.c
kernel/cred.c
kernel/futex.c
kernel/hrtimer.c
kernel/irq/Kconfig
kernel/irq/autoprobe.c
kernel/irq/chip.c
kernel/irq/compat.h [new file with mode: 0644]
kernel/irq/debug.h [new file with mode: 0644]
kernel/irq/handle.c
kernel/irq/internals.h
kernel/irq/irqdesc.c
kernel/irq/manage.c
kernel/irq/migration.c
kernel/irq/pm.c
kernel/irq/proc.c
kernel/irq/resend.c
kernel/irq/settings.h [new file with mode: 0644]
kernel/irq/spurious.c
kernel/module.c
kernel/perf_event.c
kernel/posix-cpu-timers.c
kernel/posix-timers.c
kernel/power/main.c
kernel/power/process.c
kernel/power/snapshot.c
kernel/printk.c
kernel/ptrace.c
kernel/rcupdate.c
kernel/rcutiny_plugin.h
kernel/rcutorture.c
kernel/rtmutex-debug.c
kernel/rtmutex-tester.c
kernel/rtmutex.c
kernel/rtmutex_common.h
kernel/sched.c
kernel/sched_autogroup.c
kernel/sched_autogroup.h
kernel/sched_debug.c
kernel/sched_fair.c
kernel/sched_idletask.c
kernel/sched_rt.c
kernel/sched_stoptask.c
kernel/softirq.c
kernel/sys.c
kernel/sys_ni.c
kernel/sysctl.c
kernel/sysctl_binary.c
kernel/time.c
kernel/time/Makefile
kernel/time/clockevents.c
kernel/time/jiffies.c
kernel/time/ntp.c
kernel/time/posix-clock.c [new file with mode: 0644]
kernel/time/tick-broadcast.c
kernel/time/tick-common.c
kernel/time/tick-internal.h
kernel/time/tick-oneshot.c
kernel/time/tick-sched.c
kernel/time/timekeeping.c
kernel/time/timer_list.c
kernel/timer.c
kernel/trace/blktrace.c
kernel/trace/ftrace.c
kernel/trace/ring_buffer.c
kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_entries.h
kernel/trace/trace_events.c
kernel/trace/trace_events_filter.c
kernel/trace/trace_export.c
kernel/trace/trace_kprobe.c
kernel/trace/trace_output.c
kernel/trace/trace_sched_switch.c
kernel/trace/trace_syscalls.c
kernel/tracepoint.c
kernel/watchdog.c
kernel/workqueue.c
lib/Kconfig.debug
lib/debugobjects.c
lib/list_debug.c
lib/nlattr.c
lib/plist.c
lib/radix-tree.c
lib/rbtree.c
lib/rwsem.c
lib/swiotlb.c
lib/textsearch.c
mm/Kconfig
mm/Makefile
mm/bootmem.c
mm/huge_memory.c
mm/kmemleak-test.c
mm/kmemleak.c
mm/memblock.c
mm/memcontrol.c
mm/memory-failure.c
mm/memory.c
mm/mempolicy.c
mm/migrate.c
mm/mlock.c
mm/mremap.c
mm/nobootmem.c [new file with mode: 0644]
mm/page_alloc.c
mm/pgtable-generic.c
mm/rmap.c
mm/shmem.c
mm/swapfile.c
mm/truncate.c
mm/vmscan.c
net/9p/trans_fd.c
net/Makefile
net/batman-adv/unicast.c
net/batman-adv/vis.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/l2cap.c
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/tty.c
net/bridge/Kconfig
net/bridge/br_fdb.c
net/bridge/br_input.c
net/bridge/br_multicast.c
net/bridge/br_private.h
net/caif/chnl_net.c
net/ceph/messenger.c
net/ceph/pagevec.c
net/core/dev.c
net/core/dev_addr_lists.c
net/core/ethtool.c
net/core/pktgen.c
net/core/rtnetlink.c
net/core/scm.c
net/core/skbuff.c
net/dcb/dcbnl.c
net/dccp/input.c
net/dns_resolver/dns_key.c
net/econet/af_econet.c
net/ipv4/af_inet.c
net/ipv4/arp.c
net/ipv4/devinet.c
net/ipv4/inet_timewait_sock.c
net/ipv4/inetpeer.c
net/ipv4/ip_gre.c
net/ipv4/ipip.c
net/ipv4/ipmr.c
net/ipv4/netfilter/arpt_mangle.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv6/addrconf.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6mr.c
net/ipv6/netfilter/ip6t_LOG.c
net/ipv6/raw.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/sysctl_net_ipv6.c
net/ipv6/xfrm6_policy.c
net/mac80211/cfg.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/mlme.c
net/mac80211/status.c
net/mac80211/tx.c
net/mac80211/util.c
net/netfilter/core.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_ecache.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_log.c
net/netfilter/nf_tproxy_core.c
net/netfilter/xt_TPROXY.c
net/netfilter/xt_iprange.c
net/netfilter/xt_socket.c
net/netlink/af_netlink.c
net/rds/ib.c
net/rds/ib.h
net/rds/ib_rdma.c
net/rds/ib_send.c
net/rds/loop.c
net/rxrpc/ar-input.c
net/rxrpc/ar-key.c
net/sched/sch_cbq.c
net/sched/sch_drr.c
net/sched/sch_dsmark.c
net/sched/sch_fifo.c
net/sched/sch_generic.c
net/sched/sch_hfsc.c
net/sched/sch_htb.c
net/sched/sch_multiq.c
net/sched/sch_netem.c
net/sched/sch_prio.c
net/sched/sch_red.c
net/sched/sch_sfq.c
net/sched/sch_tbf.c
net/sched/sch_teql.c
net/sctp/sm_make_chunk.c
net/sunrpc/sched.c
net/sunrpc/svcsock.c
net/sunrpc/xprtrdma/svc_rdma_transport.c
net/sunrpc/xprtsock.c
net/unix/af_unix.c
net/unix/garbage.c
net/wireless/wext-compat.c
net/x25/x25_facilities.c
net/x25/x25_in.c
net/x25/x25_link.c
net/xfrm/xfrm_policy.c
scripts/basic/fixdep.c
scripts/checkpatch.pl
scripts/kconfig/streamline_config.pl
scripts/mod/sumversion.c
scripts/package/builddeb
scripts/recordmcount.c
scripts/recordmcount.pl
scripts/rt-tester/rt-tester.py
scripts/rt-tester/t2-l1-2rt-sameprio.tst
scripts/rt-tester/t2-l1-pi.tst
scripts/rt-tester/t2-l1-signal.tst
scripts/rt-tester/t2-l2-2rt-deadlock.tst
scripts/rt-tester/t3-l1-pi-1rt.tst
scripts/rt-tester/t3-l1-pi-2rt.tst
scripts/rt-tester/t3-l1-pi-3rt.tst
scripts/rt-tester/t3-l1-pi-signal.tst
scripts/rt-tester/t3-l1-pi-steal.tst
scripts/rt-tester/t3-l2-pi.tst
scripts/rt-tester/t4-l2-pi-deboost.tst
scripts/rt-tester/t5-l4-pi-boost-deboost-setsched.tst
scripts/rt-tester/t5-l4-pi-boost-deboost.tst
security/commoncap.c
security/keys/internal.h
security/keys/key.c
security/keys/keyring.c
security/keys/request_key.c
security/security.c
security/selinux/hooks.c
sound/arm/aaci.c
sound/atmel/ac97c.c
sound/core/hrtimer.c
sound/core/jack.c
sound/drivers/mtpav.c
sound/oss/Makefile
sound/pci/au88x0/au88x0_core.c
sound/pci/azt3328.c
sound/pci/hda/hda_eld.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/oxygen/oxygen.h
sound/pci/oxygen/oxygen_mixer.c
sound/pci/oxygen/xonar_cs43xx.c
sound/pci/oxygen/xonar_dg.c
sound/pcmcia/pdaudiocf/pdaudiocf.h
sound/pcmcia/vx/vxp_ops.c
sound/soc/atmel/snd-soc-afeb9260.c
sound/soc/blackfin/bf5xx-ssm2602.c
sound/soc/codecs/cq93vc.c
sound/soc/codecs/cx20442.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8903.h
sound/soc/codecs/wm8978.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8995.c
sound/soc/codecs/wm9081.c
sound/soc/codecs/wm_hubs.c
sound/soc/davinci/davinci-evm.c
sound/soc/imx/eukrea-tlv320.c
sound/soc/omap/am3517evm.c
sound/soc/omap/ams-delta.c
sound/soc/pxa/corgi.c
sound/soc/pxa/e740_wm9705.c
sound/soc/pxa/e750_wm9705.c
sound/soc/pxa/e800_wm9712.c
sound/soc/pxa/em-x270.c
sound/soc/pxa/mioa701_wm9713.c
sound/soc/pxa/palm27x.c
sound/soc/pxa/poodle.c
sound/soc/pxa/spitz.c
sound/soc/pxa/tosa.c
sound/soc/pxa/zylonite.c
sound/soc/samsung/neo1973_gta02_wm8753.c
sound/soc/samsung/neo1973_wm8753.c
sound/soc/samsung/s3c24xx_simtec_hermes.c
sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
sound/soc/samsung/s3c24xx_uda134x.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/usb/caiaq/audio.c
sound/usb/caiaq/midi.c
sound/usb/card.c
sound/usb/mixer.c
sound/usb/pcm.c
sound/usb/quirks-table.h
sound/usb/quirks.c
sound/usb/usbaudio.h
tools/perf/.gitignore
tools/perf/Documentation/Makefile
tools/perf/Documentation/perf-list.txt
tools/perf/Documentation/perf-lock.txt
tools/perf/Documentation/perf-probe.txt
tools/perf/Documentation/perf-record.txt
tools/perf/Documentation/perf-stat.txt
tools/perf/Makefile
tools/perf/bench/sched-pipe.c
tools/perf/builtin-annotate.c
tools/perf/builtin-diff.c
tools/perf/builtin-inject.c
tools/perf/builtin-kmem.c
tools/perf/builtin-list.c
tools/perf/builtin-lock.c
tools/perf/builtin-probe.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-script.c
tools/perf/builtin-stat.c
tools/perf/builtin-test.c
tools/perf/builtin-timechart.c
tools/perf/builtin-top.c
tools/perf/perf.h
tools/perf/python/twatch.py [new file with mode: 0755]
tools/perf/util/annotate.c [new file with mode: 0644]
tools/perf/util/annotate.h [new file with mode: 0644]
tools/perf/util/build-id.c
tools/perf/util/cache.h
tools/perf/util/callchain.c
tools/perf/util/callchain.h
tools/perf/util/cgroup.c [new file with mode: 0644]
tools/perf/util/cgroup.h [new file with mode: 0644]
tools/perf/util/cpumap.c
tools/perf/util/cpumap.h
tools/perf/util/debug.c
tools/perf/util/debug.h
tools/perf/util/event.c
tools/perf/util/event.h
tools/perf/util/evlist.c [new file with mode: 0644]
tools/perf/util/evlist.h [new file with mode: 0644]
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/exec_cmd.c
tools/perf/util/header.c
tools/perf/util/header.h
tools/perf/util/hist.c
tools/perf/util/hist.h
tools/perf/util/include/linux/list.h
tools/perf/util/parse-events.c
tools/perf/util/parse-events.h
tools/perf/util/probe-event.c
tools/perf/util/probe-event.h
tools/perf/util/probe-finder.c
tools/perf/util/python.c [new file with mode: 0644]
tools/perf/util/scripting-engines/trace-event-python.c
tools/perf/util/session.c
tools/perf/util/session.h
tools/perf/util/setup.py [new file with mode: 0644]
tools/perf/util/strfilter.c [new file with mode: 0644]
tools/perf/util/strfilter.h [new file with mode: 0644]
tools/perf/util/svghelper.c
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/thread.c
tools/perf/util/thread.h
tools/perf/util/thread_map.c [new file with mode: 0644]
tools/perf/util/thread_map.h [new file with mode: 0644]
tools/perf/util/top.c [new file with mode: 0644]
tools/perf/util/top.h [new file with mode: 0644]
tools/perf/util/trace-event-parse.c
tools/perf/util/ui/browser.c
tools/perf/util/ui/browser.h
tools/perf/util/ui/browsers/annotate.c
tools/perf/util/ui/browsers/hists.c
tools/perf/util/ui/browsers/map.c
tools/perf/util/ui/browsers/top.c [new file with mode: 0644]
tools/perf/util/ui/helpline.c
tools/perf/util/ui/libslang.h
tools/perf/util/ui/setup.c
tools/perf/util/ui/ui.h [new file with mode: 0644]
tools/perf/util/ui/util.c
tools/perf/util/util.h
tools/power/x86/turbostat/turbostat.c
tools/testing/ktest/ktest.pl

index 8faa6c0..5d56a3f 100644 (file)
@@ -28,6 +28,7 @@ modules.builtin
 *.gz
 *.bz2
 *.lzma
+*.xz
 *.lzo
 *.patch
 *.gcno
index 581fd39..1eba28a 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -23,6 +23,7 @@ Andy Adamson <andros@citi.umich.edu>
 Arnaud Patard <arnaud.patard@rtp-net.org>
 Arnd Bergmann <arnd@arndb.de>
 Axel Dyks <xl@xlsigned.net>
+Axel Lin <axel.lin@gmail.com>
 Ben Gardner <bgardner@wabtec.com>
 Ben M Cahill <ben.m.cahill@intel.com>
 Björn Steinbrink <B.Steinbrink@gmx.de>
diff --git a/Documentation/ABI/testing/sysfs-platform-at91 b/Documentation/ABI/testing/sysfs-platform-at91
new file mode 100644 (file)
index 0000000..4cc6a86
--- /dev/null
@@ -0,0 +1,25 @@
+What:          /sys/devices/platform/at91_can/net/<iface>/mb0_id
+Date:          January 2011
+KernelVersion: 2.6.38
+Contact:       Marc Kleine-Budde <kernel@pengutronix.de>
+Description:
+               Value representing the can_id of mailbox 0.
+
+               Default: 0x7ff (standard frame)
+
+               Due to a chip bug (errata 50.2.6.3 & 50.3.5.3 in
+               "AT91SAM9263 Preliminary 6249H-ATARM-27-Jul-09") the
+               contents of mailbox 0 may be send under certain
+               conditions (even if disabled or in rx mode).
+
+               The workaround in the errata suggests not to use the
+               mailbox and load it with an unused identifier.
+
+               In order to use an extended can_id add the
+               CAN_EFF_FLAG (0x80000000U) to the can_id. Example:
+
+               - standard id 0x7ff:
+               echo 0x7ff      > /sys/class/net/can0/mb0_id
+
+               - extended id 0x1fffffff:
+               echo 0x9fffffff > /sys/class/net/can0/mb0_id
index 2861055..c279158 100644 (file)
@@ -73,8 +73,8 @@
       services.
     </para>
     <para>
-      The core of every DRM driver is struct drm_device.  Drivers
-      will typically statically initialize a drm_device structure,
+      The core of every DRM driver is struct drm_driver.  Drivers
+      will typically statically initialize a drm_driver structure,
       then pass it to drm_init() at load time.
     </para>
 
@@ -84,7 +84,7 @@
     <title>Driver initialization</title>
     <para>
       Before calling the DRM initialization routines, the driver must
-      first create and fill out a struct drm_device structure.
+      first create and fill out a struct drm_driver structure.
     </para>
     <programlisting>
       static struct drm_driver driver = {
index 5e87ad5..f51f285 100644 (file)
      </sect1>
   </chapter>
 
+  <chapter id="fs_events">
+     <title>Events based on file descriptors</title>
+!Efs/eventfd.c
+  </chapter>
+
   <chapter id="sysfs">
      <title>The Filesystem for Exporting Kernel Objects</title>
 !Efs/sysfs/file.c
index cfaac34..6ef6926 100644 (file)
@@ -849,6 +849,37 @@ All:  lockdep-checked RCU-protected pointer access
 See the comment headers in the source code (or the docbook generated
 from them) for more information.
 
+However, given that there are no fewer than four families of RCU APIs
+in the Linux kernel, how do you choose which one to use?  The following
+list can be helpful:
+
+a.     Will readers need to block?  If so, you need SRCU.
+
+b.     What about the -rt patchset?  If readers would need to block
+       in an non-rt kernel, you need SRCU.  If readers would block
+       in a -rt kernel, but not in a non-rt kernel, SRCU is not
+       necessary.
+
+c.     Do you need to treat NMI handlers, hardirq handlers,
+       and code segments with preemption disabled (whether
+       via preempt_disable(), local_irq_save(), local_bh_disable(),
+       or some other mechanism) as if they were explicit RCU readers?
+       If so, you need RCU-sched.
+
+d.     Do you need RCU grace periods to complete even in the face
+       of softirq monopolization of one or more of the CPUs?  For
+       example, is your code subject to network-based denial-of-service
+       attacks?  If so, you need RCU-bh.
+
+e.     Is your workload too update-intensive for normal use of
+       RCU, but inappropriate for other synchronization mechanisms?
+       If so, consider SLAB_DESTROY_BY_RCU.  But please be careful!
+
+f.     Otherwise, use RCU.
+
+Of course, this all assumes that you have determined that RCU is in fact
+the right tool for your job.
+
 
 8.  ANSWERS TO QUICK QUIZZES
 
diff --git a/Documentation/devicetree/bindings/ata/fsl-sata.txt b/Documentation/devicetree/bindings/ata/fsl-sata.txt
new file mode 100644 (file)
index 0000000..b46bcf4
--- /dev/null
@@ -0,0 +1,29 @@
+* Freescale 8xxx/3.0 Gb/s SATA nodes
+
+SATA nodes are defined to describe on-chip Serial ATA controllers.
+Each SATA port should have its own node.
+
+Required properties:
+- compatible        : compatible list, contains 2 entries, first is
+                "fsl,CHIP-sata", where CHIP is the processor
+                (mpc8315, mpc8379, etc.) and the second is
+                "fsl,pq-sata"
+- interrupts        : <interrupt mapping for SATA IRQ>
+- cell-index        : controller index.
+                          1 for controller @ 0x18000
+                          2 for controller @ 0x19000
+                          3 for controller @ 0x1a000
+                          4 for controller @ 0x1b000
+
+Optional properties:
+- interrupt-parent  : optional, if needed for interrupt mapping
+- reg               : <registers mapping>
+
+Example:
+       sata@18000 {
+               compatible = "fsl,mpc8379-sata", "fsl,pq-sata";
+               reg = <0x18000 0x1000>;
+               cell-index = <1>;
+               interrupts = <2c 8>;
+               interrupt-parent = < &ipic >;
+       };
diff --git a/Documentation/devicetree/bindings/eeprom.txt b/Documentation/devicetree/bindings/eeprom.txt
new file mode 100644 (file)
index 0000000..4342c10
--- /dev/null
@@ -0,0 +1,28 @@
+EEPROMs (I2C)
+
+Required properties:
+
+  - compatible : should be "<manufacturer>,<type>"
+                If there is no specific driver for <manufacturer>, a generic
+                driver based on <type> is selected. Possible types are:
+                24c00, 24c01, 24c02, 24c04, 24c08, 24c16, 24c32, 24c64,
+                24c128, 24c256, 24c512, 24c1024, spd
+
+  - reg : the I2C address of the EEPROM
+
+Optional properties:
+
+  - pagesize : the length of the pagesize for writing. Please consult the
+               manual of your device, that value varies a lot. A wrong value
+              may result in data loss! If not specified, a safety value of
+              '1' is used which will be very slow.
+
+  - read-only: this parameterless property disables writes to the eeprom
+
+Example:
+
+eeprom@52 {
+       compatible = "atmel,24c32";
+       reg = <0x52>;
+       pagesize = <32>;
+};
diff --git a/Documentation/devicetree/bindings/gpio/8xxx_gpio.txt b/Documentation/devicetree/bindings/gpio/8xxx_gpio.txt
new file mode 100644 (file)
index 0000000..b0019eb
--- /dev/null
@@ -0,0 +1,60 @@
+GPIO controllers on MPC8xxx SoCs
+
+This is for the non-QE/CPM/GUTs GPIO controllers as found on
+8349, 8572, 8610 and compatible.
+
+Every GPIO controller node must have #gpio-cells property defined,
+this information will be used to translate gpio-specifiers.
+
+Required properties:
+- compatible : "fsl,<CHIP>-gpio" followed by "fsl,mpc8349-gpio" for
+  83xx, "fsl,mpc8572-gpio" for 85xx and "fsl,mpc8610-gpio" for 86xx.
+- #gpio-cells : Should be two. The first cell is the pin number and the
+  second cell is used to specify optional parameters (currently unused).
+ - interrupts : Interrupt mapping for GPIO IRQ.
+ - interrupt-parent : Phandle for the interrupt controller that
+   services interrupts for this device.
+- gpio-controller : Marks the port as GPIO controller.
+
+Example of gpio-controller nodes for a MPC8347 SoC:
+
+       gpio1: gpio-controller@c00 {
+               #gpio-cells = <2>;
+               compatible = "fsl,mpc8347-gpio", "fsl,mpc8349-gpio";
+               reg = <0xc00 0x100>;
+               interrupts = <74 0x8>;
+               interrupt-parent = <&ipic>;
+               gpio-controller;
+       };
+
+       gpio2: gpio-controller@d00 {
+               #gpio-cells = <2>;
+               compatible = "fsl,mpc8347-gpio", "fsl,mpc8349-gpio";
+               reg = <0xd00 0x100>;
+               interrupts = <75 0x8>;
+               interrupt-parent = <&ipic>;
+               gpio-controller;
+       };
+
+See booting-without-of.txt for details of how to specify GPIO
+information for devices.
+
+To use GPIO pins as interrupt sources for peripherals, specify the
+GPIO controller as the interrupt parent and define GPIO number +
+trigger mode using the interrupts property, which is defined like
+this:
+
+interrupts = <number trigger>, where:
+ - number: GPIO pin (0..31)
+ - trigger: trigger mode:
+       2 = trigger on falling edge
+       3 = trigger on both edges
+
+Example of device using this is:
+
+       funkyfpga@0 {
+               compatible = "funky-fpga";
+               ...
+               interrupts = <4 3>;
+               interrupt-parent = <&gpio1>;
+       };
diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt
new file mode 100644 (file)
index 0000000..edaa84d
--- /dev/null
@@ -0,0 +1,50 @@
+Specifying GPIO information for devices
+============================================
+
+1) gpios property
+-----------------
+
+Nodes that makes use of GPIOs should define them using `gpios' property,
+format of which is: <&gpio-controller1-phandle gpio1-specifier
+                    &gpio-controller2-phandle gpio2-specifier
+                    0 /* holes are permitted, means no GPIO 3 */
+                    &gpio-controller4-phandle gpio4-specifier
+                    ...>;
+
+Note that gpio-specifier length is controller dependent.
+
+gpio-specifier may encode: bank, pin position inside the bank,
+whether pin is open-drain and whether pin is logically inverted.
+
+Example of the node using GPIOs:
+
+       node {
+               gpios = <&qe_pio_e 18 0>;
+       };
+
+In this example gpio-specifier is "18 0" and encodes GPIO pin number,
+and empty GPIO flags as accepted by the "qe_pio_e" gpio-controller.
+
+2) gpio-controller nodes
+------------------------
+
+Every GPIO controller node must have #gpio-cells property defined,
+this information will be used to translate gpio-specifiers.
+
+Example of two SOC GPIO banks defined as gpio-controller nodes:
+
+       qe_pio_a: gpio-controller@1400 {
+               #gpio-cells = <2>;
+               compatible = "fsl,qe-pario-bank-a", "fsl,qe-pario-bank";
+               reg = <0x1400 0x18>;
+               gpio-controller;
+       };
+
+       qe_pio_e: gpio-controller@1460 {
+               #gpio-cells = <2>;
+               compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
+               reg = <0x1460 0x18>;
+               gpio-controller;
+       };
+
+
diff --git a/Documentation/devicetree/bindings/gpio/led.txt b/Documentation/devicetree/bindings/gpio/led.txt
new file mode 100644 (file)
index 0000000..064db92
--- /dev/null
@@ -0,0 +1,58 @@
+LEDs connected to GPIO lines
+
+Required properties:
+- compatible : should be "gpio-leds".
+
+Each LED is represented as a sub-node of the gpio-leds device.  Each
+node's name represents the name of the corresponding LED.
+
+LED sub-node properties:
+- gpios :  Should specify the LED's GPIO, see "Specifying GPIO information
+  for devices" in Documentation/powerpc/booting-without-of.txt.  Active
+  low LEDs should be indicated using flags in the GPIO specifier.
+- label :  (optional) The label for this LED.  If omitted, the label is
+  taken from the node name (excluding the unit address).
+- linux,default-trigger :  (optional) This parameter, if present, is a
+  string defining the trigger assigned to the LED.  Current triggers are:
+    "backlight" - LED will act as a back-light, controlled by the framebuffer
+                 system
+    "default-on" - LED will turn on, but see "default-state" below
+    "heartbeat" - LED "double" flashes at a load average based rate
+    "ide-disk" - LED indicates disk activity
+    "timer" - LED flashes at a fixed, configurable rate
+- default-state:  (optional) The initial state of the LED.  Valid
+  values are "on", "off", and "keep".  If the LED is already on or off
+  and the default-state property is set the to same value, then no
+  glitch should be produced where the LED momentarily turns off (or
+  on).  The "keep" setting will keep the LED at whatever its current
+  state is, without producing a glitch.  The default is off if this
+  property is not present.
+
+Examples:
+
+leds {
+       compatible = "gpio-leds";
+       hdd {
+               label = "IDE Activity";
+               gpios = <&mcu_pio 0 1>; /* Active low */
+               linux,default-trigger = "ide-disk";
+       };
+
+       fault {
+               gpios = <&mcu_pio 1 0>;
+               /* Keep LED on if BIOS detected hardware fault */
+               default-state = "keep";
+       };
+};
+
+run-control {
+       compatible = "gpio-leds";
+       red {
+               gpios = <&mpc8572 6 0>;
+               default-state = "off";
+       };
+       green {
+               gpios = <&mpc8572 7 0>;
+               default-state = "on";
+       };
+}
diff --git a/Documentation/devicetree/bindings/i2c/ce4100-i2c.txt b/Documentation/devicetree/bindings/i2c/ce4100-i2c.txt
new file mode 100644 (file)
index 0000000..569b162
--- /dev/null
@@ -0,0 +1,93 @@
+CE4100 I2C
+----------
+
+CE4100 has one PCI device which is described as the I2C-Controller. This
+PCI device has three PCI-bars, each bar contains a complete I2C
+controller. So we have a total of three independent I2C-Controllers
+which share only an interrupt line.
+The driver is probed via the PCI-ID and is gathering the information of
+attached devices from the devices tree.
+Grant Likely recommended to use the ranges property to map the PCI-Bar
+number to its physical address and to use this to find the child nodes
+of the specific I2C controller. This were his exact words:
+
+       Here's where the magic happens.  Each entry in
+       ranges describes how the parent pci address space
+       (middle group of 3) is translated to the local
+       address space (first group of 2) and the size of
+       each range (last cell).  In this particular case,
+       the first cell of the local address is chosen to be
+       1:1 mapped to the BARs, and the second is the
+       offset from be base of the BAR (which would be
+       non-zero if you had 2 or more devices mapped off
+       the same BAR)
+
+       ranges allows the address mapping to be described
+       in a way that the OS can interpret without
+       requiring custom device driver code.
+
+This is an example which is used on FalconFalls:
+------------------------------------------------
+       i2c-controller@b,2 {
+               #address-cells = <2>;
+               #size-cells = <1>;
+               compatible = "pci8086,2e68.2",
+                               "pci8086,2e68",
+                               "pciclass,ff0000",
+                               "pciclass,ff00";
+
+               reg = <0x15a00 0x0 0x0 0x0 0x0>;
+               interrupts = <16 1>;
+
+               /* as described by Grant, the first number in the group of
+               * three is the bar number followed by the 64bit bar address
+               * followed by size of the mapping. The bar address
+               * requires also a valid translation in parents ranges
+               * property.
+               */
+               ranges = <0 0   0x02000000 0 0xdffe0500 0x100
+                         1 0   0x02000000 0 0xdffe0600 0x100
+                         2 0   0x02000000 0 0xdffe0700 0x100>;
+
+               i2c@0 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "intel,ce4100-i2c-controller";
+
+                       /* The first number in the reg property is the
+                       * number of the bar
+                       */
+                       reg = <0 0 0x100>;
+
+                       /* This I2C controller has no devices */
+               };
+
+               i2c@1 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "intel,ce4100-i2c-controller";
+                       reg = <1 0 0x100>;
+
+                       /* This I2C controller has one gpio controller */
+                       gpio@26 {
+                               #gpio-cells = <2>;
+                               compatible = "ti,pcf8575";
+                               reg = <0x26>;
+                               gpio-controller;
+                       };
+               };
+
+               i2c@2 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "intel,ce4100-i2c-controller";
+                       reg = <2 0 0x100>;
+
+                       gpio@26 {
+                               #gpio-cells = <2>;
+                               compatible = "ti,pcf8575";
+                               reg = <0x26>;
+                               gpio-controller;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/i2c/fsl-i2c.txt b/Documentation/devicetree/bindings/i2c/fsl-i2c.txt
new file mode 100644 (file)
index 0000000..1eacd6b
--- /dev/null
@@ -0,0 +1,64 @@
+* I2C
+
+Required properties :
+
+ - reg : Offset and length of the register set for the device
+ - compatible : should be "fsl,CHIP-i2c" where CHIP is the name of a
+   compatible processor, e.g. mpc8313, mpc8543, mpc8544, mpc5121,
+   mpc5200 or mpc5200b. For the mpc5121, an additional node
+   "fsl,mpc5121-i2c-ctrl" is required as shown in the example below.
+
+Recommended properties :
+
+ - interrupts : <a b> where a is the interrupt number and b is a
+   field that represents an encoding of the sense and level
+   information for the interrupt.  This should be encoded based on
+   the information in section 2) depending on the type of interrupt
+   controller you have.
+ - interrupt-parent : the phandle for the interrupt controller that
+   services interrupts for this device.
+ - fsl,preserve-clocking : boolean; if defined, the clock settings
+   from the bootloader are preserved (not touched).
+ - clock-frequency : desired I2C bus clock frequency in Hz.
+ - fsl,timeout : I2C bus timeout in microseconds.
+
+Examples :
+
+       /* MPC5121 based board */
+       i2c@1740 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "fsl,mpc5121-i2c", "fsl-i2c";
+               reg = <0x1740 0x20>;
+               interrupts = <11 0x8>;
+               interrupt-parent = <&ipic>;
+               clock-frequency = <100000>;
+       };
+
+       i2ccontrol@1760 {
+               compatible = "fsl,mpc5121-i2c-ctrl";
+               reg = <0x1760 0x8>;
+       };
+
+       /* MPC5200B based board */
+       i2c@3d00 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
+               reg = <0x3d00 0x40>;
+               interrupts = <2 15 0>;
+               interrupt-parent = <&mpc5200_pic>;
+               fsl,preserve-clocking;
+       };
+
+       /* MPC8544 base board */
+       i2c@3100 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "fsl,mpc8544-i2c", "fsl-i2c";
+               reg = <0x3100 0x100>;
+               interrupts = <43 2>;
+               interrupt-parent = <&mpic>;
+               clock-frequency = <400000>;
+               fsl,timeout = <10000>;
+       };
diff --git a/Documentation/devicetree/bindings/marvell.txt b/Documentation/devicetree/bindings/marvell.txt
new file mode 100644 (file)
index 0000000..f1533d9
--- /dev/null
@@ -0,0 +1,521 @@
+Marvell Discovery mv64[345]6x System Controller chips
+===========================================================
+
+The Marvell mv64[345]60 series of system controller chips contain
+many of the peripherals needed to implement a complete computer
+system.  In this section, we define device tree nodes to describe
+the system controller chip itself and each of the peripherals
+which it contains.  Compatible string values for each node are
+prefixed with the string "marvell,", for Marvell Technology Group Ltd.
+
+1) The /system-controller node
+
+  This node is used to represent the system-controller and must be
+  present when the system uses a system controller chip. The top-level
+  system-controller node contains information that is global to all
+  devices within the system controller chip. The node name begins
+  with "system-controller" followed by the unit address, which is
+  the base address of the memory-mapped register set for the system
+  controller chip.
+
+  Required properties:
+
+    - ranges : Describes the translation of system controller addresses
+      for memory mapped registers.
+    - clock-frequency: Contains the main clock frequency for the system
+      controller chip.
+    - reg : This property defines the address and size of the
+      memory-mapped registers contained within the system controller
+      chip.  The address specified in the "reg" property should match
+      the unit address of the system-controller node.
+    - #address-cells : Address representation for system controller
+      devices.  This field represents the number of cells needed to
+      represent the address of the memory-mapped registers of devices
+      within the system controller chip.
+    - #size-cells : Size representation for the memory-mapped
+      registers within the system controller chip.
+    - #interrupt-cells : Defines the width of cells used to represent
+      interrupts.
+
+  Optional properties:
+
+    - model : The specific model of the system controller chip.  Such
+      as, "mv64360", "mv64460", or "mv64560".
+    - compatible : A string identifying the compatibility identifiers
+      of the system controller chip.
+
+  The system-controller node contains child nodes for each system
+  controller device that the platform uses.  Nodes should not be created
+  for devices which exist on the system controller chip but are not used
+
+  Example Marvell Discovery mv64360 system-controller node:
+
+    system-controller@f1000000 { /* Marvell Discovery mv64360 */
+           #address-cells = <1>;
+           #size-cells = <1>;
+           model = "mv64360";                      /* Default */
+           compatible = "marvell,mv64360";
+           clock-frequency = <133333333>;
+           reg = <0xf1000000 0x10000>;
+           virtual-reg = <0xf1000000>;
+           ranges = <0x88000000 0x88000000 0x1000000 /* PCI 0 I/O Space */
+                   0x80000000 0x80000000 0x8000000 /* PCI 0 MEM Space */
+                   0xa0000000 0xa0000000 0x4000000 /* User FLASH */
+                   0x00000000 0xf1000000 0x0010000 /* Bridge's regs */
+                   0xf2000000 0xf2000000 0x0040000>;/* Integrated SRAM */
+
+           [ child node definitions... ]
+    }
+
+2) Child nodes of /system-controller
+
+   a) Marvell Discovery MDIO bus
+
+   The MDIO is a bus to which the PHY devices are connected.  For each
+   device that exists on this bus, a child node should be created.  See
+   the definition of the PHY node below for an example of how to define
+   a PHY.
+
+   Required properties:
+     - #address-cells : Should be <1>
+     - #size-cells : Should be <0>
+     - device_type : Should be "mdio"
+     - compatible : Should be "marvell,mv64360-mdio"
+
+   Example:
+
+     mdio {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            device_type = "mdio";
+            compatible = "marvell,mv64360-mdio";
+
+            ethernet-phy@0 {
+                    ......
+            };
+     };
+
+
+   b) Marvell Discovery ethernet controller
+
+   The Discover ethernet controller is described with two levels
+   of nodes.  The first level describes an ethernet silicon block
+   and the second level describes up to 3 ethernet nodes within
+   that block.  The reason for the multiple levels is that the
+   registers for the node are interleaved within a single set
+   of registers.  The "ethernet-block" level describes the
+   shared register set, and the "ethernet" nodes describe ethernet
+   port-specific properties.
+
+   Ethernet block node
+
+   Required properties:
+     - #address-cells : <1>
+     - #size-cells : <0>
+     - compatible : "marvell,mv64360-eth-block"
+     - reg : Offset and length of the register set for this block
+
+   Example Discovery Ethernet block node:
+     ethernet-block@2000 {
+            #address-cells = <1>;
+            #size-cells = <0>;
+            compatible = "marvell,mv64360-eth-block";
+            reg = <0x2000 0x2000>;
+            ethernet@0 {
+                    .......
+            };
+     };
+
+   Ethernet port node
+
+   Required properties:
+     - device_type : Should be "network".
+     - compatible : Should be "marvell,mv64360-eth".
+     - reg : Should be <0>, <1>, or <2>, according to which registers
+       within the silicon block the device uses.
+     - interrupts : <a> where a is the interrupt number for the port.
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+     - phy : the phandle for the PHY connected to this ethernet
+       controller.
+     - local-mac-address : 6 bytes, MAC address
+
+   Example Discovery Ethernet port node:
+     ethernet@0 {
+            device_type = "network";
+            compatible = "marvell,mv64360-eth";
+            reg = <0>;
+            interrupts = <32>;
+            interrupt-parent = <&PIC>;
+            phy = <&PHY0>;
+            local-mac-address = [ 00 00 00 00 00 00 ];
+     };
+
+
+
+   c) Marvell Discovery PHY nodes
+
+   Required properties:
+     - device_type : Should be "ethernet-phy"
+     - interrupts : <a> where a is the interrupt number for this phy.
+     - interrupt-parent : the phandle for the interrupt controller that
+       services interrupts for this device.
+     - reg : The ID number for the phy, usually a small integer
+
+   Example Discovery PHY node:
+     ethernet-phy@1 {
+            device_type = "ethernet-phy";
+            compatible = "broadcom,bcm5421";
+            interrupts = <76>;      /* GPP 12 */
+            interrupt-parent = <&PIC>;
+            reg = <1>;
+     };
+
+
+   d) Marvell Discovery SDMA nodes
+
+   Represent DMA hardware associated with the MPSC (multiprotocol
+   serial controllers).
+
+   Required properties:
+     - compatible : "marvell,mv64360-sdma"
+     - reg : Offset and length of the register set for this device
+     - interrupts : <a> where a is the interrupt number for the DMA
+       device.
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery SDMA node:
+     sdma@4000 {
+            compatible = "marvell,mv64360-sdma";
+            reg = <0x4000 0xc18>;
+            virtual-reg = <0xf1004000>;
+            interrupts = <36>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   e) Marvell Discovery BRG nodes
+
+   Represent baud rate generator hardware associated with the MPSC
+   (multiprotocol serial controllers).
+
+   Required properties:
+     - compatible : "marvell,mv64360-brg"
+     - reg : Offset and length of the register set for this device
+     - clock-src : A value from 0 to 15 which selects the clock
+       source for the baud rate generator.  This value corresponds
+       to the CLKS value in the BRGx configuration register.  See
+       the mv64x60 User's Manual.
+     - clock-frequence : The frequency (in Hz) of the baud rate
+       generator's input clock.
+     - current-speed : The current speed setting (presumably by
+       firmware) of the baud rate generator.
+
+   Example Discovery BRG node:
+     brg@b200 {
+            compatible = "marvell,mv64360-brg";
+            reg = <0xb200 0x8>;
+            clock-src = <8>;
+            clock-frequency = <133333333>;
+            current-speed = <9600>;
+     };
+
+
+   f) Marvell Discovery CUNIT nodes
+
+   Represent the Serial Communications Unit device hardware.
+
+   Required properties:
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery CUNIT node:
+     cunit@f200 {
+            reg = <0xf200 0x200>;
+     };
+
+
+   g) Marvell Discovery MPSCROUTING nodes
+
+   Represent the Discovery's MPSC routing hardware
+
+   Required properties:
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery CUNIT node:
+     mpscrouting@b500 {
+            reg = <0xb400 0xc>;
+     };
+
+
+   h) Marvell Discovery MPSCINTR nodes
+
+   Represent the Discovery's MPSC DMA interrupt hardware registers
+   (SDMA cause and mask registers).
+
+   Required properties:
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery MPSCINTR node:
+     mpsintr@b800 {
+            reg = <0xb800 0x100>;
+     };
+
+
+   i) Marvell Discovery MPSC nodes
+
+   Represent the Discovery's MPSC (Multiprotocol Serial Controller)
+   serial port.
+
+   Required properties:
+     - device_type : "serial"
+     - compatible : "marvell,mv64360-mpsc"
+     - reg : Offset and length of the register set for this device
+     - sdma : the phandle for the SDMA node used by this port
+     - brg : the phandle for the BRG node used by this port
+     - cunit : the phandle for the CUNIT node used by this port
+     - mpscrouting : the phandle for the MPSCROUTING node used by this port
+     - mpscintr : the phandle for the MPSCINTR node used by this port
+     - cell-index : the hardware index of this cell in the MPSC core
+     - max_idle : value needed for MPSC CHR3 (Maximum Frame Length)
+       register
+     - interrupts : <a> where a is the interrupt number for the MPSC.
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery MPSCINTR node:
+     mpsc@8000 {
+            device_type = "serial";
+            compatible = "marvell,mv64360-mpsc";
+            reg = <0x8000 0x38>;
+            virtual-reg = <0xf1008000>;
+            sdma = <&SDMA0>;
+            brg = <&BRG0>;
+            cunit = <&CUNIT>;
+            mpscrouting = <&MPSCROUTING>;
+            mpscintr = <&MPSCINTR>;
+            cell-index = <0>;
+            max_idle = <40>;
+            interrupts = <40>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   j) Marvell Discovery Watch Dog Timer nodes
+
+   Represent the Discovery's watchdog timer hardware
+
+   Required properties:
+     - compatible : "marvell,mv64360-wdt"
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery Watch Dog Timer node:
+     wdt@b410 {
+            compatible = "marvell,mv64360-wdt";
+            reg = <0xb410 0x8>;
+     };
+
+
+   k) Marvell Discovery I2C nodes
+
+   Represent the Discovery's I2C hardware
+
+   Required properties:
+     - device_type : "i2c"
+     - compatible : "marvell,mv64360-i2c"
+     - reg : Offset and length of the register set for this device
+     - interrupts : <a> where a is the interrupt number for the I2C.
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery I2C node:
+            compatible = "marvell,mv64360-i2c";
+            reg = <0xc000 0x20>;
+            virtual-reg = <0xf100c000>;
+            interrupts = <37>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   l) Marvell Discovery PIC (Programmable Interrupt Controller) nodes
+
+   Represent the Discovery's PIC hardware
+
+   Required properties:
+     - #interrupt-cells : <1>
+     - #address-cells : <0>
+     - compatible : "marvell,mv64360-pic"
+     - reg : Offset and length of the register set for this device
+     - interrupt-controller
+
+   Example Discovery PIC node:
+     pic {
+            #interrupt-cells = <1>;
+            #address-cells = <0>;
+            compatible = "marvell,mv64360-pic";
+            reg = <0x0 0x88>;
+            interrupt-controller;
+     };
+
+
+   m) Marvell Discovery MPP (Multipurpose Pins) multiplexing nodes
+
+   Represent the Discovery's MPP hardware
+
+   Required properties:
+     - compatible : "marvell,mv64360-mpp"
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery MPP node:
+     mpp@f000 {
+            compatible = "marvell,mv64360-mpp";
+            reg = <0xf000 0x10>;
+     };
+
+
+   n) Marvell Discovery GPP (General Purpose Pins) nodes
+
+   Represent the Discovery's GPP hardware
+
+   Required properties:
+     - compatible : "marvell,mv64360-gpp"
+     - reg : Offset and length of the register set for this device
+
+   Example Discovery GPP node:
+     gpp@f000 {
+            compatible = "marvell,mv64360-gpp";
+            reg = <0xf100 0x20>;
+     };
+
+
+   o) Marvell Discovery PCI host bridge node
+
+   Represents the Discovery's PCI host bridge device.  The properties
+   for this node conform to Rev 2.1 of the PCI Bus Binding to IEEE
+   1275-1994.  A typical value for the compatible property is
+   "marvell,mv64360-pci".
+
+   Example Discovery PCI host bridge node
+     pci@80000000 {
+            #address-cells = <3>;
+            #size-cells = <2>;
+            #interrupt-cells = <1>;
+            device_type = "pci";
+            compatible = "marvell,mv64360-pci";
+            reg = <0xcf8 0x8>;
+            ranges = <0x01000000 0x0        0x0
+                            0x88000000 0x0 0x01000000
+                      0x02000000 0x0 0x80000000
+                            0x80000000 0x0 0x08000000>;
+            bus-range = <0 255>;
+            clock-frequency = <66000000>;
+            interrupt-parent = <&PIC>;
+            interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+            interrupt-map = <
+                    /* IDSEL 0x0a */
+                    0x5000 0 0 1 &PIC 80
+                    0x5000 0 0 2 &PIC 81
+                    0x5000 0 0 3 &PIC 91
+                    0x5000 0 0 4 &PIC 93
+
+                    /* IDSEL 0x0b */
+                    0x5800 0 0 1 &PIC 91
+                    0x5800 0 0 2 &PIC 93
+                    0x5800 0 0 3 &PIC 80
+                    0x5800 0 0 4 &PIC 81
+
+                    /* IDSEL 0x0c */
+                    0x6000 0 0 1 &PIC 91
+                    0x6000 0 0 2 &PIC 93
+                    0x6000 0 0 3 &PIC 80
+                    0x6000 0 0 4 &PIC 81
+
+                    /* IDSEL 0x0d */
+                    0x6800 0 0 1 &PIC 93
+                    0x6800 0 0 2 &PIC 80
+                    0x6800 0 0 3 &PIC 81
+                    0x6800 0 0 4 &PIC 91
+            >;
+     };
+
+
+   p) Marvell Discovery CPU Error nodes
+
+   Represent the Discovery's CPU error handler device.
+
+   Required properties:
+     - compatible : "marvell,mv64360-cpu-error"
+     - reg : Offset and length of the register set for this device
+     - interrupts : the interrupt number for this device
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery CPU Error node:
+     cpu-error@0070 {
+            compatible = "marvell,mv64360-cpu-error";
+            reg = <0x70 0x10 0x128 0x28>;
+            interrupts = <3>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   q) Marvell Discovery SRAM Controller nodes
+
+   Represent the Discovery's SRAM controller device.
+
+   Required properties:
+     - compatible : "marvell,mv64360-sram-ctrl"
+     - reg : Offset and length of the register set for this device
+     - interrupts : the interrupt number for this device
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery SRAM Controller node:
+     sram-ctrl@0380 {
+            compatible = "marvell,mv64360-sram-ctrl";
+            reg = <0x380 0x80>;
+            interrupts = <13>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   r) Marvell Discovery PCI Error Handler nodes
+
+   Represent the Discovery's PCI error handler device.
+
+   Required properties:
+     - compatible : "marvell,mv64360-pci-error"
+     - reg : Offset and length of the register set for this device
+     - interrupts : the interrupt number for this device
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery PCI Error Handler node:
+     pci-error@1d40 {
+            compatible = "marvell,mv64360-pci-error";
+            reg = <0x1d40 0x40 0xc28 0x4>;
+            interrupts = <12>;
+            interrupt-parent = <&PIC>;
+     };
+
+
+   s) Marvell Discovery Memory Controller nodes
+
+   Represent the Discovery's memory controller device.
+
+   Required properties:
+     - compatible : "marvell,mv64360-mem-ctrl"
+     - reg : Offset and length of the register set for this device
+     - interrupts : the interrupt number for this device
+     - interrupt-parent : the phandle for the interrupt controller
+       that services interrupts for this device.
+
+   Example Discovery Memory Controller node:
+     mem-ctrl@1400 {
+            compatible = "marvell,mv64360-mem-ctrl";
+            reg = <0x1400 0x60>;
+            interrupts = <17>;
+            interrupt-parent = <&PIC>;
+     };
+
+
diff --git a/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt
new file mode 100644 (file)
index 0000000..64bcb8b
--- /dev/null
@@ -0,0 +1,29 @@
+* Freescale Enhanced Secure Digital Host Controller (eSDHC)
+
+The Enhanced Secure Digital Host Controller provides an interface
+for MMC, SD, and SDIO types of memory cards.
+
+Required properties:
+  - compatible : should be
+    "fsl,<chip>-esdhc", "fsl,esdhc"
+  - reg : should contain eSDHC registers location and length.
+  - interrupts : should contain eSDHC interrupt.
+  - interrupt-parent : interrupt source phandle.
+  - clock-frequency : specifies eSDHC base clock frequency.
+  - sdhci,wp-inverted : (optional) specifies that eSDHC controller
+    reports inverted write-protect state;
+  - sdhci,1-bit-only : (optional) specifies that a controller can
+    only handle 1-bit data transfers.
+  - sdhci,auto-cmd12: (optional) specifies that a controller can
+    only handle auto CMD12.
+
+Example:
+
+sdhci@2e000 {
+       compatible = "fsl,mpc8378-esdhc", "fsl,esdhc";
+       reg = <0x2e000 0x1000>;
+       interrupts = <42 0x8>;
+       interrupt-parent = <&ipic>;
+       /* Filled in by U-Boot */
+       clock-frequency = <0>;
+};
diff --git a/Documentation/devicetree/bindings/mmc/mmc-spi-slot.txt b/Documentation/devicetree/bindings/mmc/mmc-spi-slot.txt
new file mode 100644 (file)
index 0000000..c39ac28
--- /dev/null
@@ -0,0 +1,23 @@
+MMC/SD/SDIO slot directly connected to a SPI bus
+
+Required properties:
+- compatible : should be "mmc-spi-slot".
+- reg : should specify SPI address (chip-select number).
+- spi-max-frequency : maximum frequency for this device (Hz).
+- voltage-ranges : two cells are required, first cell specifies minimum
+  slot voltage (mV), second cell specifies maximum slot voltage (mV).
+  Several ranges could be specified.
+- gpios : (optional) may specify GPIOs in this order: Card-Detect GPIO,
+  Write-Protect GPIO.
+
+Example:
+
+       mmc-slot@0 {
+               compatible = "fsl,mpc8323rdb-mmc-slot",
+                            "mmc-spi-slot";
+               reg = <0>;
+               gpios = <&qe_pio_d 14 1
+                        &qe_pio_d 15 0>;
+               voltage-ranges = <3300 3300>;
+               spi-max-frequency = <50000000>;
+       };
diff --git a/Documentation/devicetree/bindings/mtd/fsl-upm-nand.txt b/Documentation/devicetree/bindings/mtd/fsl-upm-nand.txt
new file mode 100644 (file)
index 0000000..a48b2ca
--- /dev/null
@@ -0,0 +1,63 @@
+Freescale Localbus UPM programmed to work with NAND flash
+
+Required properties:
+- compatible : "fsl,upm-nand".
+- reg : should specify localbus chip select and size used for the chip.
+- fsl,upm-addr-offset : UPM pattern offset for the address latch.
+- fsl,upm-cmd-offset : UPM pattern offset for the command latch.
+
+Optional properties:
+- fsl,upm-wait-flags : add chip-dependent short delays after running the
+       UPM pattern (0x1), after writing a data byte (0x2) or after
+       writing out a buffer (0x4).
+- fsl,upm-addr-line-cs-offsets : address offsets for multi-chip support.
+       The corresponding address lines are used to select the chip.
+- gpios : may specify optional GPIOs connected to the Ready-Not-Busy pins
+       (R/B#). For multi-chip devices, "n" GPIO definitions are required
+       according to the number of chips.
+- chip-delay : chip dependent delay for transfering data from array to
+       read registers (tR). Required if property "gpios" is not used
+       (R/B# pins not connected).
+
+Examples:
+
+upm@1,0 {
+       compatible = "fsl,upm-nand";
+       reg = <1 0 1>;
+       fsl,upm-addr-offset = <16>;
+       fsl,upm-cmd-offset = <8>;
+       gpios = <&qe_pio_e 18 0>;
+
+       flash {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "...";
+
+               partition@0 {
+                       ...
+               };
+       };
+};
+
+upm@3,0 {
+       #address-cells = <0>;
+       #size-cells = <0>;
+       compatible = "tqc,tqm8548-upm-nand", "fsl,upm-nand";
+       reg = <3 0x0 0x800>;
+       fsl,upm-addr-offset = <0x10>;
+       fsl,upm-cmd-offset = <0x08>;
+       /* Multi-chip NAND device */
+       fsl,upm-addr-line-cs-offsets = <0x0 0x200>;
+       fsl,upm-wait-flags = <0x5>;
+       chip-delay = <25>; // in micro-seconds
+
+       nand@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               partition@0 {
+                           label = "fs";
+                           reg = <0x00000000 0x10000000>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/mtd/mtd-physmap.txt b/Documentation/devicetree/bindings/mtd/mtd-physmap.txt
new file mode 100644 (file)
index 0000000..80152cb
--- /dev/null
@@ -0,0 +1,90 @@
+CFI or JEDEC memory-mapped NOR flash, MTD-RAM (NVRAM...)
+
+Flash chips (Memory Technology Devices) are often used for solid state
+file systems on embedded devices.
+
+ - compatible : should contain the specific model of mtd chip(s)
+   used, if known, followed by either "cfi-flash", "jedec-flash"
+   or "mtd-ram".
+ - reg : Address range(s) of the mtd chip(s)
+   It's possible to (optionally) define multiple "reg" tuples so that
+   non-identical chips can be described in one node.
+ - bank-width : Width (in bytes) of the bank.  Equal to the
+   device width times the number of interleaved chips.
+ - device-width : (optional) Width of a single mtd chip.  If
+   omitted, assumed to be equal to 'bank-width'.
+ - #address-cells, #size-cells : Must be present if the device has
+   sub-nodes representing partitions (see below).  In this case
+   both #address-cells and #size-cells must be equal to 1.
+
+For JEDEC compatible devices, the following additional properties
+are defined:
+
+ - vendor-id : Contains the flash chip's vendor id (1 byte).
+ - device-id : Contains the flash chip's device id (1 byte).
+
+In addition to the information on the mtd bank itself, the
+device tree may optionally contain additional information
+describing partitions of the address space.  This can be
+used on platforms which have strong conventions about which
+portions of a flash are used for what purposes, but which don't
+use an on-flash partition table such as RedBoot.
+
+Each partition is represented as a sub-node of the mtd device.
+Each node's name represents the name of the corresponding
+partition of the mtd device.
+
+Flash partitions
+ - reg : The partition's offset and size within the mtd bank.
+ - label : (optional) The label / name for this partition.
+   If omitted, the label is taken from the node name (excluding
+   the unit address).
+ - read-only : (optional) This parameter, if present, is a hint to
+   Linux that this partition should only be mounted
+   read-only.  This is usually used for flash partitions
+   containing early-boot firmware images or data which should not
+   be clobbered.
+
+Example:
+
+       flash@ff000000 {
+               compatible = "amd,am29lv128ml", "cfi-flash";
+               reg = <ff000000 01000000>;
+               bank-width = <4>;
+               device-width = <1>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               fs@0 {
+                       label = "fs";
+                       reg = <0 f80000>;
+               };
+               firmware@f80000 {
+                       label ="firmware";
+                       reg = <f80000 80000>;
+                       read-only;
+               };
+       };
+
+Here an example with multiple "reg" tuples:
+
+       flash@f0000000,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "intel,PC48F4400P0VB", "cfi-flash";
+               reg = <0 0x00000000 0x02000000
+                      0 0x02000000 0x02000000>;
+               bank-width = <2>;
+               partition@0 {
+                       label = "test-part1";
+                       reg = <0 0x04000000>;
+               };
+       };
+
+An example using SRAM:
+
+       sram@2,0 {
+               compatible = "samsung,k6f1616u6a", "mtd-ram";
+               reg = <2 0 0x00200000>;
+               bank-width = <2>;
+       };
+
diff --git a/Documentation/devicetree/bindings/net/can/mpc5xxx-mscan.txt b/Documentation/devicetree/bindings/net/can/mpc5xxx-mscan.txt
new file mode 100644 (file)
index 0000000..2fa4fcd
--- /dev/null
@@ -0,0 +1,53 @@
+CAN Device Tree Bindings
+------------------------
+
+(c) 2006-2009 Secret Lab Technologies Ltd
+Grant Likely <grant.likely@secretlab.ca>
+
+fsl,mpc5200-mscan nodes
+-----------------------
+In addition to the required compatible-, reg- and interrupt-properties, you can
+also specify which clock source shall be used for the controller:
+
+- fsl,mscan-clock-source : a string describing the clock source. Valid values
+                          are: "ip" for ip bus clock
+                                "ref" for reference clock (XTAL)
+                          "ref" is default in case this property is not
+                          present.
+
+fsl,mpc5121-mscan nodes
+-----------------------
+In addition to the required compatible-, reg- and interrupt-properties, you can
+also specify which clock source and divider shall be used for the controller:
+
+- fsl,mscan-clock-source : a string describing the clock source. Valid values
+                          are: "ip" for ip bus clock
+                               "ref" for reference clock
+                               "sys" for system clock
+                          If this property is not present, an optimal CAN
+                          clock source and frequency based on the system
+                          clock will be selected. If this is not possible,
+                          the reference clock will be used.
+
+- fsl,mscan-clock-divider: for the reference and system clock, an additional
+                          clock divider can be specified. By default, a
+                          value of 1 is used.
+
+Note that the MPC5121 Rev. 1 processor is not supported.
+
+Examples:
+       can@1300 {
+               compatible = "fsl,mpc5121-mscan";
+               interrupts = <12 0x8>;
+               interrupt-parent = <&ipic>;
+               reg = <0x1300 0x80>;
+       };
+
+       can@1380 {
+               compatible = "fsl,mpc5121-mscan";
+               interrupts = <13 0x8>;
+               interrupt-parent = <&ipic>;
+               reg = <0x1380 0x80>;
+               fsl,mscan-clock-source = "ref";
+               fsl,mscan-clock-divider = <3>;
+       };
diff --git a/Documentation/devicetree/bindings/net/can/sja1000.txt b/Documentation/devicetree/bindings/net/can/sja1000.txt
new file mode 100644 (file)
index 0000000..d6d209d
--- /dev/null
@@ -0,0 +1,53 @@
+Memory mapped SJA1000 CAN controller from NXP (formerly Philips)
+
+Required properties:
+
+- compatible : should be "nxp,sja1000".
+
+- reg : should specify the chip select, address offset and size required
+       to map the registers of the SJA1000. The size is usually 0x80.
+
+- interrupts: property with a value describing the interrupt source
+       (number and sensitivity) required for the SJA1000.
+
+Optional properties:
+
+- nxp,external-clock-frequency : Frequency of the external oscillator
+       clock in Hz. Note that the internal clock frequency used by the
+       SJA1000 is half of that value. If not specified, a default value
+       of 16000000 (16 MHz) is used.
+
+- nxp,tx-output-mode : operation mode of the TX output control logic:
+       <0x0> : bi-phase output mode
+       <0x1> : normal output mode (default)
+       <0x2> : test output mode
+       <0x3> : clock output mode
+
+- nxp,tx-output-config : TX output pin configuration:
+       <0x01> : TX0 invert
+       <0x02> : TX0 pull-down (default)
+       <0x04> : TX0 pull-up
+       <0x06> : TX0 push-pull
+       <0x08> : TX1 invert
+       <0x10> : TX1 pull-down
+       <0x20> : TX1 pull-up
+       <0x30> : TX1 push-pull
+
+- nxp,clock-out-frequency : clock frequency in Hz on the CLKOUT pin.
+       If not specified or if the specified value is 0, the CLKOUT pin
+       will be disabled.
+
+- nxp,no-comparator-bypass : Allows to disable the CAN input comperator.
+
+For futher information, please have a look to the SJA1000 data sheet.
+
+Examples:
+
+can@3,100 {
+       compatible = "nxp,sja1000";
+       reg = <3 0x100 0x80>;
+       interrupts = <2 0>;
+       interrupt-parent = <&mpic>;
+       nxp,external-clock-frequency = <16000000>;
+};
+
diff --git a/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt b/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
new file mode 100644 (file)
index 0000000..edb7ae1
--- /dev/null
@@ -0,0 +1,76 @@
+* MDIO IO device
+
+The MDIO is a bus to which the PHY devices are connected.  For each
+device that exists on this bus, a child node should be created.  See
+the definition of the PHY node in booting-without-of.txt for an example
+of how to define a PHY.
+
+Required properties:
+  - reg : Offset and length of the register set for the device
+  - compatible : Should define the compatible device type for the
+    mdio.  Currently, this is most likely to be "fsl,gianfar-mdio"
+
+Example:
+
+       mdio@24520 {
+               reg = <24520 20>;
+               compatible = "fsl,gianfar-mdio";
+
+               ethernet-phy@0 {
+                       ......
+               };
+       };
+
+* TBI Internal MDIO bus
+
+As of this writing, every tsec is associated with an internal TBI PHY.
+This PHY is accessed through the local MDIO bus.  These buses are defined
+similarly to the mdio buses, except they are compatible with "fsl,gianfar-tbi".
+The TBI PHYs underneath them are similar to normal PHYs, but the reg property
+is considered instructive, rather than descriptive.  The reg property should
+be chosen so it doesn't interfere with other PHYs on the bus.
+
+* Gianfar-compatible ethernet nodes
+
+Properties:
+
+  - device_type : Should be "network"
+  - model : Model of the device.  Can be "TSEC", "eTSEC", or "FEC"
+  - compatible : Should be "gianfar"
+  - reg : Offset and length of the register set for the device
+  - local-mac-address : List of bytes representing the ethernet address of
+    this controller
+  - interrupts : For FEC devices, the first interrupt is the device's
+    interrupt.  For TSEC and eTSEC devices, the first interrupt is
+    transmit, the second is receive, and the third is error.
+  - phy-handle : The phandle for the PHY connected to this ethernet
+    controller.
+  - fixed-link : <a b c d e> where a is emulated phy id - choose any,
+    but unique to the all specified fixed-links, b is duplex - 0 half,
+    1 full, c is link speed - d#10/d#100/d#1000, d is pause - 0 no
+    pause, 1 pause, e is asym_pause - 0 no asym_pause, 1 asym_pause.
+  - phy-connection-type : a string naming the controller/PHY interface type,
+    i.e., "mii" (default), "rmii", "gmii", "rgmii", "rgmii-id", "sgmii",
+    "tbi", or "rtbi".  This property is only really needed if the connection
+    is of type "rgmii-id", as all other connection types are detected by
+    hardware.
+  - fsl,magic-packet : If present, indicates that the hardware supports
+    waking up via magic packet.
+  - bd-stash : If present, indicates that the hardware supports stashing
+    buffer descriptors in the L2.
+  - rx-stash-len : Denotes the number of bytes of a received buffer to stash
+    in the L2.
+  - rx-stash-idx : Denotes the index of the first byte from the received
+    buffer to stash in the L2.
+
+Example:
+       ethernet@24000 {
+               device_type = "network";
+               model = "TSEC";
+               compatible = "gianfar";
+               reg = <0x24000 0x1000>;
+               local-mac-address = [ 00 E0 0C 00 73 00 ];
+               interrupts = <29 2 30 2 34 2>;
+               interrupt-parent = <&mpic>;
+               phy-handle = <&phy0>
+       };
diff --git a/Documentation/devicetree/bindings/net/mdio-gpio.txt b/Documentation/devicetree/bindings/net/mdio-gpio.txt
new file mode 100644 (file)
index 0000000..bc95495
--- /dev/null
@@ -0,0 +1,19 @@
+MDIO on GPIOs
+
+Currently defined compatibles:
+- virtual,gpio-mdio
+
+MDC and MDIO lines connected to GPIO controllers are listed in the
+gpios property as described in section VIII.1 in the following order:
+
+MDC, MDIO.
+
+Example:
+
+mdio {
+       compatible = "virtual,mdio-gpio";
+       #address-cells = <1>;
+       #size-cells = <0>;
+       gpios = <&qe_pio_a 11
+                &qe_pio_c 6>;
+};
diff --git a/Documentation/devicetree/bindings/net/phy.txt b/Documentation/devicetree/bindings/net/phy.txt
new file mode 100644 (file)
index 0000000..bb8c742
--- /dev/null
@@ -0,0 +1,25 @@
+PHY nodes
+
+Required properties:
+
+ - device_type : Should be "ethernet-phy"
+ - interrupts : <a b> where a is the interrupt number and b is a
+   field that represents an encoding of the sense and level
+   information for the interrupt.  This should be encoded based on
+   the information in section 2) depending on the type of interrupt
+   controller you have.
+ - interrupt-parent : the phandle for the interrupt controller that
+   services interrupts for this device.
+ - reg : The ID number for the phy, usually a small integer
+ - linux,phandle :  phandle for this node; likely referenced by an
+   ethernet controller node.
+
+Example:
+
+ethernet-phy@0 {
+       linux,phandle = <2452000>
+       interrupt-parent = <40000>;
+       interrupts = <35 1>;
+       reg = <0>;
+       device_type = "ethernet-phy";
+};
diff --git a/Documentation/devicetree/bindings/pci/83xx-512x-pci.txt b/Documentation/devicetree/bindings/pci/83xx-512x-pci.txt
new file mode 100644 (file)
index 0000000..35a4653
--- /dev/null
@@ -0,0 +1,40 @@
+* Freescale 83xx and 512x PCI bridges
+
+Freescale 83xx and 512x SOCs include the same pci bridge core.
+
+83xx/512x specific notes:
+- reg: should contain two address length tuples
+    The first is for the internal pci bridge registers
+    The second is for the pci config space access registers
+
+Example (MPC8313ERDB)
+       pci0: pci@e0008500 {
+               cell-index = <1>;
+               interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+               interrupt-map = <
+                               /* IDSEL 0x0E -mini PCI */
+                                0x7000 0x0 0x0 0x1 &ipic 18 0x8
+                                0x7000 0x0 0x0 0x2 &ipic 18 0x8
+                                0x7000 0x0 0x0 0x3 &ipic 18 0x8
+                                0x7000 0x0 0x0 0x4 &ipic 18 0x8
+
+                               /* IDSEL 0x0F - PCI slot */
+                                0x7800 0x0 0x0 0x1 &ipic 17 0x8
+                                0x7800 0x0 0x0 0x2 &ipic 18 0x8
+                                0x7800 0x0 0x0 0x3 &ipic 17 0x8
+                                0x7800 0x0 0x0 0x4 &ipic 18 0x8>;
+               interrupt-parent = <&ipic>;
+               interrupts = <66 0x8>;
+               bus-range = <0x0 0x0>;
+               ranges = <0x02000000 0x0 0x90000000 0x90000000 0x0 0x10000000
+                         0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000
+                         0x01000000 0x0 0x00000000 0xe2000000 0x0 0x00100000>;
+               clock-frequency = <66666666>;
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               reg = <0xe0008500 0x100         /* internal registers */
+                      0xe0008300 0x8>;         /* config space access registers */
+               compatible = "fsl,mpc8349-pci";
+               device_type = "pci";
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/4xx/cpm.txt b/Documentation/devicetree/bindings/powerpc/4xx/cpm.txt
new file mode 100644 (file)
index 0000000..ee45980
--- /dev/null
@@ -0,0 +1,52 @@
+PPC4xx Clock Power Management (CPM) node
+
+Required properties:
+       - compatible            : compatible list, currently only "ibm,cpm"
+       - dcr-access-method     : "native"
+       - dcr-reg               : < DCR register range >
+
+Optional properties:
+       - er-offset             : All 4xx SoCs with a CPM controller have
+                                 one of two different order for the CPM
+                                 registers. Some have the CPM registers
+                                 in the following order (ER,FR,SR). The
+                                 others have them in the following order
+                                 (SR,ER,FR). For the second case set
+                                 er-offset = <1>.
+       - unused-units          : specifier consist of one cell. For each
+                                 bit in the cell, the corresponding bit
+                                 in CPM will be set to turn off unused
+                                 devices.
+       - idle-doze             : specifier consist of one cell. For each
+                                 bit in the cell, the corresponding bit
+                                 in CPM will be set to turn off unused
+                                 devices. This is usually just CPM[CPU].
+       - standby               : specifier consist of one cell. For each
+                                 bit in the cell, the corresponding bit
+                                 in CPM will be set on standby and
+                                 restored on resume.
+       - suspend               : specifier consist of one cell. For each
+                                 bit in the cell, the corresponding bit
+                                 in CPM will be set on suspend (mem) and
+                                 restored on resume. Note, for standby
+                                 and suspend the corresponding bits can
+                                 be different or the same. Usually for
+                                 standby only class 2 and 3 units are set.
+                                 However, the interface does not care.
+                                 If they are the same, the additional
+                                 power saving will be seeing if support
+                                 is available to put the DDR in self
+                                 refresh mode and any additional power
+                                 saving techniques for the specific SoC.
+
+Example:
+       CPM0: cpm {
+               compatible = "ibm,cpm";
+               dcr-access-method = "native";
+               dcr-reg = <0x160 0x003>;
+               er-offset = <0>;
+               unused-units = <0x00000100>;
+               idle-doze = <0x02000000>;
+               standby = <0xfeff0000>;
+               suspend = <0xfeff791d>;
+};
diff --git a/Documentation/devicetree/bindings/powerpc/4xx/emac.txt b/Documentation/devicetree/bindings/powerpc/4xx/emac.txt
new file mode 100644 (file)
index 0000000..2161334
--- /dev/null
@@ -0,0 +1,148 @@
+    4xx/Axon EMAC ethernet nodes
+
+    The EMAC ethernet controller in IBM and AMCC 4xx chips, and also
+    the Axon bridge.  To operate this needs to interact with a ths
+    special McMAL DMA controller, and sometimes an RGMII or ZMII
+    interface.  In addition to the nodes and properties described
+    below, the node for the OPB bus on which the EMAC sits must have a
+    correct clock-frequency property.
+
+      i) The EMAC node itself
+
+    Required properties:
+    - device_type       : "network"
+
+    - compatible        : compatible list, contains 2 entries, first is
+                         "ibm,emac-CHIP" where CHIP is the host ASIC (440gx,
+                         405gp, Axon) and second is either "ibm,emac" or
+                         "ibm,emac4".  For Axon, thus, we have: "ibm,emac-axon",
+                         "ibm,emac4"
+    - interrupts        : <interrupt mapping for EMAC IRQ and WOL IRQ>
+    - interrupt-parent  : optional, if needed for interrupt mapping
+    - reg               : <registers mapping>
+    - local-mac-address : 6 bytes, MAC address
+    - mal-device        : phandle of the associated McMAL node
+    - mal-tx-channel    : 1 cell, index of the tx channel on McMAL associated
+                         with this EMAC
+    - mal-rx-channel    : 1 cell, index of the rx channel on McMAL associated
+                         with this EMAC
+    - cell-index        : 1 cell, hardware index of the EMAC cell on a given
+                         ASIC (typically 0x0 and 0x1 for EMAC0 and EMAC1 on
+                         each Axon chip)
+    - max-frame-size    : 1 cell, maximum frame size supported in bytes
+    - rx-fifo-size      : 1 cell, Rx fifo size in bytes for 10 and 100 Mb/sec
+                         operations.
+                         For Axon, 2048
+    - tx-fifo-size      : 1 cell, Tx fifo size in bytes for 10 and 100 Mb/sec
+                         operations.
+                         For Axon, 2048.
+    - fifo-entry-size   : 1 cell, size of a fifo entry (used to calculate
+                         thresholds).
+                         For Axon, 0x00000010
+    - mal-burst-size    : 1 cell, MAL burst size (used to calculate thresholds)
+                         in bytes.
+                         For Axon, 0x00000100 (I think ...)
+    - phy-mode          : string, mode of operations of the PHY interface.
+                         Supported values are: "mii", "rmii", "smii", "rgmii",
+                         "tbi", "gmii", rtbi", "sgmii".
+                         For Axon on CAB, it is "rgmii"
+    - mdio-device       : 1 cell, required iff using shared MDIO registers
+                         (440EP).  phandle of the EMAC to use to drive the
+                         MDIO lines for the PHY used by this EMAC.
+    - zmii-device       : 1 cell, required iff connected to a ZMII.  phandle of
+                         the ZMII device node
+    - zmii-channel      : 1 cell, required iff connected to a ZMII.  Which ZMII
+                         channel or 0xffffffff if ZMII is only used for MDIO.
+    - rgmii-device      : 1 cell, required iff connected to an RGMII. phandle
+                         of the RGMII device node.
+                         For Axon: phandle of plb5/plb4/opb/rgmii
+    - rgmii-channel     : 1 cell, required iff connected to an RGMII.  Which
+                         RGMII channel is used by this EMAC.
+                         Fox Axon: present, whatever value is appropriate for each
+                         EMAC, that is the content of the current (bogus) "phy-port"
+                         property.
+
+    Optional properties:
+    - phy-address       : 1 cell, optional, MDIO address of the PHY. If absent,
+                         a search is performed.
+    - phy-map           : 1 cell, optional, bitmap of addresses to probe the PHY
+                         for, used if phy-address is absent. bit 0x00000001 is
+                         MDIO address 0.
+                         For Axon it can be absent, though my current driver
+                         doesn't handle phy-address yet so for now, keep
+                         0x00ffffff in it.
+    - rx-fifo-size-gige : 1 cell, Rx fifo size in bytes for 1000 Mb/sec
+                         operations (if absent the value is the same as
+                         rx-fifo-size).  For Axon, either absent or 2048.
+    - tx-fifo-size-gige : 1 cell, Tx fifo size in bytes for 1000 Mb/sec
+                         operations (if absent the value is the same as
+                         tx-fifo-size). For Axon, either absent or 2048.
+    - tah-device        : 1 cell, optional. If connected to a TAH engine for
+                         offload, phandle of the TAH device node.
+    - tah-channel       : 1 cell, optional. If appropriate, channel used on the
+                         TAH engine.
+
+    Example:
+
+       EMAC0: ethernet@40000800 {
+               device_type = "network";
+               compatible = "ibm,emac-440gp", "ibm,emac";
+               interrupt-parent = <&UIC1>;
+               interrupts = <1c 4 1d 4>;
+               reg = <40000800 70>;
+               local-mac-address = [00 04 AC E3 1B 1E];
+               mal-device = <&MAL0>;
+               mal-tx-channel = <0 1>;
+               mal-rx-channel = <0>;
+               cell-index = <0>;
+               max-frame-size = <5dc>;
+               rx-fifo-size = <1000>;
+               tx-fifo-size = <800>;
+               phy-mode = "rmii";
+               phy-map = <00000001>;
+               zmii-device = <&ZMII0>;
+               zmii-channel = <0>;
+       };
+
+      ii) McMAL node
+
+    Required properties:
+    - device_type        : "dma-controller"
+    - compatible         : compatible list, containing 2 entries, first is
+                          "ibm,mcmal-CHIP" where CHIP is the host ASIC (like
+                          emac) and the second is either "ibm,mcmal" or
+                          "ibm,mcmal2".
+                          For Axon, "ibm,mcmal-axon","ibm,mcmal2"
+    - interrupts         : <interrupt mapping for the MAL interrupts sources:
+                           5 sources: tx_eob, rx_eob, serr, txde, rxde>.
+                           For Axon: This is _different_ from the current
+                          firmware.  We use the "delayed" interrupts for txeob
+                          and rxeob. Thus we end up with mapping those 5 MPIC
+                          interrupts, all level positive sensitive: 10, 11, 32,
+                          33, 34 (in decimal)
+    - dcr-reg            : < DCR registers range >
+    - dcr-parent         : if needed for dcr-reg
+    - num-tx-chans       : 1 cell, number of Tx channels
+    - num-rx-chans       : 1 cell, number of Rx channels
+
+      iii) ZMII node
+
+    Required properties:
+    - compatible         : compatible list, containing 2 entries, first is
+                          "ibm,zmii-CHIP" where CHIP is the host ASIC (like
+                          EMAC) and the second is "ibm,zmii".
+                          For Axon, there is no ZMII node.
+    - reg                : <registers mapping>
+
+      iv) RGMII node
+
+    Required properties:
+    - compatible         : compatible list, containing 2 entries, first is
+                          "ibm,rgmii-CHIP" where CHIP is the host ASIC (like
+                          EMAC) and the second is "ibm,rgmii".
+                           For Axon, "ibm,rgmii-axon","ibm,rgmii"
+    - reg                : <registers mapping>
+    - revision           : as provided by the RGMII new version register if
+                          available.
+                          For Axon: 0x0000012a
+
diff --git a/Documentation/devicetree/bindings/powerpc/4xx/ndfc.txt b/Documentation/devicetree/bindings/powerpc/4xx/ndfc.txt
new file mode 100644 (file)
index 0000000..869f0b5
--- /dev/null
@@ -0,0 +1,39 @@
+AMCC NDFC (NanD Flash Controller)
+
+Required properties:
+- compatible : "ibm,ndfc".
+- reg : should specify chip select and size used for the chip (0x2000).
+
+Optional properties:
+- ccr : NDFC config and control register value (default 0).
+- bank-settings : NDFC bank configuration register value (default 0).
+
+Notes:
+- partition(s) - follows the OF MTD standard for partitions
+
+Example:
+
+ndfc@1,0 {
+       compatible = "ibm,ndfc";
+       reg = <0x00000001 0x00000000 0x00002000>;
+       ccr = <0x00001000>;
+       bank-settings = <0x80002222>;
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       nand {
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               partition@0 {
+                       label = "kernel";
+                       reg = <0x00000000 0x00200000>;
+               };
+               partition@200000 {
+                       label = "root";
+                       reg = <0x00200000 0x03E00000>;
+               };
+       };
+};
+
+
diff --git a/Documentation/devicetree/bindings/powerpc/4xx/ppc440spe-adma.txt b/Documentation/devicetree/bindings/powerpc/4xx/ppc440spe-adma.txt
new file mode 100644 (file)
index 0000000..515ebcf
--- /dev/null
@@ -0,0 +1,93 @@
+PPC440SPe DMA/XOR (DMA Controller and XOR Accelerator)
+
+Device nodes needed for operation of the ppc440spe-adma driver
+are specified hereby. These are I2O/DMA, DMA and XOR nodes
+for DMA engines and Memory Queue Module node. The latter is used
+by ADMA driver for configuration of RAID-6 H/W capabilities of
+the PPC440SPe. In addition to the nodes and properties described
+below, the ranges property of PLB node must specify ranges for
+DMA devices.
+
+ i) The I2O node
+
+ Required properties:
+
+ - compatible          : "ibm,i2o-440spe";
+ - reg                 : <registers mapping>
+ - dcr-reg             : <DCR registers range>
+
+ Example:
+
+       I2O: i2o@400100000 {
+               compatible = "ibm,i2o-440spe";
+               reg = <0x00000004 0x00100000 0x100>;
+               dcr-reg = <0x060 0x020>;
+       };
+
+
+ ii) The DMA node
+
+ Required properties:
+
+ - compatible          : "ibm,dma-440spe";
+ - cell-index          : 1 cell, hardware index of the DMA engine
+                         (typically 0x0 and 0x1 for DMA0 and DMA1)
+ - reg                 : <registers mapping>
+ - dcr-reg             : <DCR registers range>
+ - interrupts          : <interrupt mapping for DMA0/1 interrupts sources:
+                          2 sources: DMAx CS FIFO Needs Service IRQ (on UIC0)
+                          and DMA Error IRQ (on UIC1). The latter is common
+                          for both DMA engines>.
+ - interrupt-parent    : needed for interrupt mapping
+
+ Example:
+
+       DMA0: dma0@400100100 {
+               compatible = "ibm,dma-440spe";
+               cell-index = <0>;
+               reg = <0x00000004 0x00100100 0x100>;
+               dcr-reg = <0x060 0x020>;
+               interrupt-parent = <&DMA0>;
+               interrupts = <0 1>;
+               #interrupt-cells = <1>;
+               #address-cells = <0>;
+               #size-cells = <0>;
+               interrupt-map = <
+                       0 &UIC0 0x14 4
+                       1 &UIC1 0x16 4>;
+       };
+
+
+ iii) XOR Accelerator node
+
+ Required properties:
+
+ - compatible          : "amcc,xor-accelerator";
+ - reg                 : <registers mapping>
+ - interrupts          : <interrupt mapping for XOR interrupt source>
+ - interrupt-parent    : for interrupt mapping
+
+ Example:
+
+       xor-accel@400200000 {
+               compatible = "amcc,xor-accelerator";
+               reg = <0x00000004 0x00200000 0x400>;
+               interrupt-parent = <&UIC1>;
+               interrupts = <0x1f 4>;
+       };
+
+
+ iv) Memory Queue Module node
+
+ Required properties:
+
+ - compatible          : "ibm,mq-440spe";
+ - dcr-reg             : <DCR registers range>
+
+ Example:
+
+       MQ0: mq {
+               compatible = "ibm,mq-440spe";
+               dcr-reg = <0x040 0x020>;
+       };
+
diff --git a/Documentation/devicetree/bindings/powerpc/4xx/reboot.txt b/Documentation/devicetree/bindings/powerpc/4xx/reboot.txt
new file mode 100644 (file)
index 0000000..d721726
--- /dev/null
@@ -0,0 +1,18 @@
+Reboot property to control system reboot on PPC4xx systems:
+
+By setting "reset_type" to one of the following values, the default
+software reset mechanism may be overidden. Here the possible values of
+"reset_type":
+
+      1 - PPC4xx core reset
+      2 - PPC4xx chip reset
+      3 - PPC4xx system reset (default)
+
+Example:
+
+               cpu@0 {
+                       device_type = "cpu";
+                       model = "PowerPC,440SPe";
+                       ...
+                       reset-type = <2>;       /* Use chip-reset */
+               };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/board.txt b/Documentation/devicetree/bindings/powerpc/fsl/board.txt
new file mode 100644 (file)
index 0000000..39e9415
--- /dev/null
@@ -0,0 +1,63 @@
+* Board Control and Status (BCSR)
+
+Required properties:
+
+ - compatible : Should be "fsl,<board>-bcsr"
+ - reg : Offset and length of the register set for the device
+
+Example:
+
+       bcsr@f8000000 {
+               compatible = "fsl,mpc8360mds-bcsr";
+               reg = <f8000000 8000>;
+       };
+
+* Freescale on board FPGA
+
+This is the memory-mapped registers for on board FPGA.
+
+Required properities:
+- compatible : should be "fsl,fpga-pixis".
+- reg : should contain the address and the length of the FPPGA register
+  set.
+- interrupt-parent: should specify phandle for the interrupt controller.
+- interrupts : should specify event (wakeup) IRQ.
+
+Example (MPC8610HPCD):
+
+       board-control@e8000000 {
+               compatible = "fsl,fpga-pixis";
+               reg = <0xe8000000 32>;
+               interrupt-parent = <&mpic>;
+               interrupts = <8 8>;
+       };
+
+* Freescale BCSR GPIO banks
+
+Some BCSR registers act as simple GPIO controllers, each such
+register can be represented by the gpio-controller node.
+
+Required properities:
+- compatible : Should be "fsl,<board>-bcsr-gpio".
+- reg : Should contain the address and the length of the GPIO bank
+  register.
+- #gpio-cells : Should be two. The first cell is the pin number and the
+  second cell is used to specify optional parameters (currently unused).
+- gpio-controller : Marks the port as GPIO controller.
+
+Example:
+
+       bcsr@1,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc8360mds-bcsr";
+               reg = <1 0 0x8000>;
+               ranges = <0 1 0 0x8000>;
+
+               bcsr13: gpio-controller@d {
+                       #gpio-cells = <2>;
+                       compatible = "fsl,mpc8360mds-bcsr-gpio";
+                       reg = <0xd 1>;
+                       gpio-controller;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm.txt
new file mode 100644 (file)
index 0000000..160c752
--- /dev/null
@@ -0,0 +1,67 @@
+* Freescale Communications Processor Module
+
+NOTE: This is an interim binding, and will likely change slightly,
+as more devices are supported.  The QE bindings especially are
+incomplete.
+
+* Root CPM node
+
+Properties:
+- compatible : "fsl,cpm1", "fsl,cpm2", or "fsl,qe".
+- reg : A 48-byte region beginning with CPCR.
+
+Example:
+     cpm@119c0 {
+       #address-cells = <1>;
+       #size-cells = <1>;
+       #interrupt-cells = <2>;
+       compatible = "fsl,mpc8272-cpm", "fsl,cpm2";
+       reg = <119c0 30>;
+     }
+
+* Properties common to multiple CPM/QE devices
+
+- fsl,cpm-command : This value is ORed with the opcode and command flag
+                    to specify the device on which a CPM command operates.
+
+- fsl,cpm-brg : Indicates which baud rate generator the device
+                is associated with.  If absent, an unused BRG
+                should be dynamically allocated.  If zero, the
+                device uses an external clock rather than a BRG.
+
+- reg : Unless otherwise specified, the first resource represents the
+        scc/fcc/ucc registers, and the second represents the device's
+        parameter RAM region (if it has one).
+
+* Multi-User RAM (MURAM)
+
+The multi-user/dual-ported RAM is expressed as a bus under the CPM node.
+
+Ranges must be set up subject to the following restrictions:
+
+- Children's reg nodes must be offsets from the start of all muram, even
+  if the user-data area does not begin at zero.
+- If multiple range entries are used, the difference between the parent
+  address and the child address must be the same in all, so that a single
+  mapping can cover them all while maintaining the ability to determine
+  CPM-side offsets with pointer subtraction.  It is recommended that
+  multiple range entries not be used.
+- A child address of zero must be translatable, even if no reg resources
+  contain it.
+
+A child "data" node must exist, compatible with "fsl,cpm-muram-data", to
+indicate the portion of muram that is usable by the OS for arbitrary
+purposes.  The data node may have an arbitrary number of reg resources,
+all of which contribute to the allocatable muram pool.
+
+Example, based on mpc8272:
+       muram@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0 10000>;
+
+               data@0 {
+                       compatible = "fsl,cpm-muram-data";
+                       reg = <0 2000 9800 800>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/brg.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/brg.txt
new file mode 100644 (file)
index 0000000..4c7d45e
--- /dev/null
@@ -0,0 +1,21 @@
+* Baud Rate Generators
+
+Currently defined compatibles:
+fsl,cpm-brg
+fsl,cpm1-brg
+fsl,cpm2-brg
+
+Properties:
+- reg : There may be an arbitrary number of reg resources; BRG
+  numbers are assigned to these in order.
+- clock-frequency : Specifies the base frequency driving
+  the BRG.
+
+Example:
+       brg@119f0 {
+               compatible = "fsl,mpc8272-brg",
+                            "fsl,cpm2-brg",
+                            "fsl,cpm-brg";
+               reg = <119f0 10 115f0 10>;
+               clock-frequency = <d#25000000>;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/i2c.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/i2c.txt
new file mode 100644 (file)
index 0000000..87bc604
--- /dev/null
@@ -0,0 +1,41 @@
+* I2C
+
+The I2C controller is expressed as a bus under the CPM node.
+
+Properties:
+- compatible : "fsl,cpm1-i2c", "fsl,cpm2-i2c"
+- reg : On CPM2 devices, the second resource doesn't specify the I2C
+  Parameter RAM itself, but the I2C_BASE field of the CPM2 Parameter RAM
+  (typically 0x8afc 0x2).
+- #address-cells : Should be one. The cell is the i2c device address with
+  the r/w bit set to zero.
+- #size-cells : Should be zero.
+- clock-frequency : Can be used to set the i2c clock frequency. If
+  unspecified, a default frequency of 60kHz is being used.
+The following two properties are deprecated. They are only used by legacy
+i2c drivers to find the bus to probe:
+- linux,i2c-index : Can be used to hard code an i2c bus number. By default,
+  the bus number is dynamically assigned by the i2c core.
+- linux,i2c-class : Can be used to override the i2c class. The class is used
+  by legacy i2c device drivers to find a bus in a specific context like
+  system management, video or sound. By default, I2C_CLASS_HWMON (1) is
+  being used. The definition of the classes can be found in
+  include/i2c/i2c.h
+
+Example, based on mpc823:
+
+       i2c@860 {
+               compatible = "fsl,mpc823-i2c",
+                            "fsl,cpm1-i2c";
+               reg = <0x860 0x20 0x3c80 0x30>;
+               interrupts = <16>;
+               interrupt-parent = <&CPM_PIC>;
+               fsl,cpm-command = <0x10>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               rtc@68 {
+                       compatible = "dallas,ds1307";
+                       reg = <0x68>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/pic.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/pic.txt
new file mode 100644 (file)
index 0000000..8e3ee16
--- /dev/null
@@ -0,0 +1,18 @@
+* Interrupt Controllers
+
+Currently defined compatibles:
+- fsl,cpm1-pic
+  - only one interrupt cell
+- fsl,pq1-pic
+- fsl,cpm2-pic
+  - second interrupt cell is level/sense:
+    - 2 is falling edge
+    - 8 is active low
+
+Example:
+       interrupt-controller@10c00 {
+               #interrupt-cells = <2>;
+               interrupt-controller;
+               reg = <10c00 80>;
+               compatible = "mpc8272-pic", "fsl,cpm2-pic";
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/usb.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/cpm/usb.txt
new file mode 100644 (file)
index 0000000..74bfda4
--- /dev/null
@@ -0,0 +1,15 @@
+* USB (Universal Serial Bus Controller)
+
+Properties:
+- compatible : "fsl,cpm1-usb", "fsl,cpm2-usb", "fsl,qe-usb"
+
+Example:
+       usb@11bc0 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "fsl,cpm2-usb";
+               reg = <11b60 18 8b00 100>;
+               interrupts = <b 8>;
+               interrupt-parent = <&PIC>;
+               fsl,cpm-command = <2e600000>;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/gpio.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/gpio.txt
new file mode 100644 (file)
index 0000000..349f79f
--- /dev/null
@@ -0,0 +1,38 @@
+Every GPIO controller node must have #gpio-cells property defined,
+this information will be used to translate gpio-specifiers.
+
+On CPM1 devices, all ports are using slightly different register layouts.
+Ports A, C and D are 16bit ports and Ports B and E are 32bit ports.
+
+On CPM2 devices, all ports are 32bit ports and use a common register layout.
+
+Required properties:
+- compatible : "fsl,cpm1-pario-bank-a", "fsl,cpm1-pario-bank-b",
+  "fsl,cpm1-pario-bank-c", "fsl,cpm1-pario-bank-d",
+  "fsl,cpm1-pario-bank-e", "fsl,cpm2-pario-bank"
+- #gpio-cells : Should be two. The first cell is the pin number and the
+  second cell is used to specify optional parameters (currently unused).
+- gpio-controller : Marks the port as GPIO controller.
+
+Example of three SOC GPIO banks defined as gpio-controller nodes:
+
+       CPM1_PIO_A: gpio-controller@950 {
+               #gpio-cells = <2>;
+               compatible = "fsl,cpm1-pario-bank-a";
+               reg = <0x950 0x10>;
+               gpio-controller;
+       };
+
+       CPM1_PIO_B: gpio-controller@ab8 {
+               #gpio-cells = <2>;
+               compatible = "fsl,cpm1-pario-bank-b";
+               reg = <0xab8 0x10>;
+               gpio-controller;
+       };
+
+       CPM1_PIO_E: gpio-controller@ac8 {
+               #gpio-cells = <2>;
+               compatible = "fsl,cpm1-pario-bank-e";
+               reg = <0xac8 0x18>;
+               gpio-controller;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/network.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/network.txt
new file mode 100644 (file)
index 0000000..0e42694
--- /dev/null
@@ -0,0 +1,45 @@
+* Network
+
+Currently defined compatibles:
+- fsl,cpm1-scc-enet
+- fsl,cpm2-scc-enet
+- fsl,cpm1-fec-enet
+- fsl,cpm2-fcc-enet (third resource is GFEMR)
+- fsl,qe-enet
+
+Example:
+
+       ethernet@11300 {
+               device_type = "network";
+               compatible = "fsl,mpc8272-fcc-enet",
+                            "fsl,cpm2-fcc-enet";
+               reg = <11300 20 8400 100 11390 1>;
+               local-mac-address = [ 00 00 00 00 00 00 ];
+               interrupts = <20 8>;
+               interrupt-parent = <&PIC>;
+               phy-handle = <&PHY0>;
+               fsl,cpm-command = <12000300>;
+       };
+
+* MDIO
+
+Currently defined compatibles:
+fsl,pq1-fec-mdio (reg is same as first resource of FEC device)
+fsl,cpm2-mdio-bitbang (reg is port C registers)
+
+Properties for fsl,cpm2-mdio-bitbang:
+fsl,mdio-pin : pin of port C controlling mdio data
+fsl,mdc-pin : pin of port C controlling mdio clock
+
+Example:
+       mdio@10d40 {
+               device_type = "mdio";
+               compatible = "fsl,mpc8272ads-mdio-bitbang",
+                            "fsl,mpc8272-mdio-bitbang",
+                            "fsl,cpm2-mdio-bitbang";
+               reg = <10d40 14>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               fsl,mdio-pin = <12>;
+               fsl,mdc-pin = <13>;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe.txt
new file mode 100644 (file)
index 0000000..4f89302
--- /dev/null
@@ -0,0 +1,115 @@
+* Freescale QUICC Engine module (QE)
+This represents qe module that is installed on PowerQUICC II Pro.
+
+NOTE:  This is an interim binding; it should be updated to fit
+in with the CPM binding later in this document.
+
+Basically, it is a bus of devices, that could act more or less
+as a complete entity (UCC, USB etc ). All of them should be siblings on
+the "root" qe node, using the common properties from there.
+The description below applies to the qe of MPC8360 and
+more nodes and properties would be extended in the future.
+
+i) Root QE device
+
+Required properties:
+- compatible : should be "fsl,qe";
+- model : precise model of the QE, Can be "QE", "CPM", or "CPM2"
+- reg : offset and length of the device registers.
+- bus-frequency : the clock frequency for QUICC Engine.
+- fsl,qe-num-riscs: define how many RISC engines the QE has.
+- fsl,qe-num-snums: define how many serial number(SNUM) the QE can use for the
+  threads.
+
+Optional properties:
+- fsl,firmware-phandle:
+    Usage: required only if there is no fsl,qe-firmware child node
+    Value type: <phandle>
+    Definition: Points to a firmware node (see "QE Firmware Node" below)
+        that contains the firmware that should be uploaded for this QE.
+        The compatible property for the firmware node should say,
+        "fsl,qe-firmware".
+
+Recommended properties
+- brg-frequency : the internal clock source frequency for baud-rate
+  generators in Hz.
+
+Example:
+     qe@e0100000 {
+       #address-cells = <1>;
+       #size-cells = <1>;
+       #interrupt-cells = <2>;
+       compatible = "fsl,qe";
+       ranges = <0 e0100000 00100000>;
+       reg = <e0100000 480>;
+       brg-frequency = <0>;
+       bus-frequency = <179A7B00>;
+     }
+
+* Multi-User RAM (MURAM)
+
+Required properties:
+- compatible : should be "fsl,qe-muram", "fsl,cpm-muram".
+- mode : the could be "host" or "slave".
+- ranges : Should be defined as specified in 1) to describe the
+   translation of MURAM addresses.
+- data-only : sub-node which defines the address area under MURAM
+   bus that can be allocated as data/parameter
+
+Example:
+
+     muram@10000 {
+       compatible = "fsl,qe-muram", "fsl,cpm-muram";
+       ranges = <0 00010000 0000c000>;
+
+       data-only@0{
+               compatible = "fsl,qe-muram-data",
+                            "fsl,cpm-muram-data";
+               reg = <0 c000>;
+       };
+     };
+
+* QE Firmware Node
+
+This node defines a firmware binary that is embedded in the device tree, for
+the purpose of passing the firmware from bootloader to the kernel, or from
+the hypervisor to the guest.
+
+The firmware node itself contains the firmware binary contents, a compatible
+property, and any firmware-specific properties.  The node should be placed
+inside a QE node that needs it.  Doing so eliminates the need for a
+fsl,firmware-phandle property.  Other QE nodes that need the same firmware
+should define an fsl,firmware-phandle property that points to the firmware node
+in the first QE node.
+
+The fsl,firmware property can be specified in the DTS (possibly using incbin)
+or can be inserted by the boot loader at boot time.
+
+Required properties:
+  - compatible
+      Usage: required
+      Value type: <string>
+      Definition: A standard property.  Specify a string that indicates what
+          kind of firmware it is.  For QE, this should be "fsl,qe-firmware".
+
+   - fsl,firmware
+      Usage: required
+      Value type: <prop-encoded-array>, encoded as an array of bytes
+      Definition: A standard property.  This property contains the firmware
+          binary "blob".
+
+Example:
+       qe1@e0080000 {
+               compatible = "fsl,qe";
+               qe_firmware:qe-firmware {
+                       compatible = "fsl,qe-firmware";
+                       fsl,firmware = [0x70 0xcd 0x00 0x00 0x01 0x46 0x45 ...];
+               };
+               ...
+       };
+
+       qe2@e0090000 {
+               compatible = "fsl,qe";
+               fsl,firmware-phandle = <&qe_firmware>;
+               ...
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/firmware.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/firmware.txt
new file mode 100644 (file)
index 0000000..249db3a
--- /dev/null
@@ -0,0 +1,24 @@
+* Uploaded QE firmware
+
+      If a new firmware has been uploaded to the QE (usually by the
+      boot loader), then a 'firmware' child node should be added to the QE
+      node.  This node provides information on the uploaded firmware that
+      device drivers may need.
+
+      Required properties:
+      - id: The string name of the firmware.  This is taken from the 'id'
+            member of the qe_firmware structure of the uploaded firmware.
+            Device drivers can search this string to determine if the
+            firmware they want is already present.
+      - extended-modes: The Extended Modes bitfield, taken from the
+                  firmware binary.  It is a 64-bit number represented
+                  as an array of two 32-bit numbers.
+      - virtual-traps: The virtual traps, taken from the firmware binary.
+                 It is an array of 8 32-bit numbers.
+
+Example:
+       firmware {
+               id = "Soft-UART";
+               extended-modes = <0 0>;
+               virtual-traps = <0 0 0 0 0 0 0 0>;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/par_io.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/par_io.txt
new file mode 100644 (file)
index 0000000..6098426
--- /dev/null
@@ -0,0 +1,51 @@
+* Parallel I/O Ports
+
+This node configures Parallel I/O ports for CPUs with QE support.
+The node should reside in the "soc" node of the tree.  For each
+device that using parallel I/O ports, a child node should be created.
+See the definition of the Pin configuration nodes below for more
+information.
+
+Required properties:
+- device_type : should be "par_io".
+- reg : offset to the register set and its length.
+- num-ports : number of Parallel I/O ports
+
+Example:
+par_io@1400 {
+       reg = <1400 100>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+       device_type = "par_io";
+       num-ports = <7>;
+       ucc_pin@01 {
+               ......
+       };
+
+Note that "par_io" nodes are obsolete, and should not be used for
+the new device trees. Instead, each Par I/O bank should be represented
+via its own gpio-controller node:
+
+Required properties:
+- #gpio-cells : should be "2".
+- compatible : should be "fsl,<chip>-qe-pario-bank",
+  "fsl,mpc8323-qe-pario-bank".
+- reg : offset to the register set and its length.
+- gpio-controller : node to identify gpio controllers.
+
+Example:
+       qe_pio_a: gpio-controller@1400 {
+               #gpio-cells = <2>;
+               compatible = "fsl,mpc8360-qe-pario-bank",
+               "fsl,mpc8323-qe-pario-bank";
+               reg = <0x1400 0x18>;
+               gpio-controller;
+         };
+
+       qe_pio_e: gpio-controller@1460 {
+               #gpio-cells = <2>;
+               compatible = "fsl,mpc8360-qe-pario-bank",
+                            "fsl,mpc8323-qe-pario-bank";
+               reg = <0x1460 0x18>;
+               gpio-controller;
+         };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/pincfg.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/pincfg.txt
new file mode 100644 (file)
index 0000000..c5b4306
--- /dev/null
@@ -0,0 +1,60 @@
+* Pin configuration nodes
+
+Required properties:
+- linux,phandle : phandle of this node; likely referenced by a QE
+  device.
+- pio-map : array of pin configurations.  Each pin is defined by 6
+  integers.  The six numbers are respectively: port, pin, dir,
+  open_drain, assignment, has_irq.
+  - port : port number of the pin; 0-6 represent port A-G in UM.
+  - pin : pin number in the port.
+  - dir : direction of the pin, should encode as follows:
+
+     0 = The pin is disabled
+     1 = The pin is an output
+     2 = The pin is an input
+     3 = The pin is I/O
+
+  - open_drain : indicates the pin is normal or wired-OR:
+
+     0 = The pin is actively driven as an output
+     1 = The pin is an open-drain driver. As an output, the pin is
+         driven active-low, otherwise it is three-stated.
+
+  - assignment : function number of the pin according to the Pin Assignment
+    tables in User Manual.  Each pin can have up to 4 possible functions in
+    QE and two options for CPM.
+  - has_irq : indicates if the pin is used as source of external
+    interrupts.
+
+Example:
+     ucc_pin@01 {
+       linux,phandle = <140001>;
+       pio-map = <
+       /* port  pin  dir  open_drain  assignment  has_irq */
+               0  3  1  0  1  0        /* TxD0 */
+               0  4  1  0  1  0        /* TxD1 */
+               0  5  1  0  1  0        /* TxD2 */
+               0  6  1  0  1  0        /* TxD3 */
+               1  6  1  0  3  0        /* TxD4 */
+               1  7  1  0  1  0        /* TxD5 */
+               1  9  1  0  2  0        /* TxD6 */
+               1  a  1  0  2  0        /* TxD7 */
+               0  9  2  0  1  0        /* RxD0 */
+               0  a  2  0  1  0        /* RxD1 */
+               0  b  2  0  1  0        /* RxD2 */
+               0  c  2  0  1  0        /* RxD3 */
+               0  d  2  0  1  0        /* RxD4 */
+               1  1  2  0  2  0        /* RxD5 */
+               1  0  2  0  2  0        /* RxD6 */
+               1  4  2  0  2  0        /* RxD7 */
+               0  7  1  0  1  0        /* TX_EN */
+               0  8  1  0  1  0        /* TX_ER */
+               0  f  2  0  1  0        /* RX_DV */
+               0  10 2  0  1  0        /* RX_ER */
+               0  0  2  0  1  0        /* RX_CLK */
+               2  9  1  0  3  0        /* GTX_CLK - CLK10 */
+               2  8  2  0  1  0>;      /* GTX125 - CLK9 */
+     };
+
+
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/ucc.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/ucc.txt
new file mode 100644 (file)
index 0000000..e47734b
--- /dev/null
@@ -0,0 +1,70 @@
+* UCC (Unified Communications Controllers)
+
+Required properties:
+- device_type : should be "network", "hldc", "uart", "transparent"
+  "bisync", "atm", or "serial".
+- compatible : could be "ucc_geth" or "fsl_atm" and so on.
+- cell-index : the ucc number(1-8), corresponding to UCCx in UM.
+- reg : Offset and length of the register set for the device
+- interrupts : <a b> where a is the interrupt number and b is a
+  field that represents an encoding of the sense and level
+  information for the interrupt.  This should be encoded based on
+  the information in section 2) depending on the type of interrupt
+  controller you have.
+- interrupt-parent : the phandle for the interrupt controller that
+  services interrupts for this device.
+- pio-handle : The phandle for the Parallel I/O port configuration.
+- port-number : for UART drivers, the port number to use, between 0 and 3.
+  This usually corresponds to the /dev/ttyQE device, e.g. <0> = /dev/ttyQE0.
+  The port number is added to the minor number of the device.  Unlike the
+  CPM UART driver, the port-number is required for the QE UART driver.
+- soft-uart : for UART drivers, if specified this means the QE UART device
+  driver should use "Soft-UART" mode, which is needed on some SOCs that have
+  broken UART hardware.  Soft-UART is provided via a microcode upload.
+- rx-clock-name: the UCC receive clock source
+  "none": clock source is disabled
+  "brg1" through "brg16": clock source is BRG1-BRG16, respectively
+  "clk1" through "clk24": clock source is CLK1-CLK24, respectively
+- tx-clock-name: the UCC transmit clock source
+  "none": clock source is disabled
+  "brg1" through "brg16": clock source is BRG1-BRG16, respectively
+  "clk1" through "clk24": clock source is CLK1-CLK24, respectively
+The following two properties are deprecated.  rx-clock has been replaced
+with rx-clock-name, and tx-clock has been replaced with tx-clock-name.
+Drivers that currently use the deprecated properties should continue to
+do so, in order to support older device trees, but they should be updated
+to check for the new properties first.
+- rx-clock : represents the UCC receive clock source.
+  0x00 : clock source is disabled;
+  0x1~0x10 : clock source is BRG1~BRG16 respectively;
+  0x11~0x28: clock source is QE_CLK1~QE_CLK24 respectively.
+- tx-clock: represents the UCC transmit clock source;
+  0x00 : clock source is disabled;
+  0x1~0x10 : clock source is BRG1~BRG16 respectively;
+  0x11~0x28: clock source is QE_CLK1~QE_CLK24 respectively.
+
+Required properties for network device_type:
+- mac-address : list of bytes representing the ethernet address.
+- phy-handle : The phandle for the PHY connected to this controller.
+
+Recommended properties:
+- phy-connection-type : a string naming the controller/PHY interface type,
+  i.e., "mii" (default), "rmii", "gmii", "rgmii", "rgmii-id" (Internal
+  Delay), "rgmii-txid" (delay on TX only), "rgmii-rxid" (delay on RX only),
+  "tbi", or "rtbi".
+
+Example:
+       ucc@2000 {
+               device_type = "network";
+               compatible = "ucc_geth";
+               cell-index = <1>;
+               reg = <2000 200>;
+               interrupts = <a0 0>;
+               interrupt-parent = <700>;
+               mac-address = [ 00 04 9f 00 23 23 ];
+               rx-clock = "none";
+               tx-clock = "clk9";
+               phy-handle = <212000>;
+               phy-connection-type = "gmii";
+               pio-handle = <140001>;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/usb.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/qe/usb.txt
new file mode 100644 (file)
index 0000000..9ccd5f3
--- /dev/null
@@ -0,0 +1,37 @@
+Freescale QUICC Engine USB Controller
+
+Required properties:
+- compatible : should be "fsl,<chip>-qe-usb", "fsl,mpc8323-qe-usb".
+- reg : the first two cells should contain usb registers location and
+  length, the next two two cells should contain PRAM location and
+  length.
+- interrupts : should contain USB interrupt.
+- interrupt-parent : interrupt source phandle.
+- fsl,fullspeed-clock : specifies the full speed USB clock source:
+  "none": clock source is disabled
+  "brg1" through "brg16": clock source is BRG1-BRG16, respectively
+  "clk1" through "clk24": clock source is CLK1-CLK24, respectively
+- fsl,lowspeed-clock : specifies the low speed USB clock source:
+  "none": clock source is disabled
+  "brg1" through "brg16": clock source is BRG1-BRG16, respectively
+  "clk1" through "clk24": clock source is CLK1-CLK24, respectively
+- hub-power-budget : USB power budget for the root hub, in mA.
+- gpios : should specify GPIOs in this order: USBOE, USBTP, USBTN, USBRP,
+  USBRN, SPEED (optional), and POWER (optional).
+
+Example:
+
+usb@6c0 {
+       compatible = "fsl,mpc8360-qe-usb", "fsl,mpc8323-qe-usb";
+       reg = <0x6c0 0x40 0x8b00 0x100>;
+       interrupts = <11>;
+       interrupt-parent = <&qeic>;
+       fsl,fullspeed-clock = "clk21";
+       gpios = <&qe_pio_b  2 0 /* USBOE */
+                &qe_pio_b  3 0 /* USBTP */
+                &qe_pio_b  8 0 /* USBTN */
+                &qe_pio_b  9 0 /* USBRP */
+                &qe_pio_b 11 0 /* USBRN */
+                &qe_pio_e 20 0 /* SPEED */
+                &qe_pio_e 21 0 /* POWER */>;
+};
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/serial.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpm_qe/serial.txt
new file mode 100644 (file)
index 0000000..2ea76d9
--- /dev/null
@@ -0,0 +1,32 @@
+* Serial
+
+Currently defined compatibles:
+- fsl,cpm1-smc-uart
+- fsl,cpm2-smc-uart
+- fsl,cpm1-scc-uart
+- fsl,cpm2-scc-uart
+- fsl,qe-uart
+
+Modem control lines connected to GPIO controllers are listed in the gpios
+property as described in booting-without-of.txt, section IX.1 in the following
+order:
+
+CTS, RTS, DCD, DSR, DTR, and RI.
+
+The gpios property is optional and can be left out when control lines are
+not used.
+
+Example:
+
+       serial@11a00 {
+               device_type = "serial";
+               compatible = "fsl,mpc8272-scc-uart",
+                            "fsl,cpm2-scc-uart";
+               reg = <11a00 20 8000 100>;
+               interrupts = <28 8>;
+               interrupt-parent = <&PIC>;
+               fsl,cpm-brg = <1>;
+               fsl,cpm-command = <00800000>;
+               gpios = <&gpio_c 15 0
+                        &gpio_d 29 0>;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/diu.txt b/Documentation/devicetree/bindings/powerpc/fsl/diu.txt
new file mode 100644 (file)
index 0000000..b66cb6d
--- /dev/null
@@ -0,0 +1,34 @@
+* Freescale Display Interface Unit
+
+The Freescale DIU is a LCD controller, with proper hardware, it can also
+drive DVI monitors.
+
+Required properties:
+- compatible : should be "fsl,diu" or "fsl,mpc5121-diu".
+- reg : should contain at least address and length of the DIU register
+  set.
+- interrupts : one DIU interrupt should be described here.
+- interrupt-parent : the phandle for the interrupt controller that
+  services interrupts for this device.
+
+Optional properties:
+- edid : verbatim EDID data block describing attached display.
+  Data from the detailed timing descriptor will be used to
+  program the display controller.
+
+Example (MPC8610HPCD):
+       display@2c000 {
+               compatible = "fsl,diu";
+               reg = <0x2c000 100>;
+               interrupts = <72 2>;
+               interrupt-parent = <&mpic>;
+       };
+
+Example for MPC5121:
+       display@2100 {
+               compatible = "fsl,mpc5121-diu";
+               reg = <0x2100 0x100>;
+               interrupts = <64 0x8>;
+               interrupt-parent = <&ipic>;
+               edid = [edid-data];
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/dma.txt b/Documentation/devicetree/bindings/powerpc/fsl/dma.txt
new file mode 100644 (file)
index 0000000..2a4b4bc
--- /dev/null
@@ -0,0 +1,144 @@
+* Freescale 83xx DMA Controller
+
+Freescale PowerPC 83xx have on chip general purpose DMA controllers.
+
+Required properties:
+
+- compatible        : compatible list, contains 2 entries, first is
+                "fsl,CHIP-dma", where CHIP is the processor
+                (mpc8349, mpc8360, etc.) and the second is
+                "fsl,elo-dma"
+- reg               : <registers mapping for DMA general status reg>
+- ranges               : Should be defined as specified in 1) to describe the
+                 DMA controller channels.
+- cell-index        : controller index.  0 for controller @ 0x8100
+- interrupts        : <interrupt mapping for DMA IRQ>
+- interrupt-parent  : optional, if needed for interrupt mapping
+
+
+- DMA channel nodes:
+        - compatible        : compatible list, contains 2 entries, first is
+                        "fsl,CHIP-dma-channel", where CHIP is the processor
+                        (mpc8349, mpc8350, etc.) and the second is
+                        "fsl,elo-dma-channel". However, see note below.
+        - reg               : <registers mapping for channel>
+        - cell-index        : dma channel index starts at 0.
+
+Optional properties:
+        - interrupts        : <interrupt mapping for DMA channel IRQ>
+                         (on 83xx this is expected to be identical to
+                          the interrupts property of the parent node)
+        - interrupt-parent  : optional, if needed for interrupt mapping
+
+Example:
+       dma@82a8 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc8349-dma", "fsl,elo-dma";
+               reg = <0x82a8 4>;
+               ranges = <0 0x8100 0x1a4>;
+               interrupt-parent = <&ipic>;
+               interrupts = <71 8>;
+               cell-index = <0>;
+               dma-channel@0 {
+                       compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
+                       cell-index = <0>;
+                       reg = <0 0x80>;
+                       interrupt-parent = <&ipic>;
+                       interrupts = <71 8>;
+               };
+               dma-channel@80 {
+                       compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
+                       cell-index = <1>;
+                       reg = <0x80 0x80>;
+                       interrupt-parent = <&ipic>;
+                       interrupts = <71 8>;
+               };
+               dma-channel@100 {
+                       compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
+                       cell-index = <2>;
+                       reg = <0x100 0x80>;
+                       interrupt-parent = <&ipic>;
+                       interrupts = <71 8>;
+               };
+               dma-channel@180 {
+                       compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
+                       cell-index = <3>;
+                       reg = <0x180 0x80>;
+                       interrupt-parent = <&ipic>;
+                       interrupts = <71 8>;
+               };
+       };
+
+* Freescale 85xx/86xx DMA Controller
+
+Freescale PowerPC 85xx/86xx have on chip general purpose DMA controllers.
+
+Required properties:
+
+- compatible        : compatible list, contains 2 entries, first is
+                "fsl,CHIP-dma", where CHIP is the processor
+                (mpc8540, mpc8540, etc.) and the second is
+                "fsl,eloplus-dma"
+- reg               : <registers mapping for DMA general status reg>
+- cell-index        : controller index.  0 for controller @ 0x21000,
+                                         1 for controller @ 0xc000
+- ranges               : Should be defined as specified in 1) to describe the
+                 DMA controller channels.
+
+- DMA channel nodes:
+        - compatible        : compatible list, contains 2 entries, first is
+                        "fsl,CHIP-dma-channel", where CHIP is the processor
+                        (mpc8540, mpc8560, etc.) and the second is
+                        "fsl,eloplus-dma-channel". However, see note below.
+        - cell-index        : dma channel index starts at 0.
+        - reg               : <registers mapping for channel>
+        - interrupts        : <interrupt mapping for DMA channel IRQ>
+        - interrupt-parent  : optional, if needed for interrupt mapping
+
+Example:
+       dma@21300 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc8540-dma", "fsl,eloplus-dma";
+               reg = <0x21300 4>;
+               ranges = <0 0x21100 0x200>;
+               cell-index = <0>;
+               dma-channel@0 {
+                       compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel";
+                       reg = <0 0x80>;
+                       cell-index = <0>;
+                       interrupt-parent = <&mpic>;
+                       interrupts = <20 2>;
+               };
+               dma-channel@80 {
+                       compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel";
+                       reg = <0x80 0x80>;
+                       cell-index = <1>;
+                       interrupt-parent = <&mpic>;
+                       interrupts = <21 2>;
+               };
+               dma-channel@100 {
+                       compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel";
+                       reg = <0x100 0x80>;
+                       cell-index = <2>;
+                       interrupt-parent = <&mpic>;
+                       interrupts = <22 2>;
+               };
+               dma-channel@180 {
+                       compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel";
+                       reg = <0x180 0x80>;
+                       cell-index = <3>;
+                       interrupt-parent = <&mpic>;
+                       interrupts = <23 2>;
+               };
+       };
+
+Note on DMA channel compatible properties: The compatible property must say
+"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel" to be used by the Elo DMA
+driver (fsldma).  Any DMA channel used by fsldma cannot be used by another
+DMA driver, such as the SSI sound drivers for the MPC8610.  Therefore, any DMA
+channel that should be used for another driver should not use
+"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel".  For the SSI drivers, for
+example, the compatible property should be "fsl,ssi-dma-channel".  See ssi.txt
+for more information.
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/ecm.txt b/Documentation/devicetree/bindings/powerpc/fsl/ecm.txt
new file mode 100644 (file)
index 0000000..f514f29
--- /dev/null
@@ -0,0 +1,64 @@
+=====================================================================
+E500 LAW & Coherency Module Device Tree Binding
+Copyright (C) 2009 Freescale Semiconductor Inc.
+=====================================================================
+
+Local Access Window (LAW) Node
+
+The LAW node represents the region of CCSR space where local access
+windows are configured.  For ECM based devices this is the first 4k
+of CCSR space that includes CCSRBAR, ALTCBAR, ALTCAR, BPTR, and some
+number of local access windows as specified by fsl,num-laws.
+
+PROPERTIES
+
+  - compatible
+      Usage: required
+      Value type: <string>
+      Definition: Must include "fsl,ecm-law"
+
+  - reg
+      Usage: required
+      Value type: <prop-encoded-array>
+      Definition: A standard property.  The value specifies the
+          physical address offset and length of the CCSR space
+          registers.
+
+  - fsl,num-laws
+      Usage: required
+      Value type: <u32>
+      Definition: The value specifies the number of local access
+          windows for this device.
+
+=====================================================================
+
+E500 Coherency Module Node
+
+The E500 LAW node represents the region of CCSR space where ECM config
+and error reporting registers exist, this is the second 4k (0x1000)
+of CCSR space.
+
+PROPERTIES
+
+  - compatible
+      Usage: required
+      Value type: <string>
+      Definition: Must include "fsl,CHIP-ecm", "fsl,ecm" where
+      CHIP is the processor (mpc8572, mpc8544, etc.)
+
+  - reg
+      Usage: required
+      Value type: <prop-encoded-array>
+      Definition: A standard property.  The value specifies the
+          physical address offset and length of the CCSR space
+          registers.
+
+   - interrupts
+      Usage: required
+      Value type: <prop-encoded-array>
+
+   - interrupt-parent
+      Usage: required
+      Value type: <phandle>
+
+=====================================================================
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/gtm.txt b/Documentation/devicetree/bindings/powerpc/fsl/gtm.txt
new file mode 100644 (file)
index 0000000..9a33efd
--- /dev/null
@@ -0,0 +1,31 @@
+* Freescale General-purpose Timers Module
+
+Required properties:
+  - compatible : should be
+    "fsl,<chip>-gtm", "fsl,gtm" for SOC GTMs
+    "fsl,<chip>-qe-gtm", "fsl,qe-gtm", "fsl,gtm" for QE GTMs
+    "fsl,<chip>-cpm2-gtm", "fsl,cpm2-gtm", "fsl,gtm" for CPM2 GTMs
+  - reg : should contain gtm registers location and length (0x40).
+  - interrupts : should contain four interrupts.
+  - interrupt-parent : interrupt source phandle.
+  - clock-frequency : specifies the frequency driving the timer.
+
+Example:
+
+timer@500 {
+       compatible = "fsl,mpc8360-gtm", "fsl,gtm";
+       reg = <0x500 0x40>;
+       interrupts = <90 8 78 8 84 8 72 8>;
+       interrupt-parent = <&ipic>;
+       /* filled by u-boot */
+       clock-frequency = <0>;
+};
+
+timer@440 {
+       compatible = "fsl,mpc8360-qe-gtm", "fsl,qe-gtm", "fsl,gtm";
+       reg = <0x440 0x40>;
+       interrupts = <12 13 14 15>;
+       interrupt-parent = <&qeic>;
+       /* filled by u-boot */
+       clock-frequency = <0>;
+};
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/guts.txt b/Documentation/devicetree/bindings/powerpc/fsl/guts.txt
new file mode 100644 (file)
index 0000000..9e7a241
--- /dev/null
@@ -0,0 +1,25 @@
+* Global Utilities Block
+
+The global utilities block controls power management, I/O device
+enabling, power-on-reset configuration monitoring, general-purpose
+I/O signal configuration, alternate function selection for multiplexed
+signals, and clock control.
+
+Required properties:
+
+ - compatible : Should define the compatible device type for
+   global-utilities.
+ - reg : Offset and length of the register set for the device.
+
+Recommended properties:
+
+ - fsl,has-rstcr : Indicates that the global utilities register set
+   contains a functioning "reset control register" (i.e. the board
+   is wired to reset upon setting the HRESET_REQ bit in this register).
+
+Example:
+       global-utilities@e0000 {        /* global utilities block */
+               compatible = "fsl,mpc8548-guts";
+               reg = <e0000 1000>;
+               fsl,has-rstcr;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/lbc.txt b/Documentation/devicetree/bindings/powerpc/fsl/lbc.txt
new file mode 100644 (file)
index 0000000..3300fec
--- /dev/null
@@ -0,0 +1,35 @@
+* Chipselect/Local Bus
+
+Properties:
+- name : Should be localbus
+- #address-cells : Should be either two or three.  The first cell is the
+                   chipselect number, and the remaining cells are the
+                   offset into the chipselect.
+- #size-cells : Either one or two, depending on how large each chipselect
+                can be.
+- ranges : Each range corresponds to a single chipselect, and cover
+           the entire access window as configured.
+
+Example:
+       localbus@f0010100 {
+               compatible = "fsl,mpc8272-localbus",
+                          "fsl,pq2-localbus";
+               #address-cells = <2>;
+               #size-cells = <1>;
+               reg = <f0010100 40>;
+
+               ranges = <0 0 fe000000 02000000
+                         1 0 f4500000 00008000>;
+
+               flash@0,0 {
+                       compatible = "jedec-flash";
+                       reg = <0 0 2000000>;
+                       bank-width = <4>;
+                       device-width = <1>;
+               };
+
+               board-control@1,0 {
+                       reg = <1 0 20>;
+                       compatible = "fsl,mpc8272ads-bcsr";
+               };
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mcm.txt b/Documentation/devicetree/bindings/powerpc/fsl/mcm.txt
new file mode 100644 (file)
index 0000000..4ceda9b
--- /dev/null
@@ -0,0 +1,64 @@
+=====================================================================
+MPX LAW & Coherency Module Device Tree Binding
+Copyright (C) 2009 Freescale Semiconductor Inc.
+=====================================================================
+
+Local Access Window (LAW) Node
+
+The LAW node represents the region of CCSR space where local access
+windows are configured.  For MCM based devices this is the first 4k
+of CCSR space that includes CCSRBAR, ALTCBAR, ALTCAR, BPTR, and some
+number of local access windows as specified by fsl,num-laws.
+
+PROPERTIES
+
+  - compatible
+      Usage: required
+      Value type: <string>
+      Definition: Must include "fsl,mcm-law"
+
+  - reg
+      Usage: required
+      Value type: <prop-encoded-array>
+      Definition: A standard property.  The value specifies the
+          physical address offset and length of the CCSR space
+          registers.
+
+  - fsl,num-laws
+      Usage: required
+      Value type: <u32>
+      Definition: The value specifies the number of local access
+          windows for this device.
+
+=====================================================================
+
+MPX Coherency Module Node
+
+The MPX LAW node represents the region of CCSR space where MCM config
+and error reporting registers exist, this is the second 4k (0x1000)
+of CCSR space.
+
+PROPERTIES
+
+  - compatible
+      Usage: required
+      Value type: <string>
+      Definition: Must include "fsl,CHIP-mcm", "fsl,mcm" where
+      CHIP is the processor (mpc8641, mpc8610, etc.)
+
+  - reg
+      Usage: required
+      Value type: <prop-encoded-array>
+      Definition: A standard property.  The value specifies the
+          physical address offset and length of the CCSR space
+          registers.
+
+   - interrupts
+      Usage: required
+      Value type: <prop-encoded-array>
+
+   - interrupt-parent
+      Usage: required
+      Value type: <phandle>
+
+=====================================================================
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mcu-mpc8349emitx.txt b/Documentation/devicetree/bindings/powerpc/fsl/mcu-mpc8349emitx.txt
new file mode 100644 (file)
index 0000000..0f76633
--- /dev/null
@@ -0,0 +1,17 @@
+Freescale MPC8349E-mITX-compatible Power Management Micro Controller Unit (MCU)
+
+Required properties:
+- compatible : "fsl,<mcu-chip>-<board>", "fsl,mcu-mpc8349emitx".
+- reg : should specify I2C address (0x0a).
+- #gpio-cells : should be 2.
+- gpio-controller : should be present.
+
+Example:
+
+mcu@0a {
+       #gpio-cells = <2>;
+       compatible = "fsl,mc9s08qg8-mpc8349emitx",
+                    "fsl,mcu-mpc8349emitx";
+       reg = <0x0a>;
+       gpio-controller;
+};
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpc5121-psc.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpc5121-psc.txt
new file mode 100644 (file)
index 0000000..8832e87
--- /dev/null
@@ -0,0 +1,70 @@
+MPC5121 PSC Device Tree Bindings
+
+PSC in UART mode
+----------------
+
+For PSC in UART mode the needed PSC serial devices
+are specified by fsl,mpc5121-psc-uart nodes in the
+fsl,mpc5121-immr SoC node. Additionally the PSC FIFO
+Controller node fsl,mpc5121-psc-fifo is requered there:
+
+fsl,mpc5121-psc-uart nodes
+--------------------------
+
+Required properties :
+ - compatible : Should contain "fsl,mpc5121-psc-uart" and "fsl,mpc5121-psc"
+ - cell-index : Index of the PSC in hardware
+ - reg : Offset and length of the register set for the PSC device
+ - interrupts : <a b> where a is the interrupt number of the
+   PSC FIFO Controller and b is a field that represents an
+   encoding of the sense and level information for the interrupt.
+ - interrupt-parent : the phandle for the interrupt controller that
+   services interrupts for this device.
+
+Recommended properties :
+ - fsl,rx-fifo-size : the size of the RX fifo slice (a multiple of 4)
+ - fsl,tx-fifo-size : the size of the TX fifo slice (a multiple of 4)
+
+
+fsl,mpc5121-psc-fifo node
+-------------------------
+
+Required properties :
+ - compatible : Should be "fsl,mpc5121-psc-fifo"
+ - reg : Offset and length of the register set for the PSC
+         FIFO Controller
+ - interrupts : <a b> where a is the interrupt number of the
+   PSC FIFO Controller and b is a field that represents an
+   encoding of the sense and level information for the interrupt.
+ - interrupt-parent : the phandle for the interrupt controller that
+   services interrupts for this device.
+
+
+Example for a board using PSC0 and PSC1 devices in serial mode:
+
+serial@11000 {
+       compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
+       cell-index = <0>;
+       reg = <0x11000 0x100>;
+       interrupts = <40 0x8>;
+       interrupt-parent = < &ipic >;
+       fsl,rx-fifo-size = <16>;
+       fsl,tx-fifo-size = <16>;
+};
+
+serial@11100 {
+       compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
+       cell-index = <1>;
+       reg = <0x11100 0x100>;
+       interrupts = <40 0x8>;
+       interrupt-parent = < &ipic >;
+       fsl,rx-fifo-size = <16>;
+       fsl,tx-fifo-size = <16>;
+};
+
+pscfifo@11f00 {
+       compatible = "fsl,mpc5121-psc-fifo";
+       reg = <0x11f00 0x100>;
+       interrupts = <40 0x8>;
+       interrupt-parent = < &ipic >;
+};
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpc5200.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpc5200.txt
new file mode 100644 (file)
index 0000000..4ccb2cd
--- /dev/null
@@ -0,0 +1,198 @@
+MPC5200 Device Tree Bindings
+----------------------------
+
+(c) 2006-2009 Secret Lab Technologies Ltd
+Grant Likely <grant.likely@secretlab.ca>
+
+Naming conventions
+------------------
+For mpc5200 on-chip devices, the format for each compatible value is
+<chip>-<device>[-<mode>].  The OS should be able to match a device driver
+to the device based solely on the compatible value.  If two drivers
+match on the compatible list; the 'most compatible' driver should be
+selected.
+
+The split between the MPC5200 and the MPC5200B leaves a bit of a
+conundrum.  How should the compatible property be set up to provide
+maximum compatibility information; but still accurately describe the
+chip?  For the MPC5200; the answer is easy.  Most of the SoC devices
+originally appeared on the MPC5200.  Since they didn't exist anywhere
+else; the 5200 compatible properties will contain only one item;
+"fsl,mpc5200-<device>".
+
+The 5200B is almost the same as the 5200, but not quite.  It fixes
+silicon bugs and it adds a small number of enhancements.  Most of the
+devices either provide exactly the same interface as on the 5200.  A few
+devices have extra functions but still have a backwards compatible mode.
+To express this information as completely as possible, 5200B device trees
+should have two items in the compatible list:
+       compatible = "fsl,mpc5200b-<device>","fsl,mpc5200-<device>";
+
+It is *strongly* recommended that 5200B device trees follow this convention
+(instead of only listing the base mpc5200 item).
+
+ie. ethernet on mpc5200: compatible = "fsl,mpc5200-fec";
+    ethernet on mpc5200b: compatible = "fsl,mpc5200b-fec", "fsl,mpc5200-fec";
+
+Modal devices, like PSCs, also append the configured function to the
+end of the compatible field.  ie. A PSC in i2s mode would specify
+"fsl,mpc5200-psc-i2s", not "fsl,mpc5200-i2s".  This convention is chosen to
+avoid naming conflicts with non-psc devices providing the same
+function.  For example, "fsl,mpc5200-spi" and "fsl,mpc5200-psc-spi" describe
+the mpc5200 simple spi device and a PSC spi mode respectively.
+
+At the time of writing, exact chip may be either 'fsl,mpc5200' or
+'fsl,mpc5200b'.
+
+The soc node
+------------
+This node describes the on chip SOC peripherals.  Every mpc5200 based
+board will have this node, and as such there is a common naming
+convention for SOC devices.
+
+Required properties:
+name                   description
+----                   -----------
+ranges                 Memory range of the internal memory mapped registers.
+                       Should be <0 [baseaddr] 0xc000>
+reg                    Should be <[baseaddr] 0x100>
+compatible             mpc5200: "fsl,mpc5200-immr"
+                       mpc5200b: "fsl,mpc5200b-immr"
+system-frequency       'fsystem' frequency in Hz; XLB, IPB, USB and PCI
+                       clocks are derived from the fsystem clock.
+bus-frequency          IPB bus frequency in Hz.  Clock rate
+                       used by most of the soc devices.
+
+soc child nodes
+---------------
+Any on chip SOC devices available to Linux must appear as soc5200 child nodes.
+
+Note: The tables below show the value for the mpc5200.  A mpc5200b device
+tree should use the "fsl,mpc5200b-<device>","fsl,mpc5200-<device>" form.
+
+Required soc5200 child nodes:
+name                           compatible              Description
+----                           ----------              -----------
+cdm@<addr>                     fsl,mpc5200-cdm         Clock Distribution
+interrupt-controller@<addr>    fsl,mpc5200-pic         need an interrupt
+                                                       controller to boot
+bestcomm@<addr>                        fsl,mpc5200-bestcomm    Bestcomm DMA controller
+
+Recommended soc5200 child nodes; populate as needed for your board
+name           compatible              Description
+----           ----------              -----------
+timer@<addr>   fsl,mpc5200-gpt          General purpose timers
+gpio@<addr>    fsl,mpc5200-gpio         MPC5200 simple gpio controller
+gpio@<addr>    fsl,mpc5200-gpio-wkup    MPC5200 wakeup gpio controller
+rtc@<addr>     fsl,mpc5200-rtc          Real time clock
+mscan@<addr>   fsl,mpc5200-mscan        CAN bus controller
+pci@<addr>     fsl,mpc5200-pci          PCI bridge
+serial@<addr>  fsl,mpc5200-psc-uart     PSC in serial mode
+i2s@<addr>     fsl,mpc5200-psc-i2s      PSC in i2s mode
+ac97@<addr>    fsl,mpc5200-psc-ac97     PSC in ac97 mode
+spi@<addr>     fsl,mpc5200-psc-spi      PSC in spi mode
+irda@<addr>    fsl,mpc5200-psc-irda     PSC in IrDA mode
+spi@<addr>     fsl,mpc5200-spi          MPC5200 spi device
+ethernet@<addr>        fsl,mpc5200-fec          MPC5200 ethernet device
+ata@<addr>     fsl,mpc5200-ata          IDE ATA interface
+i2c@<addr>     fsl,mpc5200-i2c          I2C controller
+usb@<addr>     fsl,mpc5200-ohci,ohci-be USB controller
+xlb@<addr>     fsl,mpc5200-xlb          XLB arbitrator
+
+fsl,mpc5200-gpt nodes
+---------------------
+On the mpc5200 and 5200b, GPT0 has a watchdog timer function.  If the board
+design supports the internal wdt, then the device node for GPT0 should
+include the empty property 'fsl,has-wdt'.  Note that this does not activate
+the watchdog.  The timer will function as a GPT if the timer api is used, and
+it will function as watchdog if the watchdog device is used.  The watchdog
+mode has priority over the gpt mode, i.e. if the watchdog is activated, any
+gpt api call to this timer will fail with -EBUSY.
+
+If you add the property
+       fsl,wdt-on-boot = <n>;
+GPT0 will be marked as in-use watchdog, i.e. blocking every gpt access to it.
+If n>0, the watchdog is started with a timeout of n seconds.  If n=0, the
+configuration of the watchdog is not touched.  This is useful in two cases:
+- just mark GPT0 as watchdog, blocking gpt accesses, and configure it later;
+- do not touch a configuration assigned by the boot loader which supervises
+  the boot process itself.
+
+The watchdog will respect the CONFIG_WATCHDOG_NOWAYOUT option.
+
+An mpc5200-gpt can be used as a single line GPIO controller.  To do so,
+add the following properties to the gpt node:
+       gpio-controller;
+       #gpio-cells = <2>;
+When referencing the GPIO line from another node, the first cell must always
+be zero and the second cell represents the gpio flags and described in the
+gpio device tree binding.
+
+An mpc5200-gpt can be used as a single line edge sensitive interrupt
+controller.  To do so, add the following properties to the gpt node:
+       interrupt-controller;
+       #interrupt-cells = <1>;
+When referencing the IRQ line from another node, the cell represents the
+sense mode; 1 for edge rising, 2 for edge falling.
+
+fsl,mpc5200-psc nodes
+---------------------
+The PSCs should include a cell-index which is the index of the PSC in
+hardware.  cell-index is used to determine which shared SoC registers to
+use when setting up PSC clocking.  cell-index number starts at '0'.  ie:
+       PSC1 has 'cell-index = <0>'
+       PSC4 has 'cell-index = <3>'
+
+PSC in i2s mode:  The mpc5200 and mpc5200b PSCs are not compatible when in
+i2s mode.  An 'mpc5200b-psc-i2s' node cannot include 'mpc5200-psc-i2s' in the
+compatible field.
+
+
+fsl,mpc5200-gpio and fsl,mpc5200-gpio-wkup nodes
+------------------------------------------------
+Each GPIO controller node should have the empty property gpio-controller and
+#gpio-cells set to 2. First cell is the GPIO number which is interpreted
+according to the bit numbers in the GPIO control registers. The second cell
+is for flags which is currently unused.
+
+fsl,mpc5200-fec nodes
+---------------------
+The FEC node can specify one of the following properties to configure
+the MII link:
+- fsl,7-wire-mode - An empty property that specifies the link uses 7-wire
+                    mode instead of MII
+- current-speed   - Specifies that the MII should be configured for a fixed
+                    speed.  This property should contain two cells.  The
+                    first cell specifies the speed in Mbps and the second
+                    should be '0' for half duplex and '1' for full duplex
+- phy-handle      - Contains a phandle to an Ethernet PHY.
+
+Interrupt controller (fsl,mpc5200-pic) node
+-------------------------------------------
+The mpc5200 pic binding splits hardware IRQ numbers into two levels.  The
+split reflects the layout of the PIC hardware itself, which groups
+interrupts into one of three groups; CRIT, MAIN or PERP.  Also, the
+Bestcomm dma engine has it's own set of interrupt sources which are
+cascaded off of peripheral interrupt 0, which the driver interprets as a
+fourth group, SDMA.
+
+The interrupts property for device nodes using the mpc5200 pic consists
+of three cells; <L1 L2 level>
+
+    L1 := [CRIT=0, MAIN=1, PERP=2, SDMA=3]
+    L2 := interrupt number; directly mapped from the value in the
+          "ICTL PerStat, MainStat, CritStat Encoded Register"
+    level := [LEVEL_HIGH=0, EDGE_RISING=1, EDGE_FALLING=2, LEVEL_LOW=3]
+
+For external IRQs, use the following interrupt property values (how to
+specify external interrupts is a frequently asked question):
+External interrupts:
+       external irq0:  interrupts = <0 0 n>;
+       external irq1:  interrupts = <1 1 n>;
+       external irq2:  interrupts = <1 2 n>;
+       external irq3:  interrupts = <1 3 n>;
+'n' is sense (0: level high, 1: edge rising, 2: edge falling 3: level low)
+
+fsl,mpc5200-mscan nodes
+-----------------------
+See file can.txt in this directory.
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt
new file mode 100644 (file)
index 0000000..71e39cf
--- /dev/null
@@ -0,0 +1,42 @@
+* OpenPIC and its interrupt numbers on Freescale's e500/e600 cores
+
+The OpenPIC specification does not specify which interrupt source has to
+become which interrupt number. This is up to the software implementation
+of the interrupt controller. The only requirement is that every
+interrupt source has to have an unique interrupt number / vector number.
+To accomplish this the current implementation assigns the number zero to
+the first source, the number one to the second source and so on until
+all interrupt sources have their unique number.
+Usually the assigned vector number equals the interrupt number mentioned
+in the documentation for a given core / CPU. This is however not true
+for the e500 cores (MPC85XX CPUs) where the documentation distinguishes
+between internal and external interrupt sources and starts counting at
+zero for both of them.
+
+So what to write for external interrupt source X or internal interrupt
+source Y into the device tree? Here is an example:
+
+The memory map for the interrupt controller in the MPC8544[0] shows,
+that the first interrupt source starts at 0x5_0000 (PIC Register Address
+Map-Interrupt Source Configuration Registers). This source becomes the
+number zero therefore:
+ External interrupt 0 = interrupt number 0
+ External interrupt 1 = interrupt number 1
+ External interrupt 2 = interrupt number 2
+ ...
+Every interrupt number allocates 0x20 bytes register space. So to get
+its number it is sufficient to shift the lower 16bits to right by five.
+So for the external interrupt 10 we have:
+  0x0140 >> 5 = 10
+
+After the external sources, the internal sources follow. The in core I2C
+controller on the MPC8544 for instance has the internal source number
+27. Oo obtain its interrupt number we take the lower 16bits of its memory
+address (0x5_0560) and shift it right:
+ 0x0560 >> 5 = 43
+
+Therefore the I2C device node for the MPC8544 CPU has to have the
+interrupt number 43 specified in the device tree.
+
+[0] MPC8544E PowerQUICCTM III, Integrated Host Processor Family Reference Manual
+    MPC8544ERM Rev. 1 10/2007
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt b/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt
new file mode 100644 (file)
index 0000000..bcc30ba
--- /dev/null
@@ -0,0 +1,36 @@
+* Freescale MSI interrupt controller
+
+Required properties:
+- compatible : compatible list, contains 2 entries,
+  first is "fsl,CHIP-msi", where CHIP is the processor(mpc8610, mpc8572,
+  etc.) and the second is "fsl,mpic-msi" or "fsl,ipic-msi" depending on
+  the parent type.
+- reg : should contain the address and the length of the shared message
+  interrupt register set.
+- msi-available-ranges: use <start count> style section to define which
+  msi interrupt can be used in the 256 msi interrupts. This property is
+  optional, without this, all the 256 MSI interrupts can be used.
+- interrupts : each one of the interrupts here is one entry per 32 MSIs,
+  and routed to the host interrupt controller. the interrupts should
+  be set as edge sensitive.
+- interrupt-parent: the phandle for the interrupt controller
+  that services interrupts for this device. for 83xx cpu, the interrupts
+  are routed to IPIC, and for 85xx/86xx cpu the interrupts are routed
+  to MPIC.
+
+Example:
+       msi@41600 {
+               compatible = "fsl,mpc8610-msi", "fsl,mpic-msi";
+               reg = <0x41600 0x80>;
+               msi-available-ranges = <0 0x100>;
+               interrupts = <
+                       0xe0 0
+                       0xe1 0
+                       0xe2 0
+                       0xe3 0
+                       0xe4 0
+                       0xe5 0
+                       0xe6 0
+                       0xe7 0>;
+               interrupt-parent = <&mpic>;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/pmc.txt b/Documentation/devicetree/bindings/powerpc/fsl/pmc.txt
new file mode 100644 (file)
index 0000000..07256b7
--- /dev/null
@@ -0,0 +1,63 @@
+* Power Management Controller
+
+Properties:
+- compatible: "fsl,<chip>-pmc".
+
+  "fsl,mpc8349-pmc" should be listed for any chip whose PMC is
+  compatible.  "fsl,mpc8313-pmc" should also be listed for any chip
+  whose PMC is compatible, and implies deep-sleep capability.
+
+  "fsl,mpc8548-pmc" should be listed for any chip whose PMC is
+  compatible.  "fsl,mpc8536-pmc" should also be listed for any chip
+  whose PMC is compatible, and implies deep-sleep capability.
+
+  "fsl,mpc8641d-pmc" should be listed for any chip whose PMC is
+  compatible; all statements below that apply to "fsl,mpc8548-pmc" also
+  apply to "fsl,mpc8641d-pmc".
+
+  Compatibility does not include bit assignments in SCCR/PMCDR/DEVDISR; these
+  bit assignments are indicated via the sleep specifier in each device's
+  sleep property.
+
+- reg: For devices compatible with "fsl,mpc8349-pmc", the first resource
+  is the PMC block, and the second resource is the Clock Configuration
+  block.
+
+  For devices compatible with "fsl,mpc8548-pmc", the first resource
+  is a 32-byte block beginning with DEVDISR.
+
+- interrupts: For "fsl,mpc8349-pmc"-compatible devices, the first
+  resource is the PMC block interrupt.
+
+- fsl,mpc8313-wakeup-timer: For "fsl,mpc8313-pmc"-compatible devices,
+  this is a phandle to an "fsl,gtm" node on which timer 4 can be used as
+  a wakeup source from deep sleep.
+
+Sleep specifiers:
+
+  fsl,mpc8349-pmc: Sleep specifiers consist of one cell.  For each bit
+  that is set in the cell, the corresponding bit in SCCR will be saved
+  and cleared on suspend, and restored on resume.  This sleep controller
+  supports disabling and resuming devices at any time.
+
+  fsl,mpc8536-pmc: Sleep specifiers consist of three cells, the third of
+  which will be ORed into PMCDR upon suspend, and cleared from PMCDR
+  upon resume.  The first two cells are as described for fsl,mpc8578-pmc.
+  This sleep controller only supports disabling devices during system
+  sleep, or permanently.
+
+  fsl,mpc8548-pmc: Sleep specifiers consist of one or two cells, the
+  first of which will be ORed into DEVDISR (and the second into
+  DEVDISR2, if present -- this cell should be zero or absent if the
+  hardware does not have DEVDISR2) upon a request for permanent device
+  disabling.  This sleep controller does not support configuring devices
+  to disable during system sleep (unless supported by another compatible
+  match), or dynamically.
+
+Example:
+
+       power@b00 {
+               compatible = "fsl,mpc8313-pmc", "fsl,mpc8349-pmc";
+               reg = <0xb00 0x100 0xa00 0x100>;
+               interrupts = <80 8>;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/sec.txt b/Documentation/devicetree/bindings/powerpc/fsl/sec.txt
new file mode 100644 (file)
index 0000000..2b6f2d4
--- /dev/null
@@ -0,0 +1,68 @@
+Freescale SoC SEC Security Engines
+
+Required properties:
+
+- compatible : Should contain entries for this and backward compatible
+  SEC versions, high to low, e.g., "fsl,sec2.1", "fsl,sec2.0"
+- reg : Offset and length of the register set for the device
+- interrupts : the SEC's interrupt number
+- fsl,num-channels : An integer representing the number of channels
+  available.
+- fsl,channel-fifo-len : An integer representing the number of
+  descriptor pointers each channel fetch fifo can hold.
+- fsl,exec-units-mask : The bitmask representing what execution units
+  (EUs) are available. It's a single 32-bit cell. EU information
+  should be encoded following the SEC's Descriptor Header Dword
+  EU_SEL0 field documentation, i.e. as follows:
+
+       bit 0  = reserved - should be 0
+       bit 1  = set if SEC has the ARC4 EU (AFEU)
+       bit 2  = set if SEC has the DES/3DES EU (DEU)
+       bit 3  = set if SEC has the message digest EU (MDEU/MDEU-A)
+       bit 4  = set if SEC has the random number generator EU (RNG)
+       bit 5  = set if SEC has the public key EU (PKEU)
+       bit 6  = set if SEC has the AES EU (AESU)
+       bit 7  = set if SEC has the Kasumi EU (KEU)
+       bit 8  = set if SEC has the CRC EU (CRCU)
+       bit 11 = set if SEC has the message digest EU extended alg set (MDEU-B)
+
+remaining bits are reserved for future SEC EUs.
+
+- fsl,descriptor-types-mask : The bitmask representing what descriptors
+  are available. It's a single 32-bit cell. Descriptor type information
+  should be encoded following the SEC's Descriptor Header Dword DESC_TYPE
+  field documentation, i.e. as follows:
+
+       bit 0  = set if SEC supports the aesu_ctr_nonsnoop desc. type
+       bit 1  = set if SEC supports the ipsec_esp descriptor type
+       bit 2  = set if SEC supports the common_nonsnoop desc. type
+       bit 3  = set if SEC supports the 802.11i AES ccmp desc. type
+       bit 4  = set if SEC supports the hmac_snoop_no_afeu desc. type
+       bit 5  = set if SEC supports the srtp descriptor type
+       bit 6  = set if SEC supports the non_hmac_snoop_no_afeu desc.type
+       bit 7  = set if SEC supports the pkeu_assemble descriptor type
+       bit 8  = set if SEC supports the aesu_key_expand_output desc.type
+       bit 9  = set if SEC supports the pkeu_ptmul descriptor type
+       bit 10 = set if SEC supports the common_nonsnoop_afeu desc. type
+       bit 11 = set if SEC supports the pkeu_ptadd_dbl descriptor type
+
+  ..and so on and so forth.
+
+Optional properties:
+
+- interrupt-parent : the phandle for the interrupt controller that
+  services interrupts for this device.
+
+Example:
+
+       /* MPC8548E */
+       crypto@30000 {
+               compatible = "fsl,sec2.1", "fsl,sec2.0";
+               reg = <0x30000 0x10000>;
+               interrupts = <29 2>;
+               interrupt-parent = <&mpic>;
+               fsl,num-channels = <4>;
+               fsl,channel-fifo-len = <24>;
+               fsl,exec-units-mask = <0xfe>;
+               fsl,descriptor-types-mask = <0x12b0ebf>;
+       };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/ssi.txt b/Documentation/devicetree/bindings/powerpc/fsl/ssi.txt
new file mode 100644 (file)
index 0000000..5ff76c9
--- /dev/null
@@ -0,0 +1,73 @@
+Freescale Synchronous Serial Interface
+
+The SSI is a serial device that communicates with audio codecs.  It can
+be programmed in AC97, I2S, left-justified, or right-justified modes.
+
+Required properties:
+- compatible:       Compatible list, contains "fsl,ssi".
+- cell-index:       The SSI, <0> = SSI1, <1> = SSI2, and so on.
+- reg:              Offset and length of the register set for the device.
+- interrupts:       <a b> where a is the interrupt number and b is a
+                    field that represents an encoding of the sense and
+                    level information for the interrupt.  This should be
+                    encoded based on the information in section 2)
+                    depending on the type of interrupt controller you
+                    have.
+- interrupt-parent: The phandle for the interrupt controller that
+                    services interrupts for this device.
+- fsl,mode:         The operating mode for the SSI interface.
+                    "i2s-slave" - I2S mode, SSI is clock slave
+                    "i2s-master" - I2S mode, SSI is clock master
+                    "lj-slave" - left-justified mode, SSI is clock slave
+                    "lj-master" - l.j. mode, SSI is clock master
+                    "rj-slave" - right-justified mode, SSI is clock slave
+                    "rj-master" - r.j., SSI is clock master
+                    "ac97-slave" - AC97 mode, SSI is clock slave
+                    "ac97-master" - AC97 mode, SSI is clock master
+- fsl,playback-dma: Phandle to a node for the DMA channel to use for
+                    playback of audio.  This is typically dictated by SOC
+                    design.  See the notes below.
+- fsl,capture-dma:  Phandle to a node for the DMA channel to use for
+                    capture (recording) of audio.  This is typically dictated
+                    by SOC design.  See the notes below.
+- fsl,fifo-depth:   The number of elements in the transmit and receive FIFOs.
+                    This number is the maximum allowed value for SFCSR[TFWM0].
+- fsl,ssi-asynchronous:
+                    If specified, the SSI is to be programmed in asynchronous
+                    mode.  In this mode, pins SRCK, STCK, SRFS, and STFS must
+                    all be connected to valid signals.  In synchronous mode,
+                    SRCK and SRFS are ignored.  Asynchronous mode allows
+                    playback and capture to use different sample sizes and
+                    sample rates.  Some drivers may require that SRCK and STCK
+                    be connected together, and SRFS and STFS be connected
+                    together.  This would still allow different sample sizes,
+                    but not different sample rates.
+
+Optional properties:
+- codec-handle:     Phandle to a 'codec' node that defines an audio
+                    codec connected to this SSI.  This node is typically
+                    a child of an I2C or other control node.
+
+Child 'codec' node required properties:
+- compatible:       Compatible list, contains the name of the codec
+
+Child 'codec' node optional properties:
+- clock-frequency:  The frequency of the input clock, which typically comes
+                    from an on-board dedicated oscillator.
+
+Notes on fsl,playback-dma and fsl,capture-dma:
+
+On SOCs that have an SSI, specific DMA channels are hard-wired for playback
+and capture.  On the MPC8610, for example, SSI1 must use DMA channel 0 for
+playback and DMA channel 1 for capture.  SSI2 must use DMA channel 2 for
+playback and DMA channel 3 for capture.  The developer can choose which
+DMA controller to use, but the channels themselves are hard-wired.  The
+purpose of these two properties is to represent this hardware design.
+
+The device tree nodes for the DMA channels that are referenced by
+"fsl,playback-dma" and "fsl,capture-dma" must be marked as compatible with
+"fsl,ssi-dma-channel".  The SOC-specific compatible string (e.g.
+"fsl,mpc8610-dma-channel") can remain.  If these nodes are left as
+"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel", then the generic Elo DMA
+drivers (fsldma) will attempt to use them, and it will conflict with the
+sound drivers.
diff --git a/Documentation/devicetree/bindings/powerpc/nintendo/gamecube.txt b/Documentation/devicetree/bindings/powerpc/nintendo/gamecube.txt
new file mode 100644 (file)
index 0000000..b558585
--- /dev/null
@@ -0,0 +1,109 @@
+
+Nintendo GameCube device tree
+=============================
+
+1) The "flipper" node
+
+  This node represents the multi-function "Flipper" chip, which packages
+  many of the devices found in the Nintendo GameCube.
+
+  Required properties:
+
+   - compatible : Should be "nintendo,flipper"
+
+1.a) The Video Interface (VI) node
+
+  Represents the interface between the graphics processor and a external
+  video encoder.
+
+  Required properties:
+
+   - compatible : should be "nintendo,flipper-vi"
+   - reg : should contain the VI registers location and length
+   - interrupts : should contain the VI interrupt
+
+1.b) The Processor Interface (PI) node
+
+  Represents the data and control interface between the main processor
+  and graphics and audio processor.
+
+  Required properties:
+
+  - compatible : should be "nintendo,flipper-pi"
+  - reg : should contain the PI registers location and length
+
+1.b.i) The "Flipper" interrupt controller node
+
+  Represents the interrupt controller within the "Flipper" chip.
+  The node for the "Flipper" interrupt controller must be placed under
+  the PI node.
+
+  Required properties:
+
+  - compatible : should be "nintendo,flipper-pic"
+
+1.c) The Digital Signal Procesor (DSP) node
+
+  Represents the digital signal processor interface, designed to offload
+  audio related tasks.
+
+  Required properties:
+
+   - compatible : should be "nintendo,flipper-dsp"
+   - reg : should contain the DSP registers location and length
+   - interrupts : should contain the DSP interrupt
+
+1.c.i) The Auxiliary RAM (ARAM) node
+
+  Represents the non cpu-addressable ram designed mainly to store audio
+  related information.
+  The ARAM node must be placed under the DSP node.
+
+  Required properties:
+
+   - compatible : should be "nintendo,flipper-aram"
+   - reg : should contain the ARAM start (zero-based) and length
+
+1.d) The Disk Interface (DI) node
+
+  Represents the interface used to communicate with mass storage devices.
+
+  Required properties:
+
+   - compatible : should be "nintendo,flipper-di"
+   - reg : should contain the DI registers location and length
+   - interrupts : should contain the DI interrupt
+
+1.e) The Audio Interface (AI) node
+
+  Represents the interface to the external 16-bit stereo digital-to-analog
+  converter.
+
+  Required properties:
+
+   - compatible : should be "nintendo,flipper-ai"
+   - reg : should contain the AI registers location and length
+   - interrupts : should contain the AI interrupt
+
+1.f) The Serial Interface (SI) node
+
+  Represents the interface to the four single bit serial interfaces.
+  The SI is a proprietary serial interface used normally to control gamepads.
+  It's NOT a RS232-type interface.
+
+  Required properties:
+
+   - compatible : should be "nintendo,flipper-si"
+   - reg : should contain the SI registers location and length
+   - interrupts : should contain the SI interrupt
+
+1.g) The External Interface (EXI) node
+
+  Represents the multi-channel SPI-like interface.
+
+  Required properties:
+
+   - compatible : should be "nintendo,flipper-exi"
+   - reg : should contain the EXI registers location and length
+   - interrupts : should contain the EXI interrupt
+
diff --git a/Documentation/devicetree/bindings/powerpc/nintendo/wii.txt b/Documentation/devicetree/bindings/powerpc/nintendo/wii.txt
new file mode 100644 (file)
index 0000000..a7e155a
--- /dev/null
@@ -0,0 +1,184 @@
+
+Nintendo Wii device tree
+========================
+
+0) The root node
+
+  This node represents the Nintendo Wii video game console.
+
+  Required properties:
+
+   - model : Should be "nintendo,wii"
+   - compatible : Should be "nintendo,wii"
+
+1) The "hollywood" node
+
+  This node represents the multi-function "Hollywood" chip, which packages
+  many of the devices found in the Nintendo Wii.
+
+  Required properties:
+
+   - compatible : Should be "nintendo,hollywood"
+
+1.a) The Video Interface (VI) node
+
+  Represents the interface between the graphics processor and a external
+  video encoder.
+
+  Required properties:
+
+   - compatible : should be "nintendo,hollywood-vi","nintendo,flipper-vi"
+   - reg : should contain the VI registers location and length
+   - interrupts : should contain the VI interrupt
+
+1.b) The Processor Interface (PI) node
+
+  Represents the data and control interface between the main processor
+  and graphics and audio processor.
+
+  Required properties:
+
+  - compatible : should be "nintendo,hollywood-pi","nintendo,flipper-pi"
+  - reg : should contain the PI registers location and length
+
+1.b.i) The "Flipper" interrupt controller node
+
+  Represents the "Flipper" interrupt controller within the "Hollywood" chip.
+  The node for the "Flipper" interrupt controller must be placed under
+  the PI node.
+
+  Required properties:
+
+  - #interrupt-cells : <1>
+  - compatible : should be "nintendo,flipper-pic"
+  - interrupt-controller
+
+1.c) The Digital Signal Procesor (DSP) node
+
+  Represents the digital signal processor interface, designed to offload
+  audio related tasks.
+
+  Required properties:
+
+   - compatible : should be "nintendo,hollywood-dsp","nintendo,flipper-dsp"
+   - reg : should contain the DSP registers location and length
+   - interrupts : should contain the DSP interrupt
+
+1.d) The Serial Interface (SI) node
+
+  Represents the interface to the four single bit serial interfaces.
+  The SI is a proprietary serial interface used normally to control gamepads.
+  It's NOT a RS232-type interface.
+
+  Required properties:
+
+   - compatible : should be "nintendo,hollywood-si","nintendo,flipper-si"
+   - reg : should contain the SI registers location and length
+   - interrupts : should contain the SI interrupt
+
+1.e) The Audio Interface (AI) node
+
+  Represents the interface to the external 16-bit stereo digital-to-analog
+  converter.
+
+  Required properties:
+
+   - compatible : should be "nintendo,hollywood-ai","nintendo,flipper-ai"
+   - reg : should contain the AI registers location and length
+   - interrupts : should contain the AI interrupt
+
+1.f) The External Interface (EXI) node
+
+  Represents the multi-channel SPI-like interface.
+
+  Required properties:
+
+   - compatible : should be "nintendo,hollywood-exi","nintendo,flipper-exi"
+   - reg : should contain the EXI registers location and length
+   - interrupts : should contain the EXI interrupt
+
+1.g) The Open Host Controller Interface (OHCI) nodes
+
+  Represent the USB 1.x Open Host Controller Interfaces.
+
+  Required properties:
+
+   - compatible : should be "nintendo,hollywood-usb-ohci","usb-ohci"
+   - reg : should contain the OHCI registers location and length
+   - interrupts : should contain the OHCI interrupt
+
+1.h) The Enhanced Host Controller Interface (EHCI) node
+
+  Represents the USB 2.0 Enhanced Host Controller Interface.
+
+  Required properties:
+
+   - compatible : should be "nintendo,hollywood-usb-ehci","usb-ehci"
+   - reg : should contain the EHCI registers location and length
+   - interrupts : should contain the EHCI interrupt
+
+1.i) The Secure Digital Host Controller Interface (SDHCI) nodes
+
+  Represent the Secure Digital Host Controller Interfaces.
+
+  Required properties:
+
+   - compatible : should be "nintendo,hollywood-sdhci","sdhci"
+   - reg : should contain the SDHCI registers location and length
+   - interrupts : should contain the SDHCI interrupt
+
+1.j) The Inter-Processsor Communication (IPC) node
+
+  Represent the Inter-Processor Communication interface. This interface
+  enables communications between the Broadway and the Starlet processors.
+
+   - compatible : should be "nintendo,hollywood-ipc"
+   - reg : should contain the IPC registers location and length
+   - interrupts : should contain the IPC interrupt
+
+1.k) The "Hollywood" interrupt controller node
+
+  Represents the "Hollywood" interrupt controller within the
+  "Hollywood" chip.
+
+  Required properties:
+
+  - #interrupt-cells : <1>
+  - compatible : should be "nintendo,hollywood-pic"
+  - reg : should contain the controller registers location and length
+  - interrupt-controller
+  - interrupts : should contain the cascade interrupt of the "flipper" pic
+  - interrupt-parent: should contain the phandle of the "flipper" pic
+
+1.l) The General Purpose I/O (GPIO) controller node
+
+  Represents the dual access 32 GPIO controller interface.
+
+  Required properties:
+
+  - #gpio-cells : <2>
+  - compatible : should be "nintendo,hollywood-gpio"
+  - reg : should contain the IPC registers location and length
+  - gpio-controller
+
+1.m) The control node
+
+  Represents the control interface used to setup several miscellaneous
+  settings of the "Hollywood" chip like boot memory mappings, resets,
+  disk interface mode, etc.
+
+  Required properties:
+
+   - compatible : should be "nintendo,hollywood-control"
+   - reg : should contain the control registers location and length
+
+1.n) The Disk Interface (DI) node
+
+  Represents the interface used to communicate with mass storage devices.
+
+  Required properties:
+
+   - compatible : should be "nintendo,hollywood-di"
+   - reg : should contain the DI registers location and length
+   - interrupts : should contain the DI interrupt
+
diff --git a/Documentation/devicetree/bindings/rtc/rtc-cmos.txt b/Documentation/devicetree/bindings/rtc/rtc-cmos.txt
new file mode 100644 (file)
index 0000000..7382989
--- /dev/null
@@ -0,0 +1,28 @@
+ Motorola mc146818 compatible RTC
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Required properties:
+  - compatible : "motorola,mc146818"
+  - reg : should contain registers location and length.
+
+Optional properties:
+  - interrupts : should contain interrupt.
+  - interrupt-parent : interrupt source phandle.
+  - ctrl-reg : Contains the initial value of the control register also
+    called "Register B".
+  - freq-reg : Contains the initial value of the frequency register also
+    called "Regsiter A".
+
+"Register A" and "B" are usually initialized by the firmware (BIOS for
+instance). If this is not done, it can be performed by the driver.
+
+ISA Example:
+
+       rtc@70 {
+                compatible = "motorola,mc146818";
+                interrupts = <8 3>;
+                interrupt-parent = <&ioapic1>;
+                ctrl-reg = <2>;
+                freq-reg = <0x26>;
+                reg = <1 0x70 2>;
+        };
diff --git a/Documentation/devicetree/bindings/spi/fsl-spi.txt b/Documentation/devicetree/bindings/spi/fsl-spi.txt
new file mode 100644 (file)
index 0000000..777abd7
--- /dev/null
@@ -0,0 +1,53 @@
+* SPI (Serial Peripheral Interface)
+
+Required properties:
+- cell-index : QE SPI subblock index.
+               0: QE subblock SPI1
+               1: QE subblock SPI2
+- compatible : should be "fsl,spi".
+- mode : the SPI operation mode, it can be "cpu" or "cpu-qe".
+- reg : Offset and length of the register set for the device
+- interrupts : <a b> where a is the interrupt number and b is a
+  field that represents an encoding of the sense and level
+  information for the interrupt.  This should be encoded based on
+  the information in section 2) depending on the type of interrupt
+  controller you have.
+- interrupt-parent : the phandle for the interrupt controller that
+  services interrupts for this device.
+
+Optional properties:
+- gpios : specifies the gpio pins to be used for chipselects.
+  The gpios will be referred to as reg = <index> in the SPI child nodes.
+  If unspecified, a single SPI device without a chip select can be used.
+
+Example:
+       spi@4c0 {
+               cell-index = <0>;
+               compatible = "fsl,spi";
+               reg = <4c0 40>;
+               interrupts = <82 0>;
+               interrupt-parent = <700>;
+               mode = "cpu";
+               gpios = <&gpio 18 1     // device reg=<0>
+                        &gpio 19 1>;   // device reg=<1>
+       };
+
+
+* eSPI (Enhanced Serial Peripheral Interface)
+
+Required properties:
+- compatible : should be "fsl,mpc8536-espi".
+- reg : Offset and length of the register set for the device.
+- interrupts : should contain eSPI interrupt, the device has one interrupt.
+- fsl,espi-num-chipselects : the number of the chipselect signals.
+
+Example:
+       spi@110000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "fsl,mpc8536-espi";
+               reg = <0x110000 0x1000>;
+               interrupts = <53 0x2>;
+               interrupt-parent = <&mpic>;
+               fsl,espi-num-chipselects = <4>;
+       };
diff --git a/Documentation/devicetree/bindings/spi/spi-bus.txt b/Documentation/devicetree/bindings/spi/spi-bus.txt
new file mode 100644 (file)
index 0000000..e782add
--- /dev/null
@@ -0,0 +1,57 @@
+SPI (Serial Peripheral Interface) busses
+
+SPI busses can be described with a node for the SPI master device
+and a set of child nodes for each SPI slave on the bus.  For this
+discussion, it is assumed that the system's SPI controller is in
+SPI master mode.  This binding does not describe SPI controllers
+in slave mode.
+
+The SPI master node requires the following properties:
+- #address-cells  - number of cells required to define a chip select
+               address on the SPI bus.
+- #size-cells     - should be zero.
+- compatible      - name of SPI bus controller following generic names
+               recommended practice.
+No other properties are required in the SPI bus node.  It is assumed
+that a driver for an SPI bus device will understand that it is an SPI bus.
+However, the binding does not attempt to define the specific method for
+assigning chip select numbers.  Since SPI chip select configuration is
+flexible and non-standardized, it is left out of this binding with the
+assumption that board specific platform code will be used to manage
+chip selects.  Individual drivers can define additional properties to
+support describing the chip select layout.
+
+SPI slave nodes must be children of the SPI master node and can
+contain the following properties.
+- reg             - (required) chip select address of device.
+- compatible      - (required) name of SPI device following generic names
+               recommended practice
+- spi-max-frequency - (required) Maximum SPI clocking speed of device in Hz
+- spi-cpol        - (optional) Empty property indicating device requires
+               inverse clock polarity (CPOL) mode
+- spi-cpha        - (optional) Empty property indicating device requires
+               shifted clock phase (CPHA) mode
+- spi-cs-high     - (optional) Empty property indicating device requires
+               chip select active high
+
+SPI example for an MPC5200 SPI bus:
+       spi@f00 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
+               reg = <0xf00 0x20>;
+               interrupts = <2 13 0 2 14 0>;
+               interrupt-parent = <&mpc5200_pic>;
+
+               ethernet-switch@0 {
+                       compatible = "micrel,ks8995m";
+                       spi-max-frequency = <1000000>;
+                       reg = <0>;
+               };
+
+               codec@1 {
+                       compatible = "ti,tlv320aic26";
+                       spi-max-frequency = <100000>;
+                       reg = <1>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/usb/fsl-usb.txt b/Documentation/devicetree/bindings/usb/fsl-usb.txt
new file mode 100644 (file)
index 0000000..bd5723f
--- /dev/null
@@ -0,0 +1,81 @@
+Freescale SOC USB controllers
+
+The device node for a USB controller that is part of a Freescale
+SOC is as described in the document "Open Firmware Recommended
+Practice : Universal Serial Bus" with the following modifications
+and additions :
+
+Required properties :
+ - compatible : Should be "fsl-usb2-mph" for multi port host USB
+   controllers, or "fsl-usb2-dr" for dual role USB controllers
+   or "fsl,mpc5121-usb2-dr" for dual role USB controllers of MPC5121
+ - phy_type : For multi port host USB controllers, should be one of
+   "ulpi", or "serial". For dual role USB controllers, should be
+   one of "ulpi", "utmi", "utmi_wide", or "serial".
+ - reg : Offset and length of the register set for the device
+ - port0 : boolean; if defined, indicates port0 is connected for
+   fsl-usb2-mph compatible controllers.  Either this property or
+   "port1" (or both) must be defined for "fsl-usb2-mph" compatible
+   controllers.
+ - port1 : boolean; if defined, indicates port1 is connected for
+   fsl-usb2-mph compatible controllers.  Either this property or
+   "port0" (or both) must be defined for "fsl-usb2-mph" compatible
+   controllers.
+ - dr_mode : indicates the working mode for "fsl-usb2-dr" compatible
+   controllers.  Can be "host", "peripheral", or "otg".  Default to
+   "host" if not defined for backward compatibility.
+
+Recommended properties :
+ - interrupts : <a b> where a is the interrupt number and b is a
+   field that represents an encoding of the sense and level
+   information for the interrupt.  This should be encoded based on
+   the information in section 2) depending on the type of interrupt
+   controller you have.
+ - interrupt-parent : the phandle for the interrupt controller that
+   services interrupts for this device.
+
+Optional properties :
+ - fsl,invert-drvvbus : boolean; for MPC5121 USB0 only. Indicates the
+   port power polarity of internal PHY signal DRVVBUS is inverted.
+ - fsl,invert-pwr-fault : boolean; for MPC5121 USB0 only. Indicates
+   the PWR_FAULT signal polarity is inverted.
+
+Example multi port host USB controller device node :
+       usb@22000 {
+               compatible = "fsl-usb2-mph";
+               reg = <22000 1000>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               interrupt-parent = <700>;
+               interrupts = <27 1>;
+               phy_type = "ulpi";
+               port0;
+               port1;
+       };
+
+Example dual role USB controller device node :
+       usb@23000 {
+               compatible = "fsl-usb2-dr";
+               reg = <23000 1000>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               interrupt-parent = <700>;
+               interrupts = <26 1>;
+               dr_mode = "otg";
+               phy = "ulpi";
+       };
+
+Example dual role USB controller device node for MPC5121ADS:
+
+       usb@4000 {
+               compatible = "fsl,mpc5121-usb2-dr";
+               reg = <0x4000 0x1000>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               interrupt-parent = < &ipic >;
+               interrupts = <44 0x8>;
+               dr_mode = "otg";
+               phy_type = "utmi_wide";
+               fsl,invert-drvvbus;
+               fsl,invert-pwr-fault;
+       };
diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt
new file mode 100644 (file)
index 0000000..fa18612
--- /dev/null
@@ -0,0 +1,25 @@
+USB EHCI controllers
+
+Required properties:
+  - compatible : should be "usb-ehci".
+  - reg : should contain at least address and length of the standard EHCI
+    register set for the device. Optional platform-dependent registers
+    (debug-port or other) can be also specified here, but only after
+    definition of standard EHCI registers.
+  - interrupts : one EHCI interrupt should be described here.
+If device registers are implemented in big endian mode, the device
+node should have "big-endian-regs" property.
+If controller implementation operates with big endian descriptors,
+"big-endian-desc" property should be specified.
+If both big endian registers and descriptors are used by the controller
+implementation, "big-endian" property can be specified instead of having
+both "big-endian-regs" and "big-endian-desc".
+
+Example (Sequoia 440EPx):
+    ehci@e0000300 {
+          compatible = "ibm,usb-ehci-440epx", "usb-ehci";
+          interrupt-parent = <&UIC0>;
+          interrupts = <1a 4>;
+          reg = <0 e0000300 90 0 e0000390 70>;
+          big-endian;
+   };
diff --git a/Documentation/devicetree/bindings/x86/ce4100.txt b/Documentation/devicetree/bindings/x86/ce4100.txt
new file mode 100644 (file)
index 0000000..b49ae59
--- /dev/null
@@ -0,0 +1,38 @@
+CE4100 Device Tree Bindings
+---------------------------
+
+The CE4100 SoC uses for in core peripherals the following compatible
+format: <vendor>,<chip>-<device>.
+Many of the "generic" devices like HPET or IO APIC have the ce4100
+name in their compatible property because they first appeared in this
+SoC.
+
+The CPU node
+------------
+       cpu@0 {
+               device_type = "cpu";
+               compatible = "intel,ce4100";
+               reg = <0>;
+               lapic = <&lapic0>;
+       };
+
+The reg property describes the CPU number. The lapic property points to
+the local APIC timer.
+
+The SoC node
+------------
+
+This node describes the in-core peripherals. Required property:
+  compatible = "intel,ce4100-cp";
+
+The PCI node
+------------
+This node describes the PCI bus on the SoC. Its property should be
+  compatible = "intel,ce4100-pci", "pci";
+
+If the OS is using the IO-APIC for interrupt routing then the reported
+interrupt numbers for devices is no longer true. In order to obtain the
+correct interrupt number, the child node which represents the device has
+to contain the interrupt property. Besides the interrupt property it has
+to contain at least the reg property containing the PCI bus address and
+compatible property according to "PCI Bus Binding Revision 2.1".
diff --git a/Documentation/devicetree/bindings/x86/interrupt.txt b/Documentation/devicetree/bindings/x86/interrupt.txt
new file mode 100644 (file)
index 0000000..7d19f49
--- /dev/null
@@ -0,0 +1,26 @@
+Interrupt chips
+---------------
+
+* Intel I/O Advanced Programmable Interrupt Controller (IO APIC)
+
+  Required properties:
+  --------------------
+     compatible = "intel,ce4100-ioapic";
+     #interrupt-cells = <2>;
+
+  Device's interrupt property:
+
+     interrupts = <P S>;
+
+  The first number (P) represents the interrupt pin which is wired to the
+  IO APIC. The second number (S) represents the sense of interrupt which
+  should be configured and can be one of:
+    0 - Edge Rising
+    1 - Level Low
+    2 - Level High
+    3 - Edge Falling
+
+* Local APIC
+  Required property:
+
+     compatible = "intel,ce4100-lapic";
diff --git a/Documentation/devicetree/bindings/x86/timer.txt b/Documentation/devicetree/bindings/x86/timer.txt
new file mode 100644 (file)
index 0000000..c688af5
--- /dev/null
@@ -0,0 +1,6 @@
+Timers
+------
+
+* High Precision Event Timer (HPET)
+  Required property:
+     compatible = "intel,ce4100-hpet";
diff --git a/Documentation/devicetree/bindings/xilinx.txt b/Documentation/devicetree/bindings/xilinx.txt
new file mode 100644 (file)
index 0000000..299d092
--- /dev/null
@@ -0,0 +1,306 @@
+   d) Xilinx IP cores
+
+   The Xilinx EDK toolchain ships with a set of IP cores (devices) for use
+   in Xilinx Spartan and Virtex FPGAs.  The devices cover the whole range
+   of standard device types (network, serial, etc.) and miscellaneous
+   devices (gpio, LCD, spi, etc).  Also, since these devices are
+   implemented within the fpga fabric every instance of the device can be
+   synthesised with different options that change the behaviour.
+
+   Each IP-core has a set of parameters which the FPGA designer can use to
+   control how the core is synthesized.  Historically, the EDK tool would
+   extract the device parameters relevant to device drivers and copy them
+   into an 'xparameters.h' in the form of #define symbols.  This tells the
+   device drivers how the IP cores are configured, but it requires the kernel
+   to be recompiled every time the FPGA bitstream is resynthesized.
+
+   The new approach is to export the parameters into the device tree and
+   generate a new device tree each time the FPGA bitstream changes.  The
+   parameters which used to be exported as #defines will now become
+   properties of the device node.  In general, device nodes for IP-cores
+   will take the following form:
+
+       (name): (generic-name)@(base-address) {
+               compatible = "xlnx,(ip-core-name)-(HW_VER)"
+                            [, (list of compatible devices), ...];
+               reg = <(baseaddr) (size)>;
+               interrupt-parent = <&interrupt-controller-phandle>;
+               interrupts = < ... >;
+               xlnx,(parameter1) = "(string-value)";
+               xlnx,(parameter2) = <(int-value)>;
+       };
+
+       (generic-name):   an open firmware-style name that describes the
+                       generic class of device.  Preferably, this is one word, such
+                       as 'serial' or 'ethernet'.
+       (ip-core-name): the name of the ip block (given after the BEGIN
+                       directive in system.mhs).  Should be in lowercase
+                       and all underscores '_' converted to dashes '-'.
+       (name):         is derived from the "PARAMETER INSTANCE" value.
+       (parameter#):   C_* parameters from system.mhs.  The C_ prefix is
+                       dropped from the parameter name, the name is converted
+                       to lowercase and all underscore '_' characters are
+                       converted to dashes '-'.
+       (baseaddr):     the baseaddr parameter value (often named C_BASEADDR).
+       (HW_VER):       from the HW_VER parameter.
+       (size):         the address range size (often C_HIGHADDR - C_BASEADDR + 1).
+
+   Typically, the compatible list will include the exact IP core version
+   followed by an older IP core version which implements the same
+   interface or any other device with the same interface.
+
+   'reg', 'interrupt-parent' and 'interrupts' are all optional properties.
+
+   For example, the following block from system.mhs:
+
+       BEGIN opb_uartlite
+               PARAMETER INSTANCE = opb_uartlite_0
+               PARAMETER HW_VER = 1.00.b
+               PARAMETER C_BAUDRATE = 115200
+               PARAMETER C_DATA_BITS = 8
+               PARAMETER C_ODD_PARITY = 0
+               PARAMETER C_USE_PARITY = 0
+               PARAMETER C_CLK_FREQ = 50000000
+               PARAMETER C_BASEADDR = 0xEC100000
+               PARAMETER C_HIGHADDR = 0xEC10FFFF
+               BUS_INTERFACE SOPB = opb_7
+               PORT OPB_Clk = CLK_50MHz
+               PORT Interrupt = opb_uartlite_0_Interrupt
+               PORT RX = opb_uartlite_0_RX
+               PORT TX = opb_uartlite_0_TX
+               PORT OPB_Rst = sys_bus_reset_0
+       END
+
+   becomes the following device tree node:
+
+       opb_uartlite_0: serial@ec100000 {
+               device_type = "serial";
+               compatible = "xlnx,opb-uartlite-1.00.b";
+               reg = <ec100000 10000>;
+               interrupt-parent = <&opb_intc_0>;
+               interrupts = <1 0>; // got this from the opb_intc parameters
+               current-speed = <d#115200>;     // standard serial device prop
+               clock-frequency = <d#50000000>; // standard serial device prop
+               xlnx,data-bits = <8>;
+               xlnx,odd-parity = <0>;
+               xlnx,use-parity = <0>;
+       };
+
+   Some IP cores actually implement 2 or more logical devices.  In
+   this case, the device should still describe the whole IP core with
+   a single node and add a child node for each logical device.  The
+   ranges property can be used to translate from parent IP-core to the
+   registers of each device.  In addition, the parent node should be
+   compatible with the bus type 'xlnx,compound', and should contain
+   #address-cells and #size-cells, as with any other bus.  (Note: this
+   makes the assumption that both logical devices have the same bus
+   binding.  If this is not true, then separate nodes should be used
+   for each logical device).  The 'cell-index' property can be used to
+   enumerate logical devices within an IP core.  For example, the
+   following is the system.mhs entry for the dual ps2 controller found
+   on the ml403 reference design.
+
+       BEGIN opb_ps2_dual_ref
+               PARAMETER INSTANCE = opb_ps2_dual_ref_0
+               PARAMETER HW_VER = 1.00.a
+               PARAMETER C_BASEADDR = 0xA9000000
+               PARAMETER C_HIGHADDR = 0xA9001FFF
+               BUS_INTERFACE SOPB = opb_v20_0
+               PORT Sys_Intr1 = ps2_1_intr
+               PORT Sys_Intr2 = ps2_2_intr
+               PORT Clkin1 = ps2_clk_rx_1
+               PORT Clkin2 = ps2_clk_rx_2
+               PORT Clkpd1 = ps2_clk_tx_1
+               PORT Clkpd2 = ps2_clk_tx_2
+               PORT Rx1 = ps2_d_rx_1
+               PORT Rx2 = ps2_d_rx_2
+               PORT Txpd1 = ps2_d_tx_1
+               PORT Txpd2 = ps2_d_tx_2
+       END
+
+   It would result in the following device tree nodes:
+
+       opb_ps2_dual_ref_0: opb-ps2-dual-ref@a9000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "xlnx,compound";
+               ranges = <0 a9000000 2000>;
+               // If this device had extra parameters, then they would
+               // go here.
+               ps2@0 {
+                       compatible = "xlnx,opb-ps2-dual-ref-1.00.a";
+                       reg = <0 40>;
+                       interrupt-parent = <&opb_intc_0>;
+                       interrupts = <3 0>;
+                       cell-index = <0>;
+               };
+               ps2@1000 {
+                       compatible = "xlnx,opb-ps2-dual-ref-1.00.a";
+                       reg = <1000 40>;
+                       interrupt-parent = <&opb_intc_0>;
+                       interrupts = <3 0>;
+                       cell-index = <0>;
+               };
+       };
+
+   Also, the system.mhs file defines bus attachments from the processor
+   to the devices.  The device tree structure should reflect the bus
+   attachments.  Again an example; this system.mhs fragment:
+
+       BEGIN ppc405_virtex4
+               PARAMETER INSTANCE = ppc405_0
+               PARAMETER HW_VER = 1.01.a
+               BUS_INTERFACE DPLB = plb_v34_0
+               BUS_INTERFACE IPLB = plb_v34_0
+       END
+
+       BEGIN opb_intc
+               PARAMETER INSTANCE = opb_intc_0
+               PARAMETER HW_VER = 1.00.c
+               PARAMETER C_BASEADDR = 0xD1000FC0
+               PARAMETER C_HIGHADDR = 0xD1000FDF
+               BUS_INTERFACE SOPB = opb_v20_0
+       END
+
+       BEGIN opb_uart16550
+               PARAMETER INSTANCE = opb_uart16550_0
+               PARAMETER HW_VER = 1.00.d
+               PARAMETER C_BASEADDR = 0xa0000000
+               PARAMETER C_HIGHADDR = 0xa0001FFF
+               BUS_INTERFACE SOPB = opb_v20_0
+       END
+
+       BEGIN plb_v34
+               PARAMETER INSTANCE = plb_v34_0
+               PARAMETER HW_VER = 1.02.a
+       END
+
+       BEGIN plb_bram_if_cntlr
+               PARAMETER INSTANCE = plb_bram_if_cntlr_0
+               PARAMETER HW_VER = 1.00.b
+               PARAMETER C_BASEADDR = 0xFFFF0000
+               PARAMETER C_HIGHADDR = 0xFFFFFFFF
+               BUS_INTERFACE SPLB = plb_v34_0
+       END
+
+       BEGIN plb2opb_bridge
+               PARAMETER INSTANCE = plb2opb_bridge_0
+               PARAMETER HW_VER = 1.01.a
+               PARAMETER C_RNG0_BASEADDR = 0x20000000
+               PARAMETER C_RNG0_HIGHADDR = 0x3FFFFFFF
+               PARAMETER C_RNG1_BASEADDR = 0x60000000
+               PARAMETER C_RNG1_HIGHADDR = 0x7FFFFFFF
+               PARAMETER C_RNG2_BASEADDR = 0x80000000
+               PARAMETER C_RNG2_HIGHADDR = 0xBFFFFFFF
+               PARAMETER C_RNG3_BASEADDR = 0xC0000000
+               PARAMETER C_RNG3_HIGHADDR = 0xDFFFFFFF
+               BUS_INTERFACE SPLB = plb_v34_0
+               BUS_INTERFACE MOPB = opb_v20_0
+       END
+
+   Gives this device tree (some properties removed for clarity):
+
+       plb@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "xlnx,plb-v34-1.02.a";
+               device_type = "ibm,plb";
+               ranges; // 1:1 translation
+
+               plb_bram_if_cntrl_0: bram@ffff0000 {
+                       reg = <ffff0000 10000>;
+               }
+
+               opb@20000000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <20000000 20000000 20000000
+                                 60000000 60000000 20000000
+                                 80000000 80000000 40000000
+                                 c0000000 c0000000 20000000>;
+
+                       opb_uart16550_0: serial@a0000000 {
+                               reg = <a00000000 2000>;
+                       };
+
+                       opb_intc_0: interrupt-controller@d1000fc0 {
+                               reg = <d1000fc0 20>;
+                       };
+               };
+       };
+
+   That covers the general approach to binding xilinx IP cores into the
+   device tree.  The following are bindings for specific devices:
+
+      i) Xilinx ML300 Framebuffer
+
+      Simple framebuffer device from the ML300 reference design (also on the
+      ML403 reference design as well as others).
+
+      Optional properties:
+       - resolution = <xres yres> : pixel resolution of framebuffer.  Some
+                                    implementations use a different resolution.
+                                    Default is <d#640 d#480>
+       - virt-resolution = <xvirt yvirt> : Size of framebuffer in memory.
+                                           Default is <d#1024 d#480>.
+       - rotate-display (empty) : rotate display 180 degrees.
+
+      ii) Xilinx SystemACE
+
+      The Xilinx SystemACE device is used to program FPGAs from an FPGA
+      bitstream stored on a CF card.  It can also be used as a generic CF
+      interface device.
+
+      Optional properties:
+       - 8-bit (empty) : Set this property for SystemACE in 8 bit mode
+
+      iii) Xilinx EMAC and Xilinx TEMAC
+
+      Xilinx Ethernet devices.  In addition to general xilinx properties
+      listed above, nodes for these devices should include a phy-handle
+      property, and may include other common network device properties
+      like local-mac-address.
+
+      iv) Xilinx Uartlite
+
+      Xilinx uartlite devices are simple fixed speed serial ports.
+
+      Required properties:
+       - current-speed : Baud rate of uartlite
+
+      v) Xilinx hwicap
+
+               Xilinx hwicap devices provide access to the configuration logic
+               of the FPGA through the Internal Configuration Access Port
+               (ICAP).  The ICAP enables partial reconfiguration of the FPGA,
+               readback of the configuration information, and some control over
+               'warm boots' of the FPGA fabric.
+
+               Required properties:
+               - xlnx,family : The family of the FPGA, necessary since the
+                      capabilities of the underlying ICAP hardware
+                      differ between different families.  May be
+                      'virtex2p', 'virtex4', or 'virtex5'.
+
+      vi) Xilinx Uart 16550
+
+      Xilinx UART 16550 devices are very similar to the NS16550 but with
+      different register spacing and an offset from the base address.
+
+      Required properties:
+       - clock-frequency : Frequency of the clock input
+       - reg-offset : A value of 3 is required
+       - reg-shift : A value of 2 is required
+
+      vii) Xilinx USB Host controller
+
+      The Xilinx USB host controller is EHCI compatible but with a different
+      base address for the EHCI registers, and it is always a big-endian
+      USB Host controller. The hardware can be configured as high speed only,
+      or high speed/full speed hybrid.
+
+      Required properties:
+      - xlnx,support-usb-fs: A value 0 means the core is built as high speed
+                             only. A value 1 means the core also supports
+                             full speed devices.
+
diff --git a/Documentation/devicetree/booting-without-of.txt b/Documentation/devicetree/booting-without-of.txt
new file mode 100644 (file)
index 0000000..55fd262
--- /dev/null
@@ -0,0 +1,1410 @@
+           Booting the Linux/ppc kernel without Open Firmware
+           --------------------------------------------------
+
+(c) 2005 Benjamin Herrenschmidt <benh at kernel.crashing.org>,
+    IBM Corp.
+(c) 2005 Becky Bruce <becky.bruce at freescale.com>,
+    Freescale Semiconductor, FSL SOC and 32-bit additions
+(c) 2006 MontaVista Software, Inc.
+    Flash chip node definition
+
+Table of Contents
+=================
+
+  I - Introduction
+    1) Entry point for arch/powerpc
+    2) Entry point for arch/x86
+
+  II - The DT block format
+    1) Header
+    2) Device tree generalities
+    3) Device tree "structure" block
+    4) Device tree "strings" block
+
+  III - Required content of the device tree
+    1) Note about cells and address representation
+    2) Note about "compatible" properties
+    3) Note about "name" properties
+    4) Note about node and property names and character set
+    5) Required nodes and properties
+      a) The root node
+      b) The /cpus node
+      c) The /cpus/* nodes
+      d) the /memory node(s)
+      e) The /chosen node
+      f) the /soc<SOCname> node
+
+  IV - "dtc", the device tree compiler
+
+  V - Recommendations for a bootloader
+
+  VI - System-on-a-chip devices and nodes
+    1) Defining child nodes of an SOC
+    2) Representing devices without a current OF specification
+
+  VII - Specifying interrupt information for devices
+    1) interrupts property
+    2) interrupt-parent property
+    3) OpenPIC Interrupt Controllers
+    4) ISA Interrupt Controllers
+
+  VIII - Specifying device power management information (sleep property)
+
+  Appendix A - Sample SOC node for MPC8540
+
+
+Revision Information
+====================
+
+   May 18, 2005: Rev 0.1 - Initial draft, no chapter III yet.
+
+   May 19, 2005: Rev 0.2 - Add chapter III and bits & pieces here or
+                           clarifies the fact that a lot of things are
+                           optional, the kernel only requires a very
+                           small device tree, though it is encouraged
+                           to provide an as complete one as possible.
+
+   May 24, 2005: Rev 0.3 - Precise that DT block has to be in RAM
+                        - Misc fixes
+                        - Define version 3 and new format version 16
+                          for the DT block (version 16 needs kernel
+                          patches, will be fwd separately).
+                          String block now has a size, and full path
+                          is replaced by unit name for more
+                          compactness.
+                          linux,phandle is made optional, only nodes
+                          that are referenced by other nodes need it.
+                          "name" property is now automatically
+                          deduced from the unit name
+
+   June 1, 2005: Rev 0.4 - Correct confusion between OF_DT_END and
+                           OF_DT_END_NODE in structure definition.
+                         - Change version 16 format to always align
+                           property data to 4 bytes. Since tokens are
+                           already aligned, that means no specific
+                           required alignment between property size
+                           and property data. The old style variable
+                           alignment would make it impossible to do
+                           "simple" insertion of properties using
+                           memmove (thanks Milton for
+                           noticing). Updated kernel patch as well
+                        - Correct a few more alignment constraints
+                        - Add a chapter about the device-tree
+                           compiler and the textural representation of
+                           the tree that can be "compiled" by dtc.
+
+   November 21, 2005: Rev 0.5
+                        - Additions/generalizations for 32-bit
+                        - Changed to reflect the new arch/powerpc
+                          structure
+                        - Added chapter VI
+
+
+ ToDo:
+       - Add some definitions of interrupt tree (simple/complex)
+       - Add some definitions for PCI host bridges
+       - Add some common address format examples
+       - Add definitions for standard properties and "compatible"
+         names for cells that are not already defined by the existing
+         OF spec.
+       - Compare FSL SOC use of PCI to standard and make sure no new
+         node definition required.
+       - Add more information about node definitions for SOC devices
+         that currently have no standard, like the FSL CPM.
+
+
+I - Introduction
+================
+
+During the development of the Linux/ppc64 kernel, and more
+specifically, the addition of new platform types outside of the old
+IBM pSeries/iSeries pair, it was decided to enforce some strict rules
+regarding the kernel entry and bootloader <-> kernel interfaces, in
+order to avoid the degeneration that had become the ppc32 kernel entry
+point and the way a new platform should be added to the kernel. The
+legacy iSeries platform breaks those rules as it predates this scheme,
+but no new board support will be accepted in the main tree that
+doesn't follow them properly.  In addition, since the advent of the
+arch/powerpc merged architecture for ppc32 and ppc64, new 32-bit
+platforms and 32-bit platforms which move into arch/powerpc will be
+required to use these rules as well.
+
+The main requirement that will be defined in more detail below is
+the presence of a device-tree whose format is defined after Open
+Firmware specification. However, in order to make life easier
+to embedded board vendors, the kernel doesn't require the device-tree
+to represent every device in the system and only requires some nodes
+and properties to be present. This will be described in detail in
+section III, but, for example, the kernel does not require you to
+create a node for every PCI device in the system. It is a requirement
+to have a node for PCI host bridges in order to provide interrupt
+routing informations and memory/IO ranges, among others. It is also
+recommended to define nodes for on chip devices and other buses that
+don't specifically fit in an existing OF specification. This creates a
+great flexibility in the way the kernel can then probe those and match
+drivers to device, without having to hard code all sorts of tables. It
+also makes it more flexible for board vendors to do minor hardware
+upgrades without significantly impacting the kernel code or cluttering
+it with special cases.
+
+
+1) Entry point for arch/powerpc
+-------------------------------
+
+   There is one single entry point to the kernel, at the start
+   of the kernel image. That entry point supports two calling
+   conventions:
+
+        a) Boot from Open Firmware. If your firmware is compatible
+        with Open Firmware (IEEE 1275) or provides an OF compatible
+        client interface API (support for "interpret" callback of
+        forth words isn't required), you can enter the kernel with:
+
+              r5 : OF callback pointer as defined by IEEE 1275
+              bindings to powerpc. Only the 32-bit client interface
+              is currently supported
+
+              r3, r4 : address & length of an initrd if any or 0
+
+              The MMU is either on or off; the kernel will run the
+              trampoline located in arch/powerpc/kernel/prom_init.c to
+              extract the device-tree and other information from open
+              firmware and build a flattened device-tree as described
+              in b). prom_init() will then re-enter the kernel using
+              the second method. This trampoline code runs in the
+              context of the firmware, which is supposed to handle all
+              exceptions during that time.
+
+        b) Direct entry with a flattened device-tree block. This entry
+        point is called by a) after the OF trampoline and can also be
+        called directly by a bootloader that does not support the Open
+        Firmware client interface. It is also used by "kexec" to
+        implement "hot" booting of a new kernel from a previous
+        running one. This method is what I will describe in more
+        details in this document, as method a) is simply standard Open
+        Firmware, and thus should be implemented according to the
+        various standard documents defining it and its binding to the
+        PowerPC platform. The entry point definition then becomes:
+
+                r3 : physical pointer to the device-tree block
+                (defined in chapter II) in RAM
+
+                r4 : physical pointer to the kernel itself. This is
+                used by the assembly code to properly disable the MMU
+                in case you are entering the kernel with MMU enabled
+                and a non-1:1 mapping.
+
+                r5 : NULL (as to differentiate with method a)
+
+        Note about SMP entry: Either your firmware puts your other
+        CPUs in some sleep loop or spin loop in ROM where you can get
+        them out via a soft reset or some other means, in which case
+        you don't need to care, or you'll have to enter the kernel
+        with all CPUs. The way to do that with method b) will be
+        described in a later revision of this document.
+
+   Board supports (platforms) are not exclusive config options. An
+   arbitrary set of board supports can be built in a single kernel
+   image. The kernel will "know" what set of functions to use for a
+   given platform based on the content of the device-tree. Thus, you
+   should:
+
+        a) add your platform support as a _boolean_ option in
+        arch/powerpc/Kconfig, following the example of PPC_PSERIES,
+        PPC_PMAC and PPC_MAPLE. The later is probably a good
+        example of a board support to start from.
+
+        b) create your main platform file as
+        "arch/powerpc/platforms/myplatform/myboard_setup.c" and add it
+        to the Makefile under the condition of your CONFIG_
+        option. This file will define a structure of type "ppc_md"
+        containing the various callbacks that the generic code will
+        use to get to your platform specific code
+
+  A kernel image may support multiple platforms, but only if the
+  platforms feature the same core architecture.  A single kernel build
+  cannot support both configurations with Book E and configurations
+  with classic Powerpc architectures.
+
+2) Entry point for arch/x86
+-------------------------------
+
+  There is one single 32bit entry point to the kernel at code32_start,
+  the decompressor (the real mode entry point goes to the same  32bit
+  entry point once it switched into protected mode). That entry point
+  supports one calling convention which is documented in
+  Documentation/x86/boot.txt
+  The physical pointer to the device-tree block (defined in chapter II)
+  is passed via setup_data which requires at least boot protocol 2.09.
+  The type filed is defined as
+
+  #define SETUP_DTB                      2
+
+  This device-tree is used as an extension to the "boot page". As such it
+  does not parse / consider data which is already covered by the boot
+  page. This includes memory size, reserved ranges, command line arguments
+  or initrd address. It simply holds information which can not be retrieved
+  otherwise like interrupt routing or a list of devices behind an I2C bus.
+
+II - The DT block format
+========================
+
+
+This chapter defines the actual format of the flattened device-tree
+passed to the kernel. The actual content of it and kernel requirements
+are described later. You can find example of code manipulating that
+format in various places, including arch/powerpc/kernel/prom_init.c
+which will generate a flattened device-tree from the Open Firmware
+representation, or the fs2dt utility which is part of the kexec tools
+which will generate one from a filesystem representation. It is
+expected that a bootloader like uboot provides a bit more support,
+that will be discussed later as well.
+
+Note: The block has to be in main memory. It has to be accessible in
+both real mode and virtual mode with no mapping other than main
+memory. If you are writing a simple flash bootloader, it should copy
+the block to RAM before passing it to the kernel.
+
+
+1) Header
+---------
+
+   The kernel is passed the physical address pointing to an area of memory
+   that is roughly described in include/linux/of_fdt.h by the structure
+   boot_param_header:
+
+struct boot_param_header {
+        u32     magic;                  /* magic word OF_DT_HEADER */
+        u32     totalsize;              /* total size of DT block */
+        u32     off_dt_struct;          /* offset to structure */
+        u32     off_dt_strings;         /* offset to strings */
+        u32     off_mem_rsvmap;         /* offset to memory reserve map
+                                           */
+        u32     version;                /* format version */
+        u32     last_comp_version;      /* last compatible version */
+
+        /* version 2 fields below */
+        u32     boot_cpuid_phys;        /* Which physical CPU id we're
+                                           booting on */
+        /* version 3 fields below */
+        u32     size_dt_strings;        /* size of the strings block */
+
+        /* version 17 fields below */
+        u32    size_dt_struct;         /* size of the DT structure block */
+};
+
+   Along with the constants:
+
+/* Definitions used by the flattened device tree */
+#define OF_DT_HEADER            0xd00dfeed      /* 4: version,
+                                                  4: total size */
+#define OF_DT_BEGIN_NODE        0x1             /* Start node: full name
+                                                  */
+#define OF_DT_END_NODE          0x2             /* End node */
+#define OF_DT_PROP              0x3             /* Property: name off,
+                                                   size, content */
+#define OF_DT_END               0x9
+
+   All values in this header are in big endian format, the various
+   fields in this header are defined more precisely below. All
+   "offset" values are in bytes from the start of the header; that is
+   from the physical base address of the device tree block.
+
+   - magic
+
+     This is a magic value that "marks" the beginning of the
+     device-tree block header. It contains the value 0xd00dfeed and is
+     defined by the constant OF_DT_HEADER
+
+   - totalsize
+
+     This is the total size of the DT block including the header. The
+     "DT" block should enclose all data structures defined in this
+     chapter (who are pointed to by offsets in this header). That is,
+     the device-tree structure, strings, and the memory reserve map.
+
+   - off_dt_struct
+
+     This is an offset from the beginning of the header to the start
+     of the "structure" part the device tree. (see 2) device tree)
+
+   - off_dt_strings
+
+     This is an offset from the beginning of the header to the start
+     of the "strings" part of the device-tree
+
+   - off_mem_rsvmap
+
+     This is an offset from the beginning of the header to the start
+     of the reserved memory map. This map is a list of pairs of 64-
+     bit integers. Each pair is a physical address and a size. The
+     list is terminated by an entry of size 0. This map provides the
+     kernel with a list of physical memory areas that are "reserved"
+     and thus not to be used for memory allocations, especially during
+     early initialization. The kernel needs to allocate memory during
+     boot for things like un-flattening the device-tree, allocating an
+     MMU hash table, etc... Those allocations must be done in such a
+     way to avoid overriding critical things like, on Open Firmware
+     capable machines, the RTAS instance, or on some pSeries, the TCE
+     tables used for the iommu. Typically, the reserve map should
+     contain _at least_ this DT block itself (header,total_size). If
+     you are passing an initrd to the kernel, you should reserve it as
+     well. You do not need to reserve the kernel image itself. The map
+     should be 64-bit aligned.
+
+   - version
+
+     This is the version of this structure. Version 1 stops
+     here. Version 2 adds an additional field boot_cpuid_phys.
+     Version 3 adds the size of the strings block, allowing the kernel
+     to reallocate it easily at boot and free up the unused flattened
+     structure after expansion. Version 16 introduces a new more
+     "compact" format for the tree itself that is however not backward
+     compatible. Version 17 adds an additional field, size_dt_struct,
+     allowing it to be reallocated or moved more easily (this is
+     particularly useful for bootloaders which need to make
+     adjustments to a device tree based on probed information). You
+     should always generate a structure of the highest version defined
+     at the time of your implementation. Currently that is version 17,
+     unless you explicitly aim at being backward compatible.
+
+   - last_comp_version
+
+     Last compatible version. This indicates down to what version of
+     the DT block you are backward compatible. For example, version 2
+     is backward compatible with version 1 (that is, a kernel build
+     for version 1 will be able to boot with a version 2 format). You
+     should put a 1 in this field if you generate a device tree of
+     version 1 to 3, or 16 if you generate a tree of version 16 or 17
+     using the new unit name format.
+
+   - boot_cpuid_phys
+
+     This field only exist on version 2 headers. It indicate which
+     physical CPU ID is calling the kernel entry point. This is used,
+     among others, by kexec. If you are on an SMP system, this value
+     should match the content of the "reg" property of the CPU node in
+     the device-tree corresponding to the CPU calling the kernel entry
+     point (see further chapters for more informations on the required
+     device-tree contents)
+
+   - size_dt_strings
+
+     This field only exists on version 3 and later headers.  It
+     gives the size of the "strings" section of the device tree (which
+     starts at the offset given by off_dt_strings).
+
+   - size_dt_struct
+
+     This field only exists on version 17 and later headers.  It gives
+     the size of the "structure" section of the device tree (which
+     starts at the offset given by off_dt_struct).
+
+   So the typical layout of a DT block (though the various parts don't
+   need to be in that order) looks like this (addresses go from top to
+   bottom):
+
+
+             ------------------------------
+     base -> |  struct boot_param_header  |
+             ------------------------------
+             |      (alignment gap) (*)   |
+             ------------------------------
+             |      memory reserve map    |
+             ------------------------------
+             |      (alignment gap)       |
+             ------------------------------
+             |                            |
+             |    device-tree structure   |
+             |                            |
+             ------------------------------
+             |      (alignment gap)       |
+             ------------------------------
+             |                            |
+             |     device-tree strings    |
+             |                            |
+      -----> ------------------------------
+      |
+      |
+      --- (base + totalsize)
+
+  (*) The alignment gaps are not necessarily present; their presence
+      and size are dependent on the various alignment requirements of
+      the individual data blocks.
+
+
+2) Device tree generalities
+---------------------------
+
+This device-tree itself is separated in two different blocks, a
+structure block and a strings block. Both need to be aligned to a 4
+byte boundary.
+
+First, let's quickly describe the device-tree concept before detailing
+the storage format. This chapter does _not_ describe the detail of the
+required types of nodes & properties for the kernel, this is done
+later in chapter III.
+
+The device-tree layout is strongly inherited from the definition of
+the Open Firmware IEEE 1275 device-tree. It's basically a tree of
+nodes, each node having two or more named properties. A property can
+have a value or not.
+
+It is a tree, so each node has one and only one parent except for the
+root node who has no parent.
+
+A node has 2 names. The actual node name is generally contained in a
+property of type "name" in the node property list whose value is a
+zero terminated string and is mandatory for version 1 to 3 of the
+format definition (as it is in Open Firmware). Version 16 makes it
+optional as it can generate it from the unit name defined below.
+
+There is also a "unit name" that is used to differentiate nodes with
+the same name at the same level, it is usually made of the node
+names, the "@" sign, and a "unit address", which definition is
+specific to the bus type the node sits on.
+
+The unit name doesn't exist as a property per-se but is included in
+the device-tree structure. It is typically used to represent "path" in
+the device-tree. More details about the actual format of these will be
+below.
+
+The kernel generic code does not make any formal use of the
+unit address (though some board support code may do) so the only real
+requirement here for the unit address is to ensure uniqueness of
+the node unit name at a given level of the tree. Nodes with no notion
+of address and no possible sibling of the same name (like /memory or
+/cpus) may omit the unit address in the context of this specification,
+or use the "@0" default unit address. The unit name is used to define
+a node "full path", which is the concatenation of all parent node
+unit names separated with "/".
+
+The root node doesn't have a defined name, and isn't required to have
+a name property either if you are using version 3 or earlier of the
+format. It also has no unit address (no @ symbol followed by a unit
+address). The root node unit name is thus an empty string. The full
+path to the root node is "/".
+
+Every node which actually represents an actual device (that is, a node
+which isn't only a virtual "container" for more nodes, like "/cpus"
+is) is also required to have a "compatible" property indicating the
+specific hardware and an optional list of devices it is fully
+backwards compatible with.
+
+Finally, every node that can be referenced from a property in another
+node is required to have either a "phandle" or a "linux,phandle"
+property. Real Open Firmware implementations provide a unique
+"phandle" value for every node that the "prom_init()" trampoline code
+turns into "linux,phandle" properties. However, this is made optional
+if the flattened device tree is used directly. An example of a node
+referencing another node via "phandle" is when laying out the
+interrupt tree which will be described in a further version of this
+document.
+
+The "phandle" property is a 32-bit value that uniquely
+identifies a node. You are free to use whatever values or system of
+values, internal pointers, or whatever to generate these, the only
+requirement is that every node for which you provide that property has
+a unique value for it.
+
+Here is an example of a simple device-tree. In this example, an "o"
+designates a node followed by the node unit name. Properties are
+presented with their name followed by their content. "content"
+represents an ASCII string (zero terminated) value, while <content>
+represents a 32-bit hexadecimal value. The various nodes in this
+example will be discussed in a later chapter. At this point, it is
+only meant to give you a idea of what a device-tree looks like. I have
+purposefully kept the "name" and "linux,phandle" properties which
+aren't necessary in order to give you a better idea of what the tree
+looks like in practice.
+
+  / o device-tree
+      |- name = "device-tree"
+      |- model = "MyBoardName"
+      |- compatible = "MyBoardFamilyName"
+      |- #address-cells = <2>
+      |- #size-cells = <2>
+      |- linux,phandle = <0>
+      |
+      o cpus
+      | | - name = "cpus"
+      | | - linux,phandle = <1>
+      | | - #address-cells = <1>
+      | | - #size-cells = <0>
+      | |
+      | o PowerPC,970@0
+      |   |- name = "PowerPC,970"
+      |   |- device_type = "cpu"
+      |   |- reg = <0>
+      |   |- clock-frequency = <5f5e1000>
+      |   |- 64-bit
+      |   |- linux,phandle = <2>
+      |
+      o memory@0
+      | |- name = "memory"
+      | |- device_type = "memory"
+      | |- reg = <00000000 00000000 00000000 20000000>
+      | |- linux,phandle = <3>
+      |
+      o chosen
+        |- name = "chosen"
+        |- bootargs = "root=/dev/sda2"
+        |- linux,phandle = <4>
+
+This tree is almost a minimal tree. It pretty much contains the
+minimal set of required nodes and properties to boot a linux kernel;
+that is, some basic model informations at the root, the CPUs, and the
+physical memory layout.  It also includes misc information passed
+through /chosen, like in this example, the platform type (mandatory)
+and the kernel command line arguments (optional).
+
+The /cpus/PowerPC,970@0/64-bit property is an example of a
+property without a value. All other properties have a value. The
+significance of the #address-cells and #size-cells properties will be
+explained in chapter IV which defines precisely the required nodes and
+properties and their content.
+
+
+3) Device tree "structure" block
+
+The structure of the device tree is a linearized tree structure. The
+"OF_DT_BEGIN_NODE" token starts a new node, and the "OF_DT_END_NODE"
+ends that node definition. Child nodes are simply defined before
+"OF_DT_END_NODE" (that is nodes within the node). A 'token' is a 32
+bit value. The tree has to be "finished" with a OF_DT_END token
+
+Here's the basic structure of a single node:
+
+     * token OF_DT_BEGIN_NODE (that is 0x00000001)
+     * for version 1 to 3, this is the node full path as a zero
+       terminated string, starting with "/". For version 16 and later,
+       this is the node unit name only (or an empty string for the
+       root node)
+     * [align gap to next 4 bytes boundary]
+     * for each property:
+        * token OF_DT_PROP (that is 0x00000003)
+        * 32-bit value of property value size in bytes (or 0 if no
+          value)
+        * 32-bit value of offset in string block of property name
+        * property value data if any
+        * [align gap to next 4 bytes boundary]
+     * [child nodes if any]
+     * token OF_DT_END_NODE (that is 0x00000002)
+
+So the node content can be summarized as a start token, a full path,
+a list of properties, a list of child nodes, and an end token. Every
+child node is a full node structure itself as defined above.
+
+NOTE: The above definition requires that all property definitions for
+a particular node MUST precede any subnode definitions for that node.
+Although the structure would not be ambiguous if properties and
+subnodes were intermingled, the kernel parser requires that the
+properties come first (up until at least 2.6.22).  Any tools
+manipulating a flattened tree must take care to preserve this
+constraint.
+
+4) Device tree "strings" block
+
+In order to save space, property names, which are generally redundant,
+are stored separately in the "strings" block. This block is simply the
+whole bunch of zero terminated strings for all property names
+concatenated together. The device-tree property definitions in the
+structure block will contain offset values from the beginning of the
+strings block.
+
+
+III - Required content of the device tree
+=========================================
+
+WARNING: All "linux,*" properties defined in this document apply only
+to a flattened device-tree. If your platform uses a real
+implementation of Open Firmware or an implementation compatible with
+the Open Firmware client interface, those properties will be created
+by the trampoline code in the kernel's prom_init() file. For example,
+that's where you'll have to add code to detect your board model and
+set the platform number. However, when using the flattened device-tree
+entry point, there is no prom_init() pass, and thus you have to
+provide those properties yourself.
+
+
+1) Note about cells and address representation
+----------------------------------------------
+
+The general rule is documented in the various Open Firmware
+documentations. If you choose to describe a bus with the device-tree
+and there exist an OF bus binding, then you should follow the
+specification. However, the kernel does not require every single
+device or bus to be described by the device tree.
+
+In general, the format of an address for a device is defined by the
+parent bus type, based on the #address-cells and #size-cells
+properties.  Note that the parent's parent definitions of #address-cells
+and #size-cells are not inherited so every node with children must specify
+them.  The kernel requires the root node to have those properties defining
+addresses format for devices directly mapped on the processor bus.
+
+Those 2 properties define 'cells' for representing an address and a
+size. A "cell" is a 32-bit number. For example, if both contain 2
+like the example tree given above, then an address and a size are both
+composed of 2 cells, and each is a 64-bit number (cells are
+concatenated and expected to be in big endian format). Another example
+is the way Apple firmware defines them, with 2 cells for an address
+and one cell for a size.  Most 32-bit implementations should define
+#address-cells and #size-cells to 1, which represents a 32-bit value.
+Some 32-bit processors allow for physical addresses greater than 32
+bits; these processors should define #address-cells as 2.
+
+"reg" properties are always a tuple of the type "address size" where
+the number of cells of address and size is specified by the bus
+#address-cells and #size-cells. When a bus supports various address
+spaces and other flags relative to a given address allocation (like
+prefetchable, etc...) those flags are usually added to the top level
+bits of the physical address. For example, a PCI physical address is
+made of 3 cells, the bottom two containing the actual address itself
+while the top cell contains address space indication, flags, and pci
+bus & device numbers.
+
+For buses that support dynamic allocation, it's the accepted practice
+to then not provide the address in "reg" (keep it 0) though while
+providing a flag indicating the address is dynamically allocated, and
+then, to provide a separate "assigned-addresses" property that
+contains the fully allocated addresses. See the PCI OF bindings for
+details.
+
+In general, a simple bus with no address space bits and no dynamic
+allocation is preferred if it reflects your hardware, as the existing
+kernel address parsing functions will work out of the box. If you
+define a bus type with a more complex address format, including things
+like address space bits, you'll have to add a bus translator to the
+prom_parse.c file of the recent kernels for your bus type.
+
+The "reg" property only defines addresses and sizes (if #size-cells is
+non-0) within a given bus. In order to translate addresses upward
+(that is into parent bus addresses, and possibly into CPU physical
+addresses), all buses must contain a "ranges" property. If the
+"ranges" property is missing at a given level, it's assumed that
+translation isn't possible, i.e., the registers are not visible on the
+parent bus.  The format of the "ranges" property for a bus is a list
+of:
+
+       bus address, parent bus address, size
+
+"bus address" is in the format of the bus this bus node is defining,
+that is, for a PCI bridge, it would be a PCI address. Thus, (bus
+address, size) defines a range of addresses for child devices. "parent
+bus address" is in the format of the parent bus of this bus. For
+example, for a PCI host controller, that would be a CPU address. For a
+PCI<->ISA bridge, that would be a PCI address. It defines the base
+address in the parent bus where the beginning of that range is mapped.
+
+For new 64-bit board support, I recommend either the 2/2 format or
+Apple's 2/1 format which is slightly more compact since sizes usually
+fit in a single 32-bit word.   New 32-bit board support should use a
+1/1 format, unless the processor supports physical addresses greater
+than 32-bits, in which case a 2/1 format is recommended.
+
+Alternatively, the "ranges" property may be empty, indicating that the
+registers are visible on the parent bus using an identity mapping
+translation.  In other words, the parent bus address space is the same
+as the child bus address space.
+
+2) Note about "compatible" properties
+-------------------------------------
+
+These properties are optional, but recommended in devices and the root
+node. The format of a "compatible" property is a list of concatenated
+zero terminated strings. They allow a device to express its
+compatibility with a family of similar devices, in some cases,
+allowing a single driver to match against several devices regardless
+of their actual names.
+
+3) Note about "name" properties
+-------------------------------
+
+While earlier users of Open Firmware like OldWorld macintoshes tended
+to use the actual device name for the "name" property, it's nowadays
+considered a good practice to use a name that is closer to the device
+class (often equal to device_type). For example, nowadays, Ethernet
+controllers are named "ethernet", an additional "model" property
+defining precisely the chip type/model, and "compatible" property
+defining the family in case a single driver can driver more than one
+of these chips. However, the kernel doesn't generally put any
+restriction on the "name" property; it is simply considered good
+practice to follow the standard and its evolutions as closely as
+possible.
+
+Note also that the new format version 16 makes the "name" property
+optional. If it's absent for a node, then the node's unit name is then
+used to reconstruct the name. That is, the part of the unit name
+before the "@" sign is used (or the entire unit name if no "@" sign
+is present).
+
+4) Note about node and property names and character set
+-------------------------------------------------------
+
+While Open Firmware provides more flexible usage of 8859-1, this
+specification enforces more strict rules. Nodes and properties should
+be comprised only of ASCII characters 'a' to 'z', '0' to
+'9', ',', '.', '_', '+', '#', '?', and '-'. Node names additionally
+allow uppercase characters 'A' to 'Z' (property names should be
+lowercase. The fact that vendors like Apple don't respect this rule is
+irrelevant here). Additionally, node and property names should always
+begin with a character in the range 'a' to 'z' (or 'A' to 'Z' for node
+names).
+
+The maximum number of characters for both nodes and property names
+is 31. In the case of node names, this is only the leftmost part of
+a unit name (the pure "name" property), it doesn't include the unit
+address which can extend beyond that limit.
+
+
+5) Required nodes and properties
+--------------------------------
+  These are all that are currently required. However, it is strongly
+  recommended that you expose PCI host bridges as documented in the
+  PCI binding to Open Firmware, and your interrupt tree as documented
+  in OF interrupt tree specification.
+
+  a) The root node
+
+  The root node requires some properties to be present:
+
+    - model : this is your board name/model
+    - #address-cells : address representation for "root" devices
+    - #size-cells: the size representation for "root" devices
+    - compatible : the board "family" generally finds its way here,
+      for example, if you have 2 board models with a similar layout,
+      that typically get driven by the same platform code in the
+      kernel, you would specify the exact board model in the
+      compatible property followed by an entry that represents the SoC
+      model.
+
+  The root node is also generally where you add additional properties
+  specific to your board like the serial number if any, that sort of
+  thing. It is recommended that if you add any "custom" property whose
+  name may clash with standard defined ones, you prefix them with your
+  vendor name and a comma.
+
+  b) The /cpus node
+
+  This node is the parent of all individual CPU nodes. It doesn't
+  have any specific requirements, though it's generally good practice
+  to have at least:
+
+               #address-cells = <00000001>
+               #size-cells    = <00000000>
+
+  This defines that the "address" for a CPU is a single cell, and has
+  no meaningful size. This is not necessary but the kernel will assume
+  that format when reading the "reg" properties of a CPU node, see
+  below
+
+  c) The /cpus/* nodes
+
+  So under /cpus, you are supposed to create a node for every CPU on
+  the machine. There is no specific restriction on the name of the
+  CPU, though it's common to call it <architecture>,<core>. For
+  example, Apple uses PowerPC,G5 while IBM uses PowerPC,970FX.
+  However, the Generic Names convention suggests that it would be
+  better to simply use 'cpu' for each cpu node and use the compatible
+  property to identify the specific cpu core.
+
+  Required properties:
+
+    - device_type : has to be "cpu"
+    - reg : This is the physical CPU number, it's a single 32-bit cell
+      and is also used as-is as the unit number for constructing the
+      unit name in the full path. For example, with 2 CPUs, you would
+      have the full path:
+        /cpus/PowerPC,970FX@0
+        /cpus/PowerPC,970FX@1
+      (unit addresses do not require leading zeroes)
+    - d-cache-block-size : one cell, L1 data cache block size in bytes (*)
+    - i-cache-block-size : one cell, L1 instruction cache block size in
+      bytes
+    - d-cache-size : one cell, size of L1 data cache in bytes
+    - i-cache-size : one cell, size of L1 instruction cache in bytes
+
+(*) The cache "block" size is the size on which the cache management
+instructions operate. Historically, this document used the cache
+"line" size here which is incorrect. The kernel will prefer the cache
+block size and will fallback to cache line size for backward
+compatibility.
+
+  Recommended properties:
+
+    - timebase-frequency : a cell indicating the frequency of the
+      timebase in Hz. This is not directly used by the generic code,
+      but you are welcome to copy/paste the pSeries code for setting
+      the kernel timebase/decrementer calibration based on this
+      value.
+    - clock-frequency : a cell indicating the CPU core clock frequency
+      in Hz. A new property will be defined for 64-bit values, but if
+      your frequency is < 4Ghz, one cell is enough. Here as well as
+      for the above, the common code doesn't use that property, but
+      you are welcome to re-use the pSeries or Maple one. A future
+      kernel version might provide a common function for this.
+    - d-cache-line-size : one cell, L1 data cache line size in bytes
+      if different from the block size
+    - i-cache-line-size : one cell, L1 instruction cache line size in
+      bytes if different from the block size
+
+  You are welcome to add any property you find relevant to your board,
+  like some information about the mechanism used to soft-reset the
+  CPUs. For example, Apple puts the GPIO number for CPU soft reset
+  lines in there as a "soft-reset" property since they start secondary
+  CPUs by soft-resetting them.
+
+
+  d) the /memory node(s)
+
+  To define the physical memory layout of your board, you should
+  create one or more memory node(s). You can either create a single
+  node with all memory ranges in its reg property, or you can create
+  several nodes, as you wish. The unit address (@ part) used for the
+  full path is the address of the first range of memory defined by a
+  given node. If you use a single memory node, this will typically be
+  @0.
+
+  Required properties:
+
+    - device_type : has to be "memory"
+    - reg : This property contains all the physical memory ranges of
+      your board. It's a list of addresses/sizes concatenated
+      together, with the number of cells of each defined by the
+      #address-cells and #size-cells of the root node. For example,
+      with both of these properties being 2 like in the example given
+      earlier, a 970 based machine with 6Gb of RAM could typically
+      have a "reg" property here that looks like:
+
+      00000000 00000000 00000000 80000000
+      00000001 00000000 00000001 00000000
+
+      That is a range starting at 0 of 0x80000000 bytes and a range
+      starting at 0x100000000 and of 0x100000000 bytes. You can see
+      that there is no memory covering the IO hole between 2Gb and
+      4Gb. Some vendors prefer splitting those ranges into smaller
+      segments, but the kernel doesn't care.
+
+  e) The /chosen node
+
+  This node is a bit "special". Normally, that's where Open Firmware
+  puts some variable environment information, like the arguments, or
+  the default input/output devices.
+
+  This specification makes a few of these mandatory, but also defines
+  some linux-specific properties that would be normally constructed by
+  the prom_init() trampoline when booting with an OF client interface,
+  but that you have to provide yourself when using the flattened format.
+
+  Recommended properties:
+
+    - bootargs : This zero-terminated string is passed as the kernel
+      command line
+    - linux,stdout-path : This is the full path to your standard
+      console device if any. Typically, if you have serial devices on
+      your board, you may want to put the full path to the one set as
+      the default console in the firmware here, for the kernel to pick
+      it up as its own default console.
+
+  Note that u-boot creates and fills in the chosen node for platforms
+  that use it.
+
+  (Note: a practice that is now obsolete was to include a property
+  under /chosen called interrupt-controller which had a phandle value
+  that pointed to the main interrupt controller)
+
+  f) the /soc<SOCname> node
+
+  This node is used to represent a system-on-a-chip (SoC) and must be
+  present if the processor is a SoC. The top-level soc node contains
+  information that is global to all devices on the SoC. The node name
+  should contain a unit address for the SoC, which is the base address
+  of the memory-mapped register set for the SoC. The name of an SoC
+  node should start with "soc", and the remainder of the name should
+  represent the part number for the soc.  For example, the MPC8540's
+  soc node would be called "soc8540".
+
+  Required properties:
+
+    - ranges : Should be defined as specified in 1) to describe the
+      translation of SoC addresses for memory mapped SoC registers.
+    - bus-frequency: Contains the bus frequency for the SoC node.
+      Typically, the value of this field is filled in by the boot
+      loader.
+    - compatible : Exact model of the SoC
+
+
+  Recommended properties:
+
+    - reg : This property defines the address and size of the
+      memory-mapped registers that are used for the SOC node itself.
+      It does not include the child device registers - these will be
+      defined inside each child node.  The address specified in the
+      "reg" property should match the unit address of the SOC node.
+    - #address-cells : Address representation for "soc" devices.  The
+      format of this field may vary depending on whether or not the
+      device registers are memory mapped.  For memory mapped
+      registers, this field represents the number of cells needed to
+      represent the address of the registers.  For SOCs that do not
+      use MMIO, a special address format should be defined that
+      contains enough cells to represent the required information.
+      See 1) above for more details on defining #address-cells.
+    - #size-cells : Size representation for "soc" devices
+    - #interrupt-cells : Defines the width of cells used to represent
+       interrupts.  Typically this value is <2>, which includes a
+       32-bit number that represents the interrupt number, and a
+       32-bit number that represents the interrupt sense and level.
+       This field is only needed if the SOC contains an interrupt
+       controller.
+
+  The SOC node may contain child nodes for each SOC device that the
+  platform uses.  Nodes should not be created for devices which exist
+  on the SOC but are not used by a particular platform. See chapter VI
+  for more information on how to specify devices that are part of a SOC.
+
+  Example SOC node for the MPC8540:
+
+       soc8540@e0000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               #interrupt-cells = <2>;
+               device_type = "soc";
+               ranges = <00000000 e0000000 00100000>
+               reg = <e0000000 00003000>;
+               bus-frequency = <0>;
+       }
+
+
+
+IV - "dtc", the device tree compiler
+====================================
+
+
+dtc source code can be found at
+<http://git.jdl.com/gitweb/?p=dtc.git>
+
+WARNING: This version is still in early development stage; the
+resulting device-tree "blobs" have not yet been validated with the
+kernel. The current generated block lacks a useful reserve map (it will
+be fixed to generate an empty one, it's up to the bootloader to fill
+it up) among others. The error handling needs work, bugs are lurking,
+etc...
+
+dtc basically takes a device-tree in a given format and outputs a
+device-tree in another format. The currently supported formats are:
+
+  Input formats:
+  -------------
+
+     - "dtb": "blob" format, that is a flattened device-tree block
+       with
+        header all in a binary blob.
+     - "dts": "source" format. This is a text file containing a
+       "source" for a device-tree. The format is defined later in this
+        chapter.
+     - "fs" format. This is a representation equivalent to the
+        output of /proc/device-tree, that is nodes are directories and
+       properties are files
+
+ Output formats:
+ ---------------
+
+     - "dtb": "blob" format
+     - "dts": "source" format
+     - "asm": assembly language file. This is a file that can be
+       sourced by gas to generate a device-tree "blob". That file can
+       then simply be added to your Makefile. Additionally, the
+       assembly file exports some symbols that can be used.
+
+
+The syntax of the dtc tool is
+
+    dtc [-I <input-format>] [-O <output-format>]
+        [-o output-filename] [-V output_version] input_filename
+
+
+The "output_version" defines what version of the "blob" format will be
+generated. Supported versions are 1,2,3 and 16. The default is
+currently version 3 but that may change in the future to version 16.
+
+Additionally, dtc performs various sanity checks on the tree, like the
+uniqueness of linux, phandle properties, validity of strings, etc...
+
+The format of the .dts "source" file is "C" like, supports C and C++
+style comments.
+
+/ {
+}
+
+The above is the "device-tree" definition. It's the only statement
+supported currently at the toplevel.
+
+/ {
+  property1 = "string_value";  /* define a property containing a 0
+                                 * terminated string
+                                */
+
+  property2 = <1234abcd>;      /* define a property containing a
+                                 * numerical 32-bit value (hexadecimal)
+                                */
+
+  property3 = <12345678 12345678 deadbeef>;
+                                /* define a property containing 3
+                                 * numerical 32-bit values (cells) in
+                                 * hexadecimal
+                                */
+  property4 = [0a 0b 0c 0d de ea ad be ef];
+                                /* define a property whose content is
+                                 * an arbitrary array of bytes
+                                 */
+
+  childnode@address {  /* define a child node named "childnode"
+                                 * whose unit name is "childnode at
+                                * address"
+                                 */
+
+    childprop = "hello\n";      /* define a property "childprop" of
+                                 * childnode (in this case, a string)
+                                 */
+  };
+};
+
+Nodes can contain other nodes etc... thus defining the hierarchical
+structure of the tree.
+
+Strings support common escape sequences from C: "\n", "\t", "\r",
+"\(octal value)", "\x(hex value)".
+
+It is also suggested that you pipe your source file through cpp (gcc
+preprocessor) so you can use #include's, #define for constants, etc...
+
+Finally, various options are planned but not yet implemented, like
+automatic generation of phandles, labels (exported to the asm file so
+you can point to a property content and change it easily from whatever
+you link the device-tree with), label or path instead of numeric value
+in some cells to "point" to a node (replaced by a phandle at compile
+time), export of reserve map address to the asm file, ability to
+specify reserve map content at compile time, etc...
+
+We may provide a .h include file with common definitions of that
+proves useful for some properties (like building PCI properties or
+interrupt maps) though it may be better to add a notion of struct
+definitions to the compiler...
+
+
+V - Recommendations for a bootloader
+====================================
+
+
+Here are some various ideas/recommendations that have been proposed
+while all this has been defined and implemented.
+
+  - The bootloader may want to be able to use the device-tree itself
+    and may want to manipulate it (to add/edit some properties,
+    like physical memory size or kernel arguments). At this point, 2
+    choices can be made. Either the bootloader works directly on the
+    flattened format, or the bootloader has its own internal tree
+    representation with pointers (similar to the kernel one) and
+    re-flattens the tree when booting the kernel. The former is a bit
+    more difficult to edit/modify, the later requires probably a bit
+    more code to handle the tree structure. Note that the structure
+    format has been designed so it's relatively easy to "insert"
+    properties or nodes or delete them by just memmoving things
+    around. It contains no internal offsets or pointers for this
+    purpose.
+
+  - An example of code for iterating nodes & retrieving properties
+    directly from the flattened tree format can be found in the kernel
+    file drivers/of/fdt.c.  Look at the of_scan_flat_dt() function,
+    its usage in early_init_devtree(), and the corresponding various
+    early_init_dt_scan_*() callbacks. That code can be re-used in a
+    GPL bootloader, and as the author of that code, I would be happy
+    to discuss possible free licensing to any vendor who wishes to
+    integrate all or part of this code into a non-GPL bootloader.
+    (reference needed; who is 'I' here? ---gcl Jan 31, 2011)
+
+
+
+VI - System-on-a-chip devices and nodes
+=======================================
+
+Many companies are now starting to develop system-on-a-chip
+processors, where the processor core (CPU) and many peripheral devices
+exist on a single piece of silicon.  For these SOCs, an SOC node
+should be used that defines child nodes for the devices that make
+up the SOC. While platforms are not required to use this model in
+order to boot the kernel, it is highly encouraged that all SOC
+implementations define as complete a flat-device-tree as possible to
+describe the devices on the SOC.  This will allow for the
+genericization of much of the kernel code.
+
+
+1) Defining child nodes of an SOC
+---------------------------------
+
+Each device that is part of an SOC may have its own node entry inside
+the SOC node.  For each device that is included in the SOC, the unit
+address property represents the address offset for this device's
+memory-mapped registers in the parent's address space.  The parent's
+address space is defined by the "ranges" property in the top-level soc
+node. The "reg" property for each node that exists directly under the
+SOC node should contain the address mapping from the child address space
+to the parent SOC address space and the size of the device's
+memory-mapped register file.
+
+For many devices that may exist inside an SOC, there are predefined
+specifications for the format of the device tree node.  All SOC child
+nodes should follow these specifications, except where noted in this
+document.
+
+See appendix A for an example partial SOC node definition for the
+MPC8540.
+
+
+2) Representing devices without a current OF specification
+----------------------------------------------------------
+
+Currently, there are many devices on SoCs that do not have a standard
+representation defined as part of the Open Firmware specifications,
+mainly because the boards that contain these SoCs are not currently
+booted using Open Firmware.  Binding documentation for new devices
+should be added to the Documentation/devicetree/bindings directory.
+That directory will expand as device tree support is added to more and
+more SoCs.
+
+
+VII - Specifying interrupt information for devices
+===================================================
+
+The device tree represents the buses and devices of a hardware
+system in a form similar to the physical bus topology of the
+hardware.
+
+In addition, a logical 'interrupt tree' exists which represents the
+hierarchy and routing of interrupts in the hardware.
+
+The interrupt tree model is fully described in the
+document "Open Firmware Recommended Practice: Interrupt
+Mapping Version 0.9".  The document is available at:
+<http://playground.sun.com/1275/practice>.
+
+1) interrupts property
+----------------------
+
+Devices that generate interrupts to a single interrupt controller
+should use the conventional OF representation described in the
+OF interrupt mapping documentation.
+
+Each device which generates interrupts must have an 'interrupt'
+property.  The interrupt property value is an arbitrary number of
+of 'interrupt specifier' values which describe the interrupt or
+interrupts for the device.
+
+The encoding of an interrupt specifier is determined by the
+interrupt domain in which the device is located in the
+interrupt tree.  The root of an interrupt domain specifies in
+its #interrupt-cells property the number of 32-bit cells
+required to encode an interrupt specifier.  See the OF interrupt
+mapping documentation for a detailed description of domains.
+
+For example, the binding for the OpenPIC interrupt controller
+specifies  an #interrupt-cells value of 2 to encode the interrupt
+number and level/sense information. All interrupt children in an
+OpenPIC interrupt domain use 2 cells per interrupt in their interrupts
+property.
+
+The PCI bus binding specifies a #interrupt-cell value of 1 to encode
+which interrupt pin (INTA,INTB,INTC,INTD) is used.
+
+2) interrupt-parent property
+----------------------------
+
+The interrupt-parent property is specified to define an explicit
+link between a device node and its interrupt parent in
+the interrupt tree.  The value of interrupt-parent is the
+phandle of the parent node.
+
+If the interrupt-parent property is not defined for a node, its
+interrupt parent is assumed to be an ancestor in the node's
+_device tree_ hierarchy.
+
+3) OpenPIC Interrupt Controllers
+--------------------------------
+
+OpenPIC interrupt controllers require 2 cells to encode
+interrupt information.  The first cell defines the interrupt
+number.  The second cell defines the sense and level
+information.
+
+Sense and level information should be encoded as follows:
+
+       0 = low to high edge sensitive type enabled
+       1 = active low level sensitive type enabled
+       2 = active high level sensitive type enabled
+       3 = high to low edge sensitive type enabled
+
+4) ISA Interrupt Controllers
+----------------------------
+
+ISA PIC interrupt controllers require 2 cells to encode
+interrupt information.  The first cell defines the interrupt
+number.  The second cell defines the sense and level
+information.
+
+ISA PIC interrupt controllers should adhere to the ISA PIC
+encodings listed below:
+
+       0 =  active low level sensitive type enabled
+       1 =  active high level sensitive type enabled
+       2 =  high to low edge sensitive type enabled
+       3 =  low to high edge sensitive type enabled
+
+VIII - Specifying Device Power Management Information (sleep property)
+===================================================================
+
+Devices on SOCs often have mechanisms for placing devices into low-power
+states that are decoupled from the devices' own register blocks.  Sometimes,
+this information is more complicated than a cell-index property can
+reasonably describe.  Thus, each device controlled in such a manner
+may contain a "sleep" property which describes these connections.
+
+The sleep property consists of one or more sleep resources, each of
+which consists of a phandle to a sleep controller, followed by a
+controller-specific sleep specifier of zero or more cells.
+
+The semantics of what type of low power modes are possible are defined
+by the sleep controller.  Some examples of the types of low power modes
+that may be supported are:
+
+ - Dynamic: The device may be disabled or enabled at any time.
+ - System Suspend: The device may request to be disabled or remain
+   awake during system suspend, but will not be disabled until then.
+ - Permanent: The device is disabled permanently (until the next hard
+   reset).
+
+Some devices may share a clock domain with each other, such that they should
+only be suspended when none of the devices are in use.  Where reasonable,
+such nodes should be placed on a virtual bus, where the bus has the sleep
+property.  If the clock domain is shared among devices that cannot be
+reasonably grouped in this manner, then create a virtual sleep controller
+(similar to an interrupt nexus, except that defining a standardized
+sleep-map should wait until its necessity is demonstrated).
+
+Appendix A - Sample SOC node for MPC8540
+========================================
+
+       soc@e0000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc8540-ccsr", "simple-bus";
+               device_type = "soc";
+               ranges = <0x00000000 0xe0000000 0x00100000>
+               bus-frequency = <0>;
+               interrupt-parent = <&pic>;
+
+               ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       device_type = "network";
+                       model = "TSEC";
+                       compatible = "gianfar", "simple-bus";
+                       reg = <0x24000 0x1000>;
+                       local-mac-address = [ 00 E0 0C 00 73 00 ];
+                       interrupts = <29 2 30 2 34 2>;
+                       phy-handle = <&phy0>;
+                       sleep = <&pmc 00000080>;
+                       ranges;
+
+                       mdio@24520 {
+                               reg = <0x24520 0x20>;
+                               compatible = "fsl,gianfar-mdio";
+
+                               phy0: ethernet-phy@0 {
+                                       interrupts = <5 1>;
+                                       reg = <0>;
+                                       device_type = "ethernet-phy";
+                               };
+
+                               phy1: ethernet-phy@1 {
+                                       interrupts = <5 1>;
+                                       reg = <1>;
+                                       device_type = "ethernet-phy";
+                               };
+
+                               phy3: ethernet-phy@3 {
+                                       interrupts = <7 1>;
+                                       reg = <3>;
+                                       device_type = "ethernet-phy";
+                               };
+                       };
+               };
+
+               ethernet@25000 {
+                       device_type = "network";
+                       model = "TSEC";
+                       compatible = "gianfar";
+                       reg = <0x25000 0x1000>;
+                       local-mac-address = [ 00 E0 0C 00 73 01 ];
+                       interrupts = <13 2 14 2 18 2>;
+                       phy-handle = <&phy1>;
+                       sleep = <&pmc 00000040>;
+               };
+
+               ethernet@26000 {
+                       device_type = "network";
+                       model = "FEC";
+                       compatible = "gianfar";
+                       reg = <0x26000 0x1000>;
+                       local-mac-address = [ 00 E0 0C 00 73 02 ];
+                       interrupts = <41 2>;
+                       phy-handle = <&phy3>;
+                       sleep = <&pmc 00000020>;
+               };
+
+               serial@4500 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "fsl,mpc8540-duart", "simple-bus";
+                       sleep = <&pmc 00000002>;
+                       ranges;
+
+                       serial@4500 {
+                               device_type = "serial";
+                               compatible = "ns16550";
+                               reg = <0x4500 0x100>;
+                               clock-frequency = <0>;
+                               interrupts = <42 2>;
+                       };
+
+                       serial@4600 {
+                               device_type = "serial";
+                               compatible = "ns16550";
+                               reg = <0x4600 0x100>;
+                               clock-frequency = <0>;
+                               interrupts = <42 2>;
+                       };
+               };
+
+               pic: pic@40000 {
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <2>;
+                       reg = <0x40000 0x40000>;
+                       compatible = "chrp,open-pic";
+                       device_type = "open-pic";
+               };
+
+               i2c@3000 {
+                       interrupts = <43 2>;
+                       reg = <0x3000 0x100>;
+                       compatible  = "fsl-i2c";
+                       dfsrr;
+                       sleep = <&pmc 00000004>;
+               };
+
+               pmc: power@e0070 {
+                       compatible = "fsl,mpc8540-pmc", "fsl,mpc8548-pmc";
+                       reg = <0xe0070 0x20>;
+               };
+       };
index b959659..b3f35e5 100644 (file)
@@ -603,3 +603,19 @@ Why:       The adm9240, w83792d and w83793 hardware monitoring drivers have
 Who:   Jean Delvare <khali@linux-fr.org>
 
 ----------------------------
+
+What:  noswapaccount kernel command line parameter
+When:  2.6.40
+Why:   The original implementation of memsw feature enabled by
+       CONFIG_CGROUP_MEM_RES_CTLR_SWAP could be disabled by the noswapaccount
+       kernel parameter (introduced in 2.6.29-rc1). Later on, this decision
+       turned out to be not ideal because we cannot have the feature compiled
+       in and disabled by default and let only interested to enable it
+       (e.g. general distribution kernels might need it). Therefore we have
+       added swapaccount[=0|1] parameter (introduced in 2.6.37) which provides
+       the both possibilities. If we remove noswapaccount we will have
+       less command line parameters with the same functionality and we
+       can also cleanup the parameter handling a bit ().
+Who:   Michal Hocko <mhocko@suse.cz>
+
+----------------------------
index 6ef8cf3..933bc66 100644 (file)
@@ -460,6 +460,8 @@ Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
 2.1.30:
        - Fix writev() (it kept writing the first segment over and over again
          instead of moving onto subsequent segments).
+       - Fix crash in ntfs_mft_record_alloc() when mapping the new extent mft
+         record failed.
 2.1.29:
        - Fix a deadlock when mounting read-write.
 2.1.28:
index 0e76ef1..a22ecf4 100644 (file)
@@ -51,7 +51,8 @@ Supported chips:
   * JEDEC JC 42.4 compliant temperature sensor chips
     Prefix: 'jc42'
     Addresses scanned: I2C 0x18 - 0x1f
-    Datasheet: -
+    Datasheet:
+       http://www.jedec.org/sites/default/files/docs/4_01_04R19.pdf
 
 Author:
        Guenter Roeck <guenter.roeck@ericsson.com>
@@ -60,7 +61,11 @@ Author:
 Description
 -----------
 
-This driver implements support for JEDEC JC 42.4 compliant temperature sensors.
+This driver implements support for JEDEC JC 42.4 compliant temperature sensors,
+which are used on many DDR3 memory modules for mobile devices and servers. Some
+systems use the sensor to prevent memory overheating by automatically throttling
+the memory controller.
+
 The driver auto-detects the chips listed above, but can be manually instantiated
 to support other JC 42.4 compliant chips.
 
@@ -81,15 +86,19 @@ limits. The chip supports only a single register to configure the hysteresis,
 which applies to all limits. This register can be written by writing into
 temp1_crit_hyst. Other hysteresis attributes are read-only.
 
+If the BIOS has configured the sensor for automatic temperature management, it
+is likely that it has locked the registers, i.e., that the temperature limits
+cannot be changed.
+
 Sysfs entries
 -------------
 
 temp1_input            Temperature (RO)
-temp1_min              Minimum temperature (RW)
-temp1_max              Maximum temperature (RW)
-temp1_crit             Critical high temperature (RW)
+temp1_min              Minimum temperature (RO or RW)
+temp1_max              Maximum temperature (RO or RW)
+temp1_crit             Critical high temperature (RO or RW)
 
-temp1_crit_hyst                Critical hysteresis temperature (RW)
+temp1_crit_hyst                Critical hysteresis temperature (RO or RW)
 temp1_max_hyst         Maximum hysteresis temperature (RO)
 
 temp1_min_alarm                Temperature low alarm
index 6526eee..d2b56a4 100644 (file)
@@ -9,6 +9,8 @@ Supported chips:
   Socket S1G3: Athlon II, Sempron, Turion II
 * AMD Family 11h processors:
   Socket S1G2: Athlon (X2), Sempron (X2), Turion X2 (Ultra)
+* AMD Family 12h processors: "Llano"
+* AMD Family 14h processors: "Brazos" (C/E/G-Series)
 
   Prefix: 'k10temp'
   Addresses scanned: PCI space
@@ -17,10 +19,14 @@ Supported chips:
     http://support.amd.com/us/Processor_TechDocs/31116.pdf
   BIOS and Kernel Developer's Guide (BKDG) for AMD Family 11h Processors:
     http://support.amd.com/us/Processor_TechDocs/41256.pdf
+  BIOS and Kernel Developer's Guide (BKDG) for AMD Family 14h Models 00h-0Fh Processors:
+    http://support.amd.com/us/Processor_TechDocs/43170.pdf
   Revision Guide for AMD Family 10h Processors:
     http://support.amd.com/us/Processor_TechDocs/41322.pdf
   Revision Guide for AMD Family 11h Processors:
     http://support.amd.com/us/Processor_TechDocs/41788.pdf
+  Revision Guide for AMD Family 14h Models 00h-0Fh Processors:
+    http://support.amd.com/us/Processor_TechDocs/47534.pdf
   AMD Family 11h Processor Power and Thermal Data Sheet for Notebooks:
     http://support.amd.com/us/Processor_TechDocs/43373.pdf
   AMD Family 10h Server and Workstation Processor Power and Thermal Data Sheet:
@@ -34,7 +40,7 @@ Description
 -----------
 
 This driver permits reading of the internal temperature sensor of AMD
-Family 10h and 11h processors.
+Family 10h/11h/12h/14h processors.
 
 All these processors have a sensor, but on those for Socket F or AM2+,
 the sensor may return inconsistent values (erratum 319).  The driver
index b72e071..738c6fd 100644 (file)
@@ -43,11 +43,11 @@ parameter is applicable:
        AVR32   AVR32 architecture is enabled.
        AX25    Appropriate AX.25 support is enabled.
        BLACKFIN Blackfin architecture is enabled.
+       DRM     Direct Rendering Management support is enabled.
+       DYNAMIC_DEBUG Build in debug messages and enable them at runtime
        EDD     BIOS Enhanced Disk Drive Services (EDD) is enabled
        EFI     EFI Partitioning (GPT) is enabled
        EIDE    EIDE/ATAPI support is enabled.
-       DRM     Direct Rendering Management support is enabled.
-       DYNAMIC_DEBUG Build in debug messages and enable them at runtime
        FB      The frame buffer device is enabled.
        GCOV    GCOV profiling is enabled.
        HW      Appropriate hardware is enabled.
@@ -144,6 +144,11 @@ a fixed number of characters. This limit depends on the architecture
 and is between 256 and 4096 characters. It is defined in the file
 ./include/asm/setup.h as COMMAND_LINE_SIZE.
 
+Finally, the [KMG] suffix is commonly described after a number of kernel
+parameter values. These 'K', 'M', and 'G' letters represent the _binary_
+multipliers 'Kilo', 'Mega', and 'Giga', equalling 2^10, 2^20, and 2^30
+bytes respectively. Such letter suffixes can also be entirely omitted.
+
 
        acpi=           [HW,ACPI,X86]
                        Advanced Configuration and Power Interface
@@ -545,16 +550,20 @@ and is between 256 and 4096 characters. It is defined in the file
                        Format:
                        <first_slot>,<last_slot>,<port>,<enum_bit>[,<debug>]
 
-       crashkernel=nn[KMG]@ss[KMG]
-                       [KNL] Reserve a chunk of physical memory to
-                       hold a kernel to switch to with kexec on panic.
+       crashkernel=size[KMG][@offset[KMG]]
+                       [KNL] Using kexec, Linux can switch to a 'crash kernel'
+                       upon panic. This parameter reserves the physical
+                       memory region [offset, offset + size] for that kernel
+                       image. If '@offset' is omitted, then a suitable offset
+                       is selected automatically. Check
+                       Documentation/kdump/kdump.txt for further details.
 
        crashkernel=range1:size1[,range2:size2,...][@offset]
                        [KNL] Same as above, but depends on the memory
                        in the running system. The syntax of range is
                        start-[end] where start and end are both
                        a memory unit (amount[KMG]). See also
-                       Documentation/kdump/kdump.txt for a example.
+                       Documentation/kdump/kdump.txt for an example.
 
        cs89x0_dma=     [HW,NET]
                        Format: <dma>
@@ -1262,10 +1271,9 @@ and is between 256 and 4096 characters. It is defined in the file
                        6 (KERN_INFO)           informational
                        7 (KERN_DEBUG)          debug-level messages
 
-       log_buf_len=n   Sets the size of the printk ring buffer, in bytes.
-                       Format: { n | nk | nM }
-                       n must be a power of two.  The default size
-                       is set in the kernel config file.
+       log_buf_len=n[KMG]      Sets the size of the printk ring buffer,
+                       in bytes.  n must be a power of two.  The default
+                       size is set in the kernel config file.
 
        logo.nologo     [FB] Disables display of the built-in Linux logo.
                        This may be used to provide more screen space for
@@ -2436,6 +2444,10 @@ and is between 256 and 4096 characters. It is defined in the file
                        <deci-seconds>: poll all this frequency
                        0: no polling (default)
 
+       threadirqs      [KNL]
+                       Force threading of all interrupt handlers except those
+                       marked explicitely IRQF_NO_THREAD.
+
        topology=       [S390]
                        Format: {off | on}
                        Specify if the kernel should make use of the cpu
index 631ad2f..f0d3a80 100644 (file)
@@ -21,6 +21,7 @@ Contents:
      - SMP barrier pairing.
      - Examples of memory barrier sequences.
      - Read memory barriers vs load speculation.
+     - Transitivity
 
  (*) Explicit kernel barriers.
 
@@ -959,6 +960,63 @@ the speculation will be cancelled and the value reloaded:
        retrieved                               :       :       +-------+
 
 
+TRANSITIVITY
+------------
+
+Transitivity is a deeply intuitive notion about ordering that is not
+always provided by real computer systems.  The following example
+demonstrates transitivity (also called "cumulativity"):
+
+       CPU 1                   CPU 2                   CPU 3
+       ======================= ======================= =======================
+               { X = 0, Y = 0 }
+       STORE X=1               LOAD X                  STORE Y=1
+                               <general barrier>       <general barrier>
+                               LOAD Y                  LOAD X
+
+Suppose that CPU 2's load from X returns 1 and its load from Y returns 0.
+This indicates that CPU 2's load from X in some sense follows CPU 1's
+store to X and that CPU 2's load from Y in some sense preceded CPU 3's
+store to Y.  The question is then "Can CPU 3's load from X return 0?"
+
+Because CPU 2's load from X in some sense came after CPU 1's store, it
+is natural to expect that CPU 3's load from X must therefore return 1.
+This expectation is an example of transitivity: if a load executing on
+CPU A follows a load from the same variable executing on CPU B, then
+CPU A's load must either return the same value that CPU B's load did,
+or must return some later value.
+
+In the Linux kernel, use of general memory barriers guarantees
+transitivity.  Therefore, in the above example, if CPU 2's load from X
+returns 1 and its load from Y returns 0, then CPU 3's load from X must
+also return 1.
+
+However, transitivity is -not- guaranteed for read or write barriers.
+For example, suppose that CPU 2's general barrier in the above example
+is changed to a read barrier as shown below:
+
+       CPU 1                   CPU 2                   CPU 3
+       ======================= ======================= =======================
+               { X = 0, Y = 0 }
+       STORE X=1               LOAD X                  STORE Y=1
+                               <read barrier>          <general barrier>
+                               LOAD Y                  LOAD X
+
+This substitution destroys transitivity: in this example, it is perfectly
+legal for CPU 2's load from X to return 1, its load from Y to return 0,
+and CPU 3's load from X to return 0.
+
+The key point is that although CPU 2's read barrier orders its pair
+of loads, it does not guarantee to order CPU 1's store.  Therefore, if
+this example runs on a system where CPUs 1 and 2 share a store buffer
+or a level of cache, CPU 2 might have early access to CPU 1's writes.
+General barriers are therefore required to ensure that all CPUs agree
+on the combined order of CPU 1's and CPU 2's accesses.
+
+To reiterate, if your code requires transitivity, use general barriers
+throughout.
+
+
 ========================
 EXPLICIT KERNEL BARRIERS
 ========================
index fe5c099..4edd78d 100644 (file)
@@ -40,8 +40,6 @@ decnet.txt
        - info on using the DECnet networking layer in Linux.
 depca.txt
        - the Digital DEPCA/EtherWORKS DE1?? and DE2?? LANCE Ethernet driver
-dgrs.txt
-       - the Digi International RightSwitch SE-X Ethernet driver
 dmfe.txt
        - info on the Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver.
 e100.txt
@@ -50,8 +48,6 @@ e1000.txt
        - info on Intel's E1000 line of gigabit ethernet boards
 eql.txt
        - serial IP load balancing
-ethertap.txt
-       - the Ethertap user space packet reception and transmission driver
 ewrk3.txt
        - the Digital EtherWORKS 3 DE203/4/5 Ethernet driver
 filter.txt
@@ -104,8 +100,6 @@ tuntap.txt
        - TUN/TAP device driver, allowing user space Rx/Tx of packets.
 vortex.txt
        - info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) Ethernet cards.
-wavelan.txt
-       - AT&T GIS (nee NCR) WaveLAN card: An Ethernet-like radio transceiver
 x25.txt
        - general info on X.25 development.
 x25-iface.txt
index 5aba7a3..24c308d 100644 (file)
@@ -4,6 +4,8 @@ obj- := dummy.o
 # List of programs to build
 hostprogs-y := ifenslave
 
+HOSTCFLAGS_ifenslave.o += -I$(objtree)/usr/include
+
 # Tell kbuild to always build the programs
 always := $(hostprogs-y)
 
index 5dc6387..25d2f41 100644 (file)
@@ -49,7 +49,8 @@ Table of Contents
 3.3    Configuring Bonding Manually with Ifenslave
 3.3.1          Configuring Multiple Bonds Manually
 3.4    Configuring Bonding Manually via Sysfs
-3.5    Overriding Configuration for Special Cases
+3.5    Configuration with Interfaces Support
+3.6    Overriding Configuration for Special Cases
 
 4. Querying Bonding Configuration
 4.1    Bonding Configuration
@@ -161,8 +162,8 @@ onwards) do not have /usr/include/linux symbolically linked to the
 default kernel source include directory.
 
 SECOND IMPORTANT NOTE:
-       If you plan to configure bonding using sysfs, you do not need
-to use ifenslave.
+       If you plan to configure bonding using sysfs or using the
+/etc/network/interfaces file, you do not need to use ifenslave.
 
 2. Bonding Driver Options
 =========================
@@ -779,22 +780,26 @@ resend_igmp
 
        You can configure bonding using either your distro's network
 initialization scripts, or manually using either ifenslave or the
-sysfs interface.  Distros generally use one of two packages for the
-network initialization scripts: initscripts or sysconfig.  Recent
-versions of these packages have support for bonding, while older
+sysfs interface.  Distros generally use one of three packages for the
+network initialization scripts: initscripts, sysconfig or interfaces.
+Recent versions of these packages have support for bonding, while older
 versions do not.
 
        We will first describe the options for configuring bonding for
-distros using versions of initscripts and sysconfig with full or
-partial support for bonding, then provide information on enabling
+distros using versions of initscripts, sysconfig and interfaces with full
+or partial support for bonding, then provide information on enabling
 bonding without support from the network initialization scripts (i.e.,
 older versions of initscripts or sysconfig).
 
-       If you're unsure whether your distro uses sysconfig or
-initscripts, or don't know if it's new enough, have no fear.
+       If you're unsure whether your distro uses sysconfig,
+initscripts or interfaces, or don't know if it's new enough, have no fear.
 Determining this is fairly straightforward.
 
-       First, issue the command:
+       First, look for a file called interfaces in /etc/network directory.
+If this file is present in your system, then your system use interfaces. See
+Configuration with Interfaces Support.
+
+       Else, issue the command:
 
 $ rpm -qf /sbin/ifup
 
@@ -1327,8 +1332,62 @@ echo 2000 > /sys/class/net/bond1/bonding/arp_interval
 echo +eth2 > /sys/class/net/bond1/bonding/slaves
 echo +eth3 > /sys/class/net/bond1/bonding/slaves
 
-3.5 Overriding Configuration for Special Cases
+3.5 Configuration with Interfaces Support
+-----------------------------------------
+
+        This section applies to distros which use /etc/network/interfaces file
+to describe network interface configuration, most notably Debian and it's
+derivatives.
+
+       The ifup and ifdown commands on Debian don't support bonding out of
+the box. The ifenslave-2.6 package should be installed to provide bonding
+support.  Once installed, this package will provide bond-* options to be used
+into /etc/network/interfaces.
+
+       Note that ifenslave-2.6 package will load the bonding module and use
+the ifenslave command when appropriate.
+
+Example Configurations
+----------------------
+
+In /etc/network/interfaces, the following stanza will configure bond0, in
+active-backup mode, with eth0 and eth1 as slaves.
+
+auto bond0
+iface bond0 inet dhcp
+       bond-slaves eth0 eth1
+       bond-mode active-backup
+       bond-miimon 100
+       bond-primary eth0 eth1
+
+If the above configuration doesn't work, you might have a system using
+upstart for system startup. This is most notably true for recent
+Ubuntu versions. The following stanza in /etc/network/interfaces will
+produce the same result on those systems.
+
+auto bond0
+iface bond0 inet dhcp
+       bond-slaves none
+       bond-mode active-backup
+       bond-miimon 100
+
+auto eth0
+iface eth0 inet manual
+       bond-master bond0
+       bond-primary eth0 eth1
+
+auto eth1
+iface eth1 inet manual
+       bond-master bond0
+       bond-primary eth0 eth1
+
+For a full list of bond-* supported options in /etc/network/interfaces and some
+more advanced examples tailored to you particular distros, see the files in
+/usr/share/doc/ifenslave-2.6.
+
+3.6 Overriding Configuration for Special Cases
 ----------------------------------------------
+
 When using the bonding driver, the physical port which transmits a frame is
 typically selected by the bonding driver, and is not relevant to the user or
 system administrator.  The output port is simply selected using the policies of
index aefd1e6..04ca063 100644 (file)
@@ -61,7 +61,6 @@ before the more general line given above as the first match is the one taken.
        create  dns_resolver    foo:*   *       /usr/sbin/dns.foo %k
 
 
-
 =====
 USAGE
 =====
@@ -104,6 +103,14 @@ implemented in the module can be called after doing:
      returned also.
 
 
+===============================
+READING DNS KEYS FROM USERSPACE
+===============================
+
+Keys of dns_resolver type can be read from userspace using keyctl_read() or
+"keyctl read/print/pipe".
+
+
 =========
 MECHANISM
 =========
index d99940d..ac3b4a7 100644 (file)
@@ -187,7 +187,7 @@ tcp_cookie_size - INTEGER
 tcp_dsack - BOOLEAN
        Allows TCP to send "duplicate" SACKs.
 
-tcp_ecn - BOOLEAN
+tcp_ecn - INTEGER
        Enable Explicit Congestion Notification (ECN) in TCP. ECN is only
        used when both ends of the TCP flow support it. It is useful to
        avoid losses due to congestion (when the bottleneck router supports
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
deleted file mode 100644 (file)
index 7400d75..0000000
+++ /dev/null
@@ -1,1447 +0,0 @@
-           Booting the Linux/ppc kernel without Open Firmware
-           --------------------------------------------------
-
-(c) 2005 Benjamin Herrenschmidt <benh at kernel.crashing.org>,
-    IBM Corp.
-(c) 2005 Becky Bruce <becky.bruce at freescale.com>,
-    Freescale Semiconductor, FSL SOC and 32-bit additions
-(c) 2006 MontaVista Software, Inc.
-    Flash chip node definition
-
-Table of Contents
-=================
-
-  I - Introduction
-    1) Entry point for arch/powerpc
-    2) Board support
-
-  II - The DT block format
-    1) Header
-    2) Device tree generalities
-    3) Device tree "structure" block
-    4) Device tree "strings" block
-
-  III - Required content of the device tree
-    1) Note about cells and address representation
-    2) Note about "compatible" properties
-    3) Note about "name" properties
-    4) Note about node and property names and character set
-    5) Required nodes and properties
-      a) The root node
-      b) The /cpus node
-      c) The /cpus/* nodes
-      d) the /memory node(s)
-      e) The /chosen node
-      f) the /soc<SOCname> node
-
-  IV - "dtc", the device tree compiler
-
-  V - Recommendations for a bootloader
-
-  VI - System-on-a-chip devices and nodes
-    1) Defining child nodes of an SOC
-    2) Representing devices without a current OF specification
-      a) PHY nodes
-      b) Interrupt controllers
-      c) 4xx/Axon EMAC ethernet nodes
-      d) Xilinx IP cores
-      e) USB EHCI controllers
-      f) MDIO on GPIOs
-      g) SPI busses
-
-  VII - Specifying interrupt information for devices
-    1) interrupts property
-    2) interrupt-parent property
-    3) OpenPIC Interrupt Controllers
-    4) ISA Interrupt Controllers
-
-  VIII - Specifying device power management information (sleep property)
-
-  Appendix A - Sample SOC node for MPC8540
-
-
-Revision Information
-====================
-
-   May 18, 2005: Rev 0.1 - Initial draft, no chapter III yet.
-
-   May 19, 2005: Rev 0.2 - Add chapter III and bits & pieces here or
-                           clarifies the fact that a lot of things are
-                           optional, the kernel only requires a very
-                           small device tree, though it is encouraged
-                           to provide an as complete one as possible.
-
-   May 24, 2005: Rev 0.3 - Precise that DT block has to be in RAM
-                        - Misc fixes
-                        - Define version 3 and new format version 16
-                          for the DT block (version 16 needs kernel
-                          patches, will be fwd separately).
-                          String block now has a size, and full path
-                          is replaced by unit name for more
-                          compactness.
-                          linux,phandle is made optional, only nodes
-                          that are referenced by other nodes need it.
-                          "name" property is now automatically
-                          deduced from the unit name
-
-   June 1, 2005: Rev 0.4 - Correct confusion between OF_DT_END and
-                           OF_DT_END_NODE in structure definition.
-                         - Change version 16 format to always align
-                           property data to 4 bytes. Since tokens are
-                           already aligned, that means no specific
-                           required alignment between property size
-                           and property data. The old style variable
-                           alignment would make it impossible to do
-                           "simple" insertion of properties using
-                           memmove (thanks Milton for
-                           noticing). Updated kernel patch as well
-                        - Correct a few more alignment constraints
-                        - Add a chapter about the device-tree
-                           compiler and the textural representation of
-                           the tree that can be "compiled" by dtc.
-
-   November 21, 2005: Rev 0.5
-                        - Additions/generalizations for 32-bit
-                        - Changed to reflect the new arch/powerpc
-                          structure
-                        - Added chapter VI
-
-
- ToDo:
-       - Add some definitions of interrupt tree (simple/complex)
-       - Add some definitions for PCI host bridges
-       - Add some common address format examples
-       - Add definitions for standard properties and "compatible"
-         names for cells that are not already defined by the existing
-         OF spec.
-       - Compare FSL SOC use of PCI to standard and make sure no new
-         node definition required.
-       - Add more information about node definitions for SOC devices
-         that currently have no standard, like the FSL CPM.
-
-
-I - Introduction
-================
-
-During the recent development of the Linux/ppc64 kernel, and more
-specifically, the addition of new platform types outside of the old
-IBM pSeries/iSeries pair, it was decided to enforce some strict rules
-regarding the kernel entry and bootloader <-> kernel interfaces, in
-order to avoid the degeneration that had become the ppc32 kernel entry
-point and the way a new platform should be added to the kernel. The
-legacy iSeries platform breaks those rules as it predates this scheme,
-but no new board support will be accepted in the main tree that
-doesn't follow them properly.  In addition, since the advent of the
-arch/powerpc merged architecture for ppc32 and ppc64, new 32-bit
-platforms and 32-bit platforms which move into arch/powerpc will be
-required to use these rules as well.
-
-The main requirement that will be defined in more detail below is
-the presence of a device-tree whose format is defined after Open
-Firmware specification. However, in order to make life easier
-to embedded board vendors, the kernel doesn't require the device-tree
-to represent every device in the system and only requires some nodes
-and properties to be present. This will be described in detail in
-section III, but, for example, the kernel does not require you to
-create a node for every PCI device in the system. It is a requirement
-to have a node for PCI host bridges in order to provide interrupt
-routing informations and memory/IO ranges, among others. It is also
-recommended to define nodes for on chip devices and other busses that
-don't specifically fit in an existing OF specification. This creates a
-great flexibility in the way the kernel can then probe those and match
-drivers to device, without having to hard code all sorts of tables. It
-also makes it more flexible for board vendors to do minor hardware
-upgrades without significantly impacting the kernel code or cluttering
-it with special cases.
-
-
-1) Entry point for arch/powerpc
--------------------------------
-
-   There is one and one single entry point to the kernel, at the start
-   of the kernel image. That entry point supports two calling
-   conventions:
-
-        a) Boot from Open Firmware. If your firmware is compatible
-        with Open Firmware (IEEE 1275) or provides an OF compatible
-        client interface API (support for "interpret" callback of
-        forth words isn't required), you can enter the kernel with:
-
-              r5 : OF callback pointer as defined by IEEE 1275
-              bindings to powerpc. Only the 32-bit client interface
-              is currently supported
-
-              r3, r4 : address & length of an initrd if any or 0
-
-              The MMU is either on or off; the kernel will run the
-              trampoline located in arch/powerpc/kernel/prom_init.c to
-              extract the device-tree and other information from open
-              firmware and build a flattened device-tree as described
-              in b). prom_init() will then re-enter the kernel using
-              the second method. This trampoline code runs in the
-              context of the firmware, which is supposed to handle all
-              exceptions during that time.
-
-        b) Direct entry with a flattened device-tree block. This entry
-        point is called by a) after the OF trampoline and can also be
-        called directly by a bootloader that does not support the Open
-        Firmware client interface. It is also used by "kexec" to
-        implement "hot" booting of a new kernel from a previous
-        running one. This method is what I will describe in more
-        details in this document, as method a) is simply standard Open
-        Firmware, and thus should be implemented according to the
-        various standard documents defining it and its binding to the
-        PowerPC platform. The entry point definition then becomes:
-
-                r3 : physical pointer to the device-tree block
-                (defined in chapter II) in RAM
-
-                r4 : physical pointer to the kernel itself. This is
-                used by the assembly code to properly disable the MMU
-                in case you are entering the kernel with MMU enabled
-                and a non-1:1 mapping.
-
-                r5 : NULL (as to differentiate with method a)
-
-        Note about SMP entry: Either your firmware puts your other
-        CPUs in some sleep loop or spin loop in ROM where you can get
-        them out via a soft reset or some other means, in which case
-        you don't need to care, or you'll have to enter the kernel
-        with all CPUs. The way to do that with method b) will be
-        described in a later revision of this document.
-
-
-2) Board support
-----------------
-
-64-bit kernels:
-
-   Board supports (platforms) are not exclusive config options. An
-   arbitrary set of board supports can be built in a single kernel
-   image. The kernel will "know" what set of functions to use for a
-   given platform based on the content of the device-tree. Thus, you
-   should:
-
-        a) add your platform support as a _boolean_ option in
-        arch/powerpc/Kconfig, following the example of PPC_PSERIES,
-        PPC_PMAC and PPC_MAPLE. The later is probably a good
-        example of a board support to start from.
-
-        b) create your main platform file as
-        "arch/powerpc/platforms/myplatform/myboard_setup.c" and add it
-        to the Makefile under the condition of your CONFIG_
-        option. This file will define a structure of type "ppc_md"
-        containing the various callbacks that the generic code will
-        use to get to your platform specific code
-
-        c) Add a reference to your "ppc_md" structure in the
-        "machines" table in arch/powerpc/kernel/setup_64.c if you are
-        a 64-bit platform.
-
-        d) request and get assigned a platform number (see PLATFORM_*
-        constants in arch/powerpc/include/asm/processor.h
-
-32-bit embedded kernels:
-
-  Currently, board support is essentially an exclusive config option.
-  The kernel is configured for a single platform.  Part of the reason
-  for this is to keep kernels on embedded systems small and efficient;
-  part of this is due to the fact the code is already that way. In the
-  future, a kernel may support multiple platforms, but only if the
-  platforms feature the same core architecture.  A single kernel build
-  cannot support both configurations with Book E and configurations
-  with classic Powerpc architectures.
-
-  32-bit embedded platforms that are moved into arch/powerpc using a
-  flattened device tree should adopt the merged tree practice of
-  setting ppc_md up dynamically, even though the kernel is currently
-  built with support for only a single platform at a time.  This allows
-  unification of the setup code, and will make it easier to go to a
-  multiple-platform-support model in the future.
-
-NOTE: I believe the above will be true once Ben's done with the merge
-of the boot sequences.... someone speak up if this is wrong!
-
-  To add a 32-bit embedded platform support, follow the instructions
-  for 64-bit platforms above, with the exception that the Kconfig
-  option should be set up such that the kernel builds exclusively for
-  the platform selected.  The processor type for the platform should
-  enable another config option to select the specific board
-  supported.
-
-NOTE: If Ben doesn't merge the setup files, may need to change this to
-point to setup_32.c
-
-
-   I will describe later the boot process and various callbacks that
-   your platform should implement.
-
-
-II - The DT block format
-========================
-
-
-This chapter defines the actual format of the flattened device-tree
-passed to the kernel. The actual content of it and kernel requirements
-are described later. You can find example of code manipulating that
-format in various places, including arch/powerpc/kernel/prom_init.c
-which will generate a flattened device-tree from the Open Firmware
-representation, or the fs2dt utility which is part of the kexec tools
-which will generate one from a filesystem representation. It is
-expected that a bootloader like uboot provides a bit more support,
-that will be discussed later as well.
-
-Note: The block has to be in main memory. It has to be accessible in
-both real mode and virtual mode with no mapping other than main
-memory. If you are writing a simple flash bootloader, it should copy
-the block to RAM before passing it to the kernel.
-
-
-1) Header
----------
-
-   The kernel is entered with r3 pointing to an area of memory that is
-   roughly described in arch/powerpc/include/asm/prom.h by the structure
-   boot_param_header:
-
-struct boot_param_header {
-        u32     magic;                  /* magic word OF_DT_HEADER */
-        u32     totalsize;              /* total size of DT block */
-        u32     off_dt_struct;          /* offset to structure */
-        u32     off_dt_strings;         /* offset to strings */
-        u32     off_mem_rsvmap;         /* offset to memory reserve map
-                                           */
-        u32     version;                /* format version */
-        u32     last_comp_version;      /* last compatible version */
-
-        /* version 2 fields below */
-        u32     boot_cpuid_phys;        /* Which physical CPU id we're
-                                           booting on */
-        /* version 3 fields below */
-        u32     size_dt_strings;        /* size of the strings block */
-
-        /* version 17 fields below */
-        u32    size_dt_struct;         /* size of the DT structure block */
-};
-
-   Along with the constants:
-
-/* Definitions used by the flattened device tree */
-#define OF_DT_HEADER            0xd00dfeed      /* 4: version,
-                                                  4: total size */
-#define OF_DT_BEGIN_NODE        0x1             /* Start node: full name
-                                                  */
-#define OF_DT_END_NODE          0x2             /* End node */
-#define OF_DT_PROP              0x3             /* Property: name off,
-                                                   size, content */
-#define OF_DT_END               0x9
-
-   All values in this header are in big endian format, the various
-   fields in this header are defined more precisely below. All
-   "offset" values are in bytes from the start of the header; that is
-   from the value of r3.
-
-   - magic
-
-     This is a magic value that "marks" the beginning of the
-     device-tree block header. It contains the value 0xd00dfeed and is
-     defined by the constant OF_DT_HEADER
-
-   - totalsize
-
-     This is the total size of the DT block including the header. The
-     "DT" block should enclose all data structures defined in this
-     chapter (who are pointed to by offsets in this header). That is,
-     the device-tree structure, strings, and the memory reserve map.
-
-   - off_dt_struct
-
-     This is an offset from the beginning of the header to the start
-     of the "structure" part the device tree. (see 2) device tree)
-
-   - off_dt_strings
-
-     This is an offset from the beginning of the header to the start
-     of the "strings" part of the device-tree
-
-   - off_mem_rsvmap
-
-     This is an offset from the beginning of the header to the start
-     of the reserved memory map. This map is a list of pairs of 64-
-     bit integers. Each pair is a physical address and a size. The
-     list is terminated by an entry of size 0. This map provides the
-     kernel with a list of physical memory areas that are "reserved"
-     and thus not to be used for memory allocations, especially during
-     early initialization. The kernel needs to allocate memory during
-     boot for things like un-flattening the device-tree, allocating an
-     MMU hash table, etc... Those allocations must be done in such a
-     way to avoid overriding critical things like, on Open Firmware
-     capable machines, the RTAS instance, or on some pSeries, the TCE
-     tables used for the iommu. Typically, the reserve map should
-     contain _at least_ this DT block itself (header,total_size). If
-     you are passing an initrd to the kernel, you should reserve it as
-     well. You do not need to reserve the kernel image itself. The map
-     should be 64-bit aligned.
-
-   - version
-
-     This is the version of this structure. Version 1 stops
-     here. Version 2 adds an additional field boot_cpuid_phys.
-     Version 3 adds the size of the strings block, allowing the kernel
-     to reallocate it easily at boot and free up the unused flattened
-     structure after expansion. Version 16 introduces a new more
-     "compact" format for the tree itself that is however not backward
-     compatible. Version 17 adds an additional field, size_dt_struct,
-     allowing it to be reallocated or moved more easily (this is
-     particularly useful for bootloaders which need to make
-     adjustments to a device tree based on probed information). You
-     should always generate a structure of the highest version defined
-     at the time of your implementation. Currently that is version 17,
-     unless you explicitly aim at being backward compatible.
-
-   - last_comp_version
-
-     Last compatible version. This indicates down to what version of
-     the DT block you are backward compatible. For example, version 2
-     is backward compatible with version 1 (that is, a kernel build
-     for version 1 will be able to boot with a version 2 format). You
-     should put a 1 in this field if you generate a device tree of
-     version 1 to 3, or 16 if you generate a tree of version 16 or 17
-     using the new unit name format.
-
-   - boot_cpuid_phys
-
-     This field only exist on version 2 headers. It indicate which
-     physical CPU ID is calling the kernel entry point. This is used,
-     among others, by kexec. If you are on an SMP system, this value
-     should match the content of the "reg" property of the CPU node in
-     the device-tree corresponding to the CPU calling the kernel entry
-     point (see further chapters for more informations on the required
-     device-tree contents)
-
-   - size_dt_strings
-
-     This field only exists on version 3 and later headers.  It
-     gives the size of the "strings" section of the device tree (which
-     starts at the offset given by off_dt_strings).
-
-   - size_dt_struct
-
-     This field only exists on version 17 and later headers.  It gives
-     the size of the "structure" section of the device tree (which
-     starts at the offset given by off_dt_struct).
-
-   So the typical layout of a DT block (though the various parts don't
-   need to be in that order) looks like this (addresses go from top to
-   bottom):
-
-
-             ------------------------------
-       r3 -> |  struct boot_param_header  |
-             ------------------------------
-             |      (alignment gap) (*)   |
-             ------------------------------
-             |      memory reserve map    |
-             ------------------------------
-             |      (alignment gap)       |
-             ------------------------------
-             |                            |
-             |    device-tree structure   |
-             |                            |
-             ------------------------------
-             |      (alignment gap)       |
-             ------------------------------
-             |                            |
-             |     device-tree strings    |
-             |                            |
-      -----> ------------------------------
-      |
-      |
-      --- (r3 + totalsize)
-
-  (*) The alignment gaps are not necessarily present; their presence
-      and size are dependent on the various alignment requirements of
-      the individual data blocks.
-
-
-2) Device tree generalities
----------------------------
-
-This device-tree itself is separated in two different blocks, a
-structure block and a strings block. Both need to be aligned to a 4
-byte boundary.
-
-First, let's quickly describe the device-tree concept before detailing
-the storage format. This chapter does _not_ describe the detail of the
-required types of nodes & properties for the kernel, this is done
-later in chapter III.
-
-The device-tree layout is strongly inherited from the definition of
-the Open Firmware IEEE 1275 device-tree. It's basically a tree of
-nodes, each node having two or more named properties. A property can
-have a value or not.
-
-It is a tree, so each node has one and only one parent except for the
-root node who has no parent.
-
-A node has 2 names. The actual node name is generally contained in a
-property of type "name" in the node property list whose value is a
-zero terminated string and is mandatory for version 1 to 3 of the
-format definition (as it is in Open Firmware). Version 16 makes it
-optional as it can generate it from the unit name defined below.
-
-There is also a "unit name" that is used to differentiate nodes with
-the same name at the same level, it is usually made of the node
-names, the "@" sign, and a "unit address", which definition is
-specific to the bus type the node sits on.
-
-The unit name doesn't exist as a property per-se but is included in
-the device-tree structure. It is typically used to represent "path" in
-the device-tree. More details about the actual format of these will be
-below.
-
-The kernel powerpc generic code does not make any formal use of the
-unit address (though some board support code may do) so the only real
-requirement here for the unit address is to ensure uniqueness of
-the node unit name at a given level of the tree. Nodes with no notion
-of address and no possible sibling of the same name (like /memory or
-/cpus) may omit the unit address in the context of this specification,
-or use the "@0" default unit address. The unit name is used to define
-a node "full path", which is the concatenation of all parent node
-unit names separated with "/".
-
-The root node doesn't have a defined name, and isn't required to have
-a name property either if you are using version 3 or earlier of the
-format. It also has no unit address (no @ symbol followed by a unit
-address). The root node unit name is thus an empty string. The full
-path to the root node is "/".
-
-Every node which actually represents an actual device (that is, a node
-which isn't only a virtual "container" for more nodes, like "/cpus"
-is) is also required to have a "device_type" property indicating the
-type of node .
-
-Finally, every node that can be referenced from a property in another
-node is required to have a "linux,phandle" property. Real open
-firmware implementations provide a unique "phandle" value for every
-node that the "prom_init()" trampoline code turns into
-"linux,phandle" properties. However, this is made optional if the
-flattened device tree is used directly. An example of a node
-referencing another node via "phandle" is when laying out the
-interrupt tree which will be described in a further version of this
-document.
-
-This "linux, phandle" property is a 32-bit value that uniquely
-identifies a node. You are free to use whatever values or system of
-values, internal pointers, or whatever to generate these, the only
-requirement is that every node for which you provide that property has
-a unique value for it.
-
-Here is an example of a simple device-tree. In this example, an "o"
-designates a node followed by the node unit name. Properties are
-presented with their name followed by their content. "content"
-represents an ASCII string (zero terminated) value, while <content>
-represents a 32-bit hexadecimal value. The various nodes in this
-example will be discussed in a later chapter. At this point, it is
-only meant to give you a idea of what a device-tree looks like. I have
-purposefully kept the "name" and "linux,phandle" properties which
-aren't necessary in order to give you a better idea of what the tree
-looks like in practice.
-
-  / o device-tree
-      |- name = "device-tree"
-      |- model = "MyBoardName"
-      |- compatible = "MyBoardFamilyName"
-      |- #address-cells = <2>
-      |- #size-cells = <2>
-      |- linux,phandle = <0>
-      |
-      o cpus
-      | | - name = "cpus"
-      | | - linux,phandle = <1>
-      | | - #address-cells = <1>
-      | | - #size-cells = <0>
-      | |
-      | o PowerPC,970@0
-      |   |- name = "PowerPC,970"
-      |   |- device_type = "cpu"
-      |   |- reg = <0>
-      |   |- clock-frequency = <5f5e1000>
-      |   |- 64-bit
-      |   |- linux,phandle = <2>
-      |
-      o memory@0
-      | |- name = "memory"
-      | |- device_type = "memory"
-      | |- reg = <00000000 00000000 00000000 20000000>
-      | |- linux,phandle = <3>
-      |
-      o chosen
-        |- name = "chosen"
-        |- bootargs = "root=/dev/sda2"
-        |- linux,phandle = <4>
-
-This tree is almost a minimal tree. It pretty much contains the
-minimal set of required nodes and properties to boot a linux kernel;
-that is, some basic model informations at the root, the CPUs, and the
-physical memory layout.  It also includes misc information passed
-through /chosen, like in this example, the platform type (mandatory)
-and the kernel command line arguments (optional).
-
-The /cpus/PowerPC,970@0/64-bit property is an example of a
-property without a value. All other properties have a value. The
-significance of the #address-cells and #size-cells properties will be
-explained in chapter IV which defines precisely the required nodes and
-properties and their content.
-
-
-3) Device tree "structure" block
-
-The structure of the device tree is a linearized tree structure. The
-"OF_DT_BEGIN_NODE" token starts a new node, and the "OF_DT_END_NODE"
-ends that node definition. Child nodes are simply defined before
-"OF_DT_END_NODE" (that is nodes within the node). A 'token' is a 32
-bit value. The tree has to be "finished" with a OF_DT_END token
-
-Here's the basic structure of a single node:
-
-     * token OF_DT_BEGIN_NODE (that is 0x00000001)
-     * for version 1 to 3, this is the node full path as a zero
-       terminated string, starting with "/". For version 16 and later,
-       this is the node unit name only (or an empty string for the
-       root node)
-     * [align gap to next 4 bytes boundary]
-     * for each property:
-        * token OF_DT_PROP (that is 0x00000003)
-        * 32-bit value of property value size in bytes (or 0 if no
-          value)
-        * 32-bit value of offset in string block of property name
-        * property value data if any
-        * [align gap to next 4 bytes boundary]
-     * [child nodes if any]
-     * token OF_DT_END_NODE (that is 0x00000002)
-
-So the node content can be summarized as a start token, a full path,
-a list of properties, a list of child nodes, and an end token. Every
-child node is a full node structure itself as defined above.
-
-NOTE: The above definition requires that all property definitions for
-a particular node MUST precede any subnode definitions for that node.
-Although the structure would not be ambiguous if properties and
-subnodes were intermingled, the kernel parser requires that the
-properties come first (up until at least 2.6.22).  Any tools
-manipulating a flattened tree must take care to preserve this
-constraint.
-
-4) Device tree "strings" block
-
-In order to save space, property names, which are generally redundant,
-are stored separately in the "strings" block. This block is simply the
-whole bunch of zero terminated strings for all property names
-concatenated together. The device-tree property definitions in the
-structure block will contain offset values from the beginning of the
-strings block.
-
-
-III - Required content of the device tree
-=========================================
-
-WARNING: All "linux,*" properties defined in this document apply only
-to a flattened device-tree. If your platform uses a real
-implementation of Open Firmware or an implementation compatible with
-the Open Firmware client interface, those properties will be created
-by the trampoline code in the kernel's prom_init() file. For example,
-that's where you'll have to add code to detect your board model and
-set the platform number. However, when using the flattened device-tree
-entry point, there is no prom_init() pass, and thus you have to
-provide those properties yourself.
-
-
-1) Note about cells and address representation
-----------------------------------------------
-
-The general rule is documented in the various Open Firmware
-documentations. If you choose to describe a bus with the device-tree
-and there exist an OF bus binding, then you should follow the
-specification. However, the kernel does not require every single
-device or bus to be described by the device tree.
-
-In general, the format of an address for a device is defined by the
-parent bus type, based on the #address-cells and #size-cells
-properties.  Note that the parent's parent definitions of #address-cells
-and #size-cells are not inherited so every node with children must specify
-them.  The kernel requires the root node to have those properties defining
-addresses format for devices directly mapped on the processor bus.
-
-Those 2 properties define 'cells' for representing an address and a
-size. A "cell" is a 32-bit number. For example, if both contain 2
-like the example tree given above, then an address and a size are both
-composed of 2 cells, and each is a 64-bit number (cells are
-concatenated and expected to be in big endian format). Another example
-is the way Apple firmware defines them, with 2 cells for an address
-and one cell for a size.  Most 32-bit implementations should define
-#address-cells and #size-cells to 1, which represents a 32-bit value.
-Some 32-bit processors allow for physical addresses greater than 32
-bits; these processors should define #address-cells as 2.
-
-"reg" properties are always a tuple of the type "address size" where
-the number of cells of address and size is specified by the bus
-#address-cells and #size-cells. When a bus supports various address
-spaces and other flags relative to a given address allocation (like
-prefetchable, etc...) those flags are usually added to the top level
-bits of the physical address. For example, a PCI physical address is
-made of 3 cells, the bottom two containing the actual address itself
-while the top cell contains address space indication, flags, and pci
-bus & device numbers.
-
-For busses that support dynamic allocation, it's the accepted practice
-to then not provide the address in "reg" (keep it 0) though while
-providing a flag indicating the address is dynamically allocated, and
-then, to provide a separate "assigned-addresses" property that
-contains the fully allocated addresses. See the PCI OF bindings for
-details.
-
-In general, a simple bus with no address space bits and no dynamic
-allocation is preferred if it reflects your hardware, as the existing
-kernel address parsing functions will work out of the box. If you
-define a bus type with a more complex address format, including things
-like address space bits, you'll have to add a bus translator to the
-prom_parse.c file of the recent kernels for your bus type.
-
-The "reg" property only defines addresses and sizes (if #size-cells is
-non-0) within a given bus. In order to translate addresses upward
-(that is into parent bus addresses, and possibly into CPU physical
-addresses), all busses must contain a "ranges" property. If the
-"ranges" property is missing at a given level, it's assumed that
-translation isn't possible, i.e., the registers are not visible on the
-parent bus.  The format of the "ranges" property for a bus is a list
-of:
-
-       bus address, parent bus address, size
-
-"bus address" is in the format of the bus this bus node is defining,
-that is, for a PCI bridge, it would be a PCI address. Thus, (bus
-address, size) defines a range of addresses for child devices. "parent
-bus address" is in the format of the parent bus of this bus. For
-example, for a PCI host controller, that would be a CPU address. For a
-PCI<->ISA bridge, that would be a PCI address. It defines the base
-address in the parent bus where the beginning of that range is mapped.
-
-For a new 64-bit powerpc board, I recommend either the 2/2 format or
-Apple's 2/1 format which is slightly more compact since sizes usually
-fit in a single 32-bit word.   New 32-bit powerpc boards should use a
-1/1 format, unless the processor supports physical addresses greater
-than 32-bits, in which case a 2/1 format is recommended.
-
-Alternatively, the "ranges" property may be empty, indicating that the
-registers are visible on the parent bus using an identity mapping
-translation.  In other words, the parent bus address space is the same
-as the child bus address space.
-
-2) Note about "compatible" properties
--------------------------------------
-
-These properties are optional, but recommended in devices and the root
-node. The format of a "compatible" property is a list of concatenated
-zero terminated strings. They allow a device to express its
-compatibility with a family of similar devices, in some cases,
-allowing a single driver to match against several devices regardless
-of their actual names.
-
-3) Note about "name" properties
--------------------------------
-
-While earlier users of Open Firmware like OldWorld macintoshes tended
-to use the actual device name for the "name" property, it's nowadays
-considered a good practice to use a name that is closer to the device
-class (often equal to device_type). For example, nowadays, ethernet
-controllers are named "ethernet", an additional "model" property
-defining precisely the chip type/model, and "compatible" property
-defining the family in case a single driver can driver more than one
-of these chips. However, the kernel doesn't generally put any
-restriction on the "name" property; it is simply considered good
-practice to follow the standard and its evolutions as closely as
-possible.
-
-Note also that the new format version 16 makes the "name" property
-optional. If it's absent for a node, then the node's unit name is then
-used to reconstruct the name. That is, the part of the unit name
-before the "@" sign is used (or the entire unit name if no "@" sign
-is present).
-
-4) Note about node and property names and character set
--------------------------------------------------------
-
-While open firmware provides more flexible usage of 8859-1, this
-specification enforces more strict rules. Nodes and properties should
-be comprised only of ASCII characters 'a' to 'z', '0' to
-'9', ',', '.', '_', '+', '#', '?', and '-'. Node names additionally
-allow uppercase characters 'A' to 'Z' (property names should be
-lowercase. The fact that vendors like Apple don't respect this rule is
-irrelevant here). Additionally, node and property names should always
-begin with a character in the range 'a' to 'z' (or 'A' to 'Z' for node
-names).
-
-The maximum number of characters for both nodes and property names
-is 31. In the case of node names, this is only the leftmost part of
-a unit name (the pure "name" property), it doesn't include the unit
-address which can extend beyond that limit.
-
-
-5) Required nodes and properties
---------------------------------
-  These are all that are currently required. However, it is strongly
-  recommended that you expose PCI host bridges as documented in the
-  PCI binding to open firmware, and your interrupt tree as documented
-  in OF interrupt tree specification.
-
-  a) The root node
-
-  The root node requires some properties to be present:
-
-    - model : this is your board name/model
-    - #address-cells : address representation for "root" devices
-    - #size-cells: the size representation for "root" devices
-    - device_type : This property shouldn't be necessary. However, if
-      you decide to create a device_type for your root node, make sure it
-      is _not_ "chrp" unless your platform is a pSeries or PAPR compliant
-      one for 64-bit, or a CHRP-type machine for 32-bit as this will
-      matched by the kernel this way.
-
-  Additionally, some recommended properties are:
-
-    - compatible : the board "family" generally finds its way here,
-      for example, if you have 2 board models with a similar layout,
-      that typically get driven by the same platform code in the
-      kernel, you would use a different "model" property but put a
-      value in "compatible". The kernel doesn't directly use that
-      value but it is generally useful.
-
-  The root node is also generally where you add additional properties
-  specific to your board like the serial number if any, that sort of
-  thing. It is recommended that if you add any "custom" property whose
-  name may clash with standard defined ones, you prefix them with your
-  vendor name and a comma.
-
-  b) The /cpus node
-
-  This node is the parent of all individual CPU nodes. It doesn't
-  have any specific requirements, though it's generally good practice
-  to have at least:
-
-               #address-cells = <00000001>
-               #size-cells    = <00000000>
-
-  This defines that the "address" for a CPU is a single cell, and has
-  no meaningful size. This is not necessary but the kernel will assume
-  that format when reading the "reg" properties of a CPU node, see
-  below
-
-  c) The /cpus/* nodes
-
-  So under /cpus, you are supposed to create a node for every CPU on
-  the machine. There is no specific restriction on the name of the
-  CPU, though It's common practice to call it PowerPC,<name>. For
-  example, Apple uses PowerPC,G5 while IBM uses PowerPC,970FX.
-
-  Required properties:
-
-    - device_type : has to be "cpu"
-    - reg : This is the physical CPU number, it's a single 32-bit cell
-      and is also used as-is as the unit number for constructing the
-      unit name in the full path. For example, with 2 CPUs, you would
-      have the full path:
-        /cpus/PowerPC,970FX@0
-        /cpus/PowerPC,970FX@1
-      (unit addresses do not require leading zeroes)
-    - d-cache-block-size : one cell, L1 data cache block size in bytes (*)
-    - i-cache-block-size : one cell, L1 instruction cache block size in
-      bytes
-    - d-cache-size : one cell, size of L1 data cache in bytes
-    - i-cache-size : one cell, size of L1 instruction cache in bytes
-
-(*) The cache "block" size is the size on which the cache management
-instructions operate. Historically, this document used the cache
-"line" size here which is incorrect. The kernel will prefer the cache
-block size and will fallback to cache line size for backward
-compatibility.
-
-  Recommended properties:
-
-    - timebase-frequency : a cell indicating the frequency of the
-      timebase in Hz. This is not directly used by the generic code,
-      but you are welcome to copy/paste the pSeries code for setting
-      the kernel timebase/decrementer calibration based on this
-      value.
-    - clock-frequency : a cell indicating the CPU core clock frequency
-      in Hz. A new property will be defined for 64-bit values, but if
-      your frequency is < 4Ghz, one cell is enough. Here as well as
-      for the above, the common code doesn't use that property, but
-      you are welcome to re-use the pSeries or Maple one. A future
-      kernel version might provide a common function for this.
-    - d-cache-line-size : one cell, L1 data cache line size in bytes
-      if different from the block size
-    - i-cache-line-size : one cell, L1 instruction cache line size in
-      bytes if different from the block size
-
-  You are welcome to add any property you find relevant to your board,
-  like some information about the mechanism used to soft-reset the
-  CPUs. For example, Apple puts the GPIO number for CPU soft reset
-  lines in there as a "soft-reset" property since they start secondary
-  CPUs by soft-resetting them.
-
-
-  d) the /memory node(s)
-
-  To define the physical memory layout of your board, you should
-  create one or more memory node(s). You can either create a single
-  node with all memory ranges in its reg property, or you can create
-  several nodes, as you wish. The unit address (@ part) used for the
-  full path is the address of the first range of memory defined by a
-  given node. If you use a single memory node, this will typically be
-  @0.
-
-  Required properties:
-
-    - device_type : has to be "memory"
-    - reg : This property contains all the physical memory ranges of
-      your board. It's a list of addresses/sizes concatenated
-      together, with the number of cells of each defined by the
-      #address-cells and #size-cells of the root node. For example,
-      with both of these properties being 2 like in the example given
-      earlier, a 970 based machine with 6Gb of RAM could typically
-      have a "reg" property here that looks like:
-
-      00000000 00000000 00000000 80000000
-      00000001 00000000 00000001 00000000
-
-      That is a range starting at 0 of 0x80000000 bytes and a range
-      starting at 0x100000000 and of 0x100000000 bytes. You can see
-      that there is no memory covering the IO hole between 2Gb and
-      4Gb. Some vendors prefer splitting those ranges into smaller
-      segments, but the kernel doesn't care.
-
-  e) The /chosen node
-
-  This node is a bit "special". Normally, that's where open firmware
-  puts some variable environment information, like the arguments, or
-  the default input/output devices.
-
-  This specification makes a few of these mandatory, but also defines
-  some linux-specific properties that would be normally constructed by
-  the prom_init() trampoline when booting with an OF client interface,
-  but that you have to provide yourself when using the flattened format.
-
-  Recommended properties:
-
-    - bootargs : This zero-terminated string is passed as the kernel
-      command line
-    - linux,stdout-path : This is the full path to your standard
-      console device if any. Typically, if you have serial devices on
-      your board, you may want to put the full path to the one set as
-      the default console in the firmware here, for the kernel to pick
-      it up as its own default console. If you look at the function
-      set_preferred_console() in arch/ppc64/kernel/setup.c, you'll see
-      that the kernel tries to find out the default console and has
-      knowledge of various types like 8250 serial ports. You may want
-      to extend this function to add your own.
-
-  Note that u-boot creates and fills in the chosen node for platforms
-  that use it.
-
-  (Note: a practice that is now obsolete was to include a property
-  under /chosen called interrupt-controller which had a phandle value
-  that pointed to the main interrupt controller)
-
-  f) the /soc<SOCname> node
-
-  This node is used to represent a system-on-a-chip (SOC) and must be
-  present if the processor is a SOC. The top-level soc node contains
-  information that is global to all devices on the SOC. The node name
-  should contain a unit address for the SOC, which is the base address
-  of the memory-mapped register set for the SOC. The name of an soc
-  node should start with "soc", and the remainder of the name should
-  represent the part number for the soc.  For example, the MPC8540's
-  soc node would be called "soc8540".
-
-  Required properties:
-
-    - device_type : Should be "soc"
-    - ranges : Should be defined as specified in 1) to describe the
-      translation of SOC addresses for memory mapped SOC registers.
-    - bus-frequency: Contains the bus frequency for the SOC node.
-      Typically, the value of this field is filled in by the boot
-      loader.
-
-
-  Recommended properties:
-
-    - reg : This property defines the address and size of the
-      memory-mapped registers that are used for the SOC node itself.
-      It does not include the child device registers - these will be
-      defined inside each child node.  The address specified in the
-      "reg" property should match the unit address of the SOC node.
-    - #address-cells : Address representation for "soc" devices.  The
-      format of this field may vary depending on whether or not the
-      device registers are memory mapped.  For memory mapped
-      registers, this field represents the number of cells needed to
-      represent the address of the registers.  For SOCs that do not
-      use MMIO, a special address format should be defined that
-      contains enough cells to represent the required information.
-      See 1) above for more details on defining #address-cells.
-    - #size-cells : Size representation for "soc" devices
-    - #interrupt-cells : Defines the width of cells used to represent
-       interrupts.  Typically this value is <2>, which includes a
-       32-bit number that represents the interrupt number, and a
-       32-bit number that represents the interrupt sense and level.
-       This field is only needed if the SOC contains an interrupt
-       controller.
-
-  The SOC node may contain child nodes for each SOC device that the
-  platform uses.  Nodes should not be created for devices which exist
-  on the SOC but are not used by a particular platform. See chapter VI
-  for more information on how to specify devices that are part of a SOC.
-
-  Example SOC node for the MPC8540:
-
-       soc8540@e0000000 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               #interrupt-cells = <2>;
-               device_type = "soc";
-               ranges = <00000000 e0000000 00100000>
-               reg = <e0000000 00003000>;
-               bus-frequency = <0>;
-       }
-
-
-
-IV - "dtc", the device tree compiler
-====================================
-
-
-dtc source code can be found at
-<http://git.jdl.com/gitweb/?p=dtc.git>
-
-WARNING: This version is still in early development stage; the
-resulting device-tree "blobs" have not yet been validated with the
-kernel. The current generated block lacks a useful reserve map (it will
-be fixed to generate an empty one, it's up to the bootloader to fill
-it up) among others. The error handling needs work, bugs are lurking,
-etc...
-
-dtc basically takes a device-tree in a given format and outputs a
-device-tree in another format. The currently supported formats are:
-
-  Input formats:
-  -------------
-
-     - "dtb": "blob" format, that is a flattened device-tree block
-       with
-        header all in a binary blob.
-     - "dts": "source" format. This is a text file containing a
-       "source" for a device-tree. The format is defined later in this
-        chapter.
-     - "fs" format. This is a representation equivalent to the
-        output of /proc/device-tree, that is nodes are directories and
-       properties are files
-
- Output formats:
- ---------------
-
-     - "dtb": "blob" format
-     - "dts": "source" format
-     - "asm": assembly language file. This is a file that can be
-       sourced by gas to generate a device-tree "blob". That file can
-       then simply be added to your Makefile. Additionally, the
-       assembly file exports some symbols that can be used.
-
-
-The syntax of the dtc tool is
-
-    dtc [-I <input-format>] [-O <output-format>]
-        [-o output-filename] [-V output_version] input_filename
-
-
-The "output_version" defines what version of the "blob" format will be
-generated. Supported versions are 1,2,3 and 16. The default is
-currently version 3 but that may change in the future to version 16.
-
-Additionally, dtc performs various sanity checks on the tree, like the
-uniqueness of linux, phandle properties, validity of strings, etc...
-
-The format of the .dts "source" file is "C" like, supports C and C++
-style comments.
-
-/ {
-}
-
-The above is the "device-tree" definition. It's the only statement
-supported currently at the toplevel.
-
-/ {
-  property1 = "string_value";  /* define a property containing a 0
-                                 * terminated string
-                                */
-
-  property2 = <1234abcd>;      /* define a property containing a
-                                 * numerical 32-bit value (hexadecimal)
-                                */
-
-  property3 = <12345678 12345678 deadbeef>;
-                                /* define a property containing 3
-                                 * numerical 32-bit values (cells) in
-                                 * hexadecimal
-                                */
-  property4 = [0a 0b 0c 0d de ea ad be ef];
-                                /* define a property whose content is
-                                 * an arbitrary array of bytes
-                                 */
-
-  childnode@address {  /* define a child node named "childnode"
-                                 * whose unit name is "childnode at
-                                * address"
-                                 */
-
-    childprop = "hello\n";      /* define a property "childprop" of
-                                 * childnode (in this case, a string)
-                                 */
-  };
-};
-
-Nodes can contain other nodes etc... thus defining the hierarchical
-structure of the tree.
-
-Strings support common escape sequences from C: "\n", "\t", "\r",
-"\(octal value)", "\x(hex value)".
-
-It is also suggested that you pipe your source file through cpp (gcc
-preprocessor) so you can use #include's, #define for constants, etc...
-
-Finally, various options are planned but not yet implemented, like
-automatic generation of phandles, labels (exported to the asm file so
-you can point to a property content and change it easily from whatever
-you link the device-tree with), label or path instead of numeric value
-in some cells to "point" to a node (replaced by a phandle at compile
-time), export of reserve map address to the asm file, ability to
-specify reserve map content at compile time, etc...
-
-We may provide a .h include file with common definitions of that
-proves useful for some properties (like building PCI properties or
-interrupt maps) though it may be better to add a notion of struct
-definitions to the compiler...
-
-
-V - Recommendations for a bootloader
-====================================
-
-
-Here are some various ideas/recommendations that have been proposed
-while all this has been defined and implemented.
-
-  - The bootloader may want to be able to use the device-tree itself
-    and may want to manipulate it (to add/edit some properties,
-    like physical memory size or kernel arguments). At this point, 2
-    choices can be made. Either the bootloader works directly on the
-    flattened format, or the bootloader has its own internal tree
-    representation with pointers (similar to the kernel one) and
-    re-flattens the tree when booting the kernel. The former is a bit
-    more difficult to edit/modify, the later requires probably a bit
-    more code to handle the tree structure. Note that the structure
-    format has been designed so it's relatively easy to "insert"
-    properties or nodes or delete them by just memmoving things
-    around. It contains no internal offsets or pointers for this
-    purpose.
-
-  - An example of code for iterating nodes & retrieving properties
-    directly from the flattened tree format can be found in the kernel
-    file arch/ppc64/kernel/prom.c, look at scan_flat_dt() function,
-    its usage in early_init_devtree(), and the corresponding various
-    early_init_dt_scan_*() callbacks. That code can be re-used in a
-    GPL bootloader, and as the author of that code, I would be happy
-    to discuss possible free licensing to any vendor who wishes to
-    integrate all or part of this code into a non-GPL bootloader.
-
-
-
-VI - System-on-a-chip devices and nodes
-=======================================
-
-Many companies are now starting to develop system-on-a-chip
-processors, where the processor core (CPU) and many peripheral devices
-exist on a single piece of silicon.  For these SOCs, an SOC node
-should be used that defines child nodes for the devices that make
-up the SOC. While platforms are not required to use this model in
-order to boot the kernel, it is highly encouraged that all SOC
-implementations define as complete a flat-device-tree as possible to
-describe the devices on the SOC.  This will allow for the
-genericization of much of the kernel code.
-
-
-1) Defining child nodes of an SOC
----------------------------------
-
-Each device that is part of an SOC may have its own node entry inside
-the SOC node.  For each device that is included in the SOC, the unit
-address property represents the address offset for this device's
-memory-mapped registers in the parent's address space.  The parent's
-address space is defined by the "ranges" property in the top-level soc
-node. The "reg" property for each node that exists directly under the
-SOC node should contain the address mapping from the child address space
-to the parent SOC address space and the size of the device's
-memory-mapped register file.
-
-For many devices that may exist inside an SOC, there are predefined
-specifications for the format of the device tree node.  All SOC child
-nodes should follow these specifications, except where noted in this
-document.
-
-See appendix A for an example partial SOC node definition for the
-MPC8540.
-
-
-2) Representing devices without a current OF specification
-----------------------------------------------------------
-
-Currently, there are many devices on SOCs that do not have a standard
-representation pre-defined as part of the open firmware
-specifications, mainly because the boards that contain these SOCs are
-not currently booted using open firmware.   This section contains
-descriptions for the SOC devices for which new nodes have been
-defined; this list will expand as more and more SOC-containing
-platforms are moved over to use the flattened-device-tree model.
-
-VII - Specifying interrupt information for devices
-===================================================
-
-The device tree represents the busses and devices of a hardware
-system in a form similar to the physical bus topology of the
-hardware.
-
-In addition, a logical 'interrupt tree' exists which represents the
-hierarchy and routing of interrupts in the hardware.
-
-The interrupt tree model is fully described in the
-document "Open Firmware Recommended Practice: Interrupt
-Mapping Version 0.9".  The document is available at:
-<http://playground.sun.com/1275/practice>.
-
-1) interrupts property
-----------------------
-
-Devices that generate interrupts to a single interrupt controller
-should use the conventional OF representation described in the
-OF interrupt mapping documentation.
-
-Each device which generates interrupts must have an 'interrupt'
-property.  The interrupt property value is an arbitrary number of
-of 'interrupt specifier' values which describe the interrupt or
-interrupts for the device.
-
-The encoding of an interrupt specifier is determined by the
-interrupt domain in which the device is located in the
-interrupt tree.  The root of an interrupt domain specifies in
-its #interrupt-cells property the number of 32-bit cells
-required to encode an interrupt specifier.  See the OF interrupt
-mapping documentation for a detailed description of domains.
-
-For example, the binding for the OpenPIC interrupt controller
-specifies  an #interrupt-cells value of 2 to encode the interrupt
-number and level/sense information. All interrupt children in an
-OpenPIC interrupt domain use 2 cells per interrupt in their interrupts
-property.
-
-The PCI bus binding specifies a #interrupt-cell value of 1 to encode
-which interrupt pin (INTA,INTB,INTC,INTD) is used.
-
-2) interrupt-parent property
-----------------------------
-
-The interrupt-parent property is specified to define an explicit
-link between a device node and its interrupt parent in
-the interrupt tree.  The value of interrupt-parent is the
-phandle of the parent node.
-
-If the interrupt-parent property is not defined for a node, its
-interrupt parent is assumed to be an ancestor in the node's
-_device tree_ hierarchy.
-
-3) OpenPIC Interrupt Controllers
---------------------------------
-
-OpenPIC interrupt controllers require 2 cells to encode
-interrupt information.  The first cell defines the interrupt
-number.  The second cell defines the sense and level
-information.
-
-Sense and level information should be encoded as follows:
-
-       0 = low to high edge sensitive type enabled
-       1 = active low level sensitive type enabled
-       2 = active high level sensitive type enabled
-       3 = high to low edge sensitive type enabled
-
-4) ISA Interrupt Controllers
-----------------------------
-
-ISA PIC interrupt controllers require 2 cells to encode
-interrupt information.  The first cell defines the interrupt
-number.  The second cell defines the sense and level
-information.
-
-ISA PIC interrupt controllers should adhere to the ISA PIC
-encodings listed below:
-
-       0 =  active low level sensitive type enabled
-       1 =  active high level sensitive type enabled
-       2 =  high to low edge sensitive type enabled
-       3 =  low to high edge sensitive type enabled
-
-VIII - Specifying Device Power Management Information (sleep property)
-===================================================================
-
-Devices on SOCs often have mechanisms for placing devices into low-power
-states that are decoupled from the devices' own register blocks.  Sometimes,
-this information is more complicated than a cell-index property can
-reasonably describe.  Thus, each device controlled in such a manner
-may contain a "sleep" property which describes these connections.
-
-The sleep property consists of one or more sleep resources, each of
-which consists of a phandle to a sleep controller, followed by a
-controller-specific sleep specifier of zero or more cells.
-
-The semantics of what type of low power modes are possible are defined
-by the sleep controller.  Some examples of the types of low power modes
-that may be supported are:
-
- - Dynamic: The device may be disabled or enabled at any time.
- - System Suspend: The device may request to be disabled or remain
-   awake during system suspend, but will not be disabled until then.
- - Permanent: The device is disabled permanently (until the next hard
-   reset).
-
-Some devices may share a clock domain with each other, such that they should
-only be suspended when none of the devices are in use.  Where reasonable,
-such nodes should be placed on a virtual bus, where the bus has the sleep
-property.  If the clock domain is shared among devices that cannot be
-reasonably grouped in this manner, then create a virtual sleep controller
-(similar to an interrupt nexus, except that defining a standardized
-sleep-map should wait until its necessity is demonstrated).
-
-Appendix A - Sample SOC node for MPC8540
-========================================
-
-       soc@e0000000 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "fsl,mpc8540-ccsr", "simple-bus";
-               device_type = "soc";
-               ranges = <0x00000000 0xe0000000 0x00100000>
-               bus-frequency = <0>;
-               interrupt-parent = <&pic>;
-
-               ethernet@24000 {
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       device_type = "network";
-                       model = "TSEC";
-                       compatible = "gianfar", "simple-bus";
-                       reg = <0x24000 0x1000>;
-                       local-mac-address = [ 00 E0 0C 00 73 00 ];
-                       interrupts = <29 2 30 2 34 2>;
-                       phy-handle = <&phy0>;
-                       sleep = <&pmc 00000080>;
-                       ranges;
-
-                       mdio@24520 {
-                               reg = <0x24520 0x20>;
-                               compatible = "fsl,gianfar-mdio";
-
-                               phy0: ethernet-phy@0 {
-                                       interrupts = <5 1>;
-                                       reg = <0>;
-                                       device_type = "ethernet-phy";
-                               };
-
-                               phy1: ethernet-phy@1 {
-                                       interrupts = <5 1>;
-                                       reg = <1>;
-                                       device_type = "ethernet-phy";
-                               };
-
-                               phy3: ethernet-phy@3 {
-                                       interrupts = <7 1>;
-                                       reg = <3>;
-                                       device_type = "ethernet-phy";
-                               };
-                       };
-               };
-
-               ethernet@25000 {
-                       device_type = "network";
-                       model = "TSEC";
-                       compatible = "gianfar";
-                       reg = <0x25000 0x1000>;
-                       local-mac-address = [ 00 E0 0C 00 73 01 ];
-                       interrupts = <13 2 14 2 18 2>;
-                       phy-handle = <&phy1>;
-                       sleep = <&pmc 00000040>;
-               };
-
-               ethernet@26000 {
-                       device_type = "network";
-                       model = "FEC";
-                       compatible = "gianfar";
-                       reg = <0x26000 0x1000>;
-                       local-mac-address = [ 00 E0 0C 00 73 02 ];
-                       interrupts = <41 2>;
-                       phy-handle = <&phy3>;
-                       sleep = <&pmc 00000020>;
-               };
-
-               serial@4500 {
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       compatible = "fsl,mpc8540-duart", "simple-bus";
-                       sleep = <&pmc 00000002>;
-                       ranges;
-
-                       serial@4500 {
-                               device_type = "serial";
-                               compatible = "ns16550";
-                               reg = <0x4500 0x100>;
-                               clock-frequency = <0>;
-                               interrupts = <42 2>;
-                       };
-
-                       serial@4600 {
-                               device_type = "serial";
-                               compatible = "ns16550";
-                               reg = <0x4600 0x100>;
-                               clock-frequency = <0>;
-                               interrupts = <42 2>;
-                       };
-               };
-
-               pic: pic@40000 {
-                       interrupt-controller;
-                       #address-cells = <0>;
-                       #interrupt-cells = <2>;
-                       reg = <0x40000 0x40000>;
-                       compatible = "chrp,open-pic";
-                       device_type = "open-pic";
-               };
-
-               i2c@3000 {
-                       interrupts = <43 2>;
-                       reg = <0x3000 0x100>;
-                       compatible  = "fsl-i2c";
-                       dfsrr;
-                       sleep = <&pmc 00000004>;
-               };
-
-               pmc: power@e0070 {
-                       compatible = "fsl,mpc8540-pmc", "fsl,mpc8548-pmc";
-                       reg = <0xe0070 0x20>;
-               };
-       };
diff --git a/Documentation/powerpc/dts-bindings/4xx/cpm.txt b/Documentation/powerpc/dts-bindings/4xx/cpm.txt
deleted file mode 100644 (file)
index ee45980..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-PPC4xx Clock Power Management (CPM) node
-
-Required properties:
-       - compatible            : compatible list, currently only "ibm,cpm"
-       - dcr-access-method     : "native"
-       - dcr-reg               : < DCR register range >
-
-Optional properties:
-       - er-offset             : All 4xx SoCs with a CPM controller have
-                                 one of two different order for the CPM
-                                 registers. Some have the CPM registers
-                                 in the following order (ER,FR,SR). The
-                                 others have them in the following order
-                                 (SR,ER,FR). For the second case set
-                                 er-offset = <1>.
-       - unused-units          : specifier consist of one cell. For each
-                                 bit in the cell, the corresponding bit
-                                 in CPM will be set to turn off unused
-                                 devices.
-       - idle-doze             : specifier consist of one cell. For each
-                                 bit in the cell, the corresponding bit
-                                 in CPM will be set to turn off unused
-                                 devices. This is usually just CPM[CPU].
-       - standby               : specifier consist of one cell. For each
-                                 bit in the cell, the corresponding bit
-                                 in CPM will be set on standby and
-                                 restored on resume.
-       - suspend               : specifier consist of one cell. For each
-                                 bit in the cell, the corresponding bit
-                                 in CPM will be set on suspend (mem) and
-                                 restored on resume. Note, for standby
-                                 and suspend the corresponding bits can
-                                 be different or the same. Usually for
-                                 standby only class 2 and 3 units are set.
-                                 However, the interface does not care.
-                                 If they are the same, the additional
-                                 power saving will be seeing if support
-                                 is available to put the DDR in self
-                                 refresh mode and any additional power
-                                 saving techniques for the specific SoC.
-
-Example:
-       CPM0: cpm {
-               compatible = "ibm,cpm";
-               dcr-access-method = "native";
-               dcr-reg = <0x160 0x003>;
-               er-offset = <0>;
-               unused-units = <0x00000100>;
-               idle-doze = <0x02000000>;
-               standby = <0xfeff0000>;
-               suspend = <0xfeff791d>;
-};
diff --git a/Documentation/powerpc/dts-bindings/4xx/emac.txt b/Documentation/powerpc/dts-bindings/4xx/emac.txt
deleted file mode 100644 (file)
index 2161334..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-    4xx/Axon EMAC ethernet nodes
-
-    The EMAC ethernet controller in IBM and AMCC 4xx chips, and also
-    the Axon bridge.  To operate this needs to interact with a ths
-    special McMAL DMA controller, and sometimes an RGMII or ZMII
-    interface.  In addition to the nodes and properties described
-    below, the node for the OPB bus on which the EMAC sits must have a
-    correct clock-frequency property.
-
-      i) The EMAC node itself
-
-    Required properties:
-    - device_type       : "network"
-
-    - compatible        : compatible list, contains 2 entries, first is
-                         "ibm,emac-CHIP" where CHIP is the host ASIC (440gx,
-                         405gp, Axon) and second is either "ibm,emac" or
-                         "ibm,emac4".  For Axon, thus, we have: "ibm,emac-axon",
-                         "ibm,emac4"
-    - interrupts        : <interrupt mapping for EMAC IRQ and WOL IRQ>
-    - interrupt-parent  : optional, if needed for interrupt mapping
-    - reg               : <registers mapping>
-    - local-mac-address : 6 bytes, MAC address
-    - mal-device        : phandle of the associated McMAL node
-    - mal-tx-channel    : 1 cell, index of the tx channel on McMAL associated
-                         with this EMAC
-    - mal-rx-channel    : 1 cell, index of the rx channel on McMAL associated
-                         with this EMAC
-    - cell-index        : 1 cell, hardware index of the EMAC cell on a given
-                         ASIC (typically 0x0 and 0x1 for EMAC0 and EMAC1 on
-                         each Axon chip)
-    - max-frame-size    : 1 cell, maximum frame size supported in bytes
-    - rx-fifo-size      : 1 cell, Rx fifo size in bytes for 10 and 100 Mb/sec
-                         operations.
-                         For Axon, 2048
-    - tx-fifo-size      : 1 cell, Tx fifo size in bytes for 10 and 100 Mb/sec
-                         operations.
-                         For Axon, 2048.
-    - fifo-entry-size   : 1 cell, size of a fifo entry (used to calculate
-                         thresholds).
-                         For Axon, 0x00000010
-    - mal-burst-size    : 1 cell, MAL burst size (used to calculate thresholds)
-                         in bytes.
-                         For Axon, 0x00000100 (I think ...)
-    - phy-mode          : string, mode of operations of the PHY interface.
-                         Supported values are: "mii", "rmii", "smii", "rgmii",
-                         "tbi", "gmii", rtbi", "sgmii".
-                         For Axon on CAB, it is "rgmii"
-    - mdio-device       : 1 cell, required iff using shared MDIO registers
-                         (440EP).  phandle of the EMAC to use to drive the
-                         MDIO lines for the PHY used by this EMAC.
-    - zmii-device       : 1 cell, required iff connected to a ZMII.  phandle of
-                         the ZMII device node
-    - zmii-channel      : 1 cell, required iff connected to a ZMII.  Which ZMII
-                         channel or 0xffffffff if ZMII is only used for MDIO.
-    - rgmii-device      : 1 cell, required iff connected to an RGMII. phandle
-                         of the RGMII device node.
-                         For Axon: phandle of plb5/plb4/opb/rgmii
-    - rgmii-channel     : 1 cell, required iff connected to an RGMII.  Which
-                         RGMII channel is used by this EMAC.
-                         Fox Axon: present, whatever value is appropriate for each
-                         EMAC, that is the content of the current (bogus) "phy-port"
-                         property.
-
-    Optional properties:
-    - phy-address       : 1 cell, optional, MDIO address of the PHY. If absent,
-                         a search is performed.
-    - phy-map           : 1 cell, optional, bitmap of addresses to probe the PHY
-                         for, used if phy-address is absent. bit 0x00000001 is
-                         MDIO address 0.
-                         For Axon it can be absent, though my current driver
-                         doesn't handle phy-address yet so for now, keep
-                         0x00ffffff in it.
-    - rx-fifo-size-gige : 1 cell, Rx fifo size in bytes for 1000 Mb/sec
-                         operations (if absent the value is the same as
-                         rx-fifo-size).  For Axon, either absent or 2048.
-    - tx-fifo-size-gige : 1 cell, Tx fifo size in bytes for 1000 Mb/sec
-                         operations (if absent the value is the same as
-                         tx-fifo-size). For Axon, either absent or 2048.
-    - tah-device        : 1 cell, optional. If connected to a TAH engine for
-                         offload, phandle of the TAH device node.
-    - tah-channel       : 1 cell, optional. If appropriate, channel used on the
-                         TAH engine.
-
-    Example:
-
-       EMAC0: ethernet@40000800 {
-               device_type = "network";
-               compatible = "ibm,emac-440gp", "ibm,emac";
-               interrupt-parent = <&UIC1>;
-               interrupts = <1c 4 1d 4>;
-               reg = <40000800 70>;
-               local-mac-address = [00 04 AC E3 1B 1E];
-               mal-device = <&MAL0>;
-               mal-tx-channel = <0 1>;
-               mal-rx-channel = <0>;
-               cell-index = <0>;
-               max-frame-size = <5dc>;
-               rx-fifo-size = <1000>;
-               tx-fifo-size = <800>;
-               phy-mode = "rmii";
-               phy-map = <00000001>;
-               zmii-device = <&ZMII0>;
-               zmii-channel = <0>;
-       };
-
-      ii) McMAL node
-
-    Required properties:
-    - device_type        : "dma-controller"
-    - compatible         : compatible list, containing 2 entries, first is
-                          "ibm,mcmal-CHIP" where CHIP is the host ASIC (like
-                          emac) and the second is either "ibm,mcmal" or
-                          "ibm,mcmal2".
-                          For Axon, "ibm,mcmal-axon","ibm,mcmal2"
-    - interrupts         : <interrupt mapping for the MAL interrupts sources:
-                           5 sources: tx_eob, rx_eob, serr, txde, rxde>.
-                           For Axon: This is _different_ from the current
-                          firmware.  We use the "delayed" interrupts for txeob
-                          and rxeob. Thus we end up with mapping those 5 MPIC
-                          interrupts, all level positive sensitive: 10, 11, 32,
-                          33, 34 (in decimal)
-    - dcr-reg            : < DCR registers range >
-    - dcr-parent         : if needed for dcr-reg
-    - num-tx-chans       : 1 cell, number of Tx channels
-    - num-rx-chans       : 1 cell, number of Rx channels
-
-      iii) ZMII node
-
-    Required properties:
-    - compatible         : compatible list, containing 2 entries, first is
-                          "ibm,zmii-CHIP" where CHIP is the host ASIC (like
-                          EMAC) and the second is "ibm,zmii".
-                          For Axon, there is no ZMII node.
-    - reg                : <registers mapping>
-
-      iv) RGMII node
-
-    Required properties:
-    - compatible         : compatible list, containing 2 entries, first is
-                          "ibm,rgmii-CHIP" where CHIP is the host ASIC (like
-                          EMAC) and the second is "ibm,rgmii".
-                           For Axon, "ibm,rgmii-axon","ibm,rgmii"
-    - reg                : <registers mapping>
-    - revision           : as provided by the RGMII new version register if
-                          available.
-                          For Axon: 0x0000012a
-
diff --git a/Documentation/powerpc/dts-bindings/4xx/ndfc.txt b/Documentation/powerpc/dts-bindings/4xx/ndfc.txt
deleted file mode 100644 (file)
index 869f0b5..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-AMCC NDFC (NanD Flash Controller)
-
-Required properties:
-- compatible : "ibm,ndfc".
-- reg : should specify chip select and size used for the chip (0x2000).
-
-Optional properties:
-- ccr : NDFC config and control register value (default 0).
-- bank-settings : NDFC bank configuration register value (default 0).
-
-Notes:
-- partition(s) - follows the OF MTD standard for partitions
-
-Example:
-
-ndfc@1,0 {
-       compatible = "ibm,ndfc";
-       reg = <0x00000001 0x00000000 0x00002000>;
-       ccr = <0x00001000>;
-       bank-settings = <0x80002222>;
-       #address-cells = <1>;
-       #size-cells = <1>;
-
-       nand {
-               #address-cells = <1>;
-               #size-cells = <1>;
-
-               partition@0 {
-                       label = "kernel";
-                       reg = <0x00000000 0x00200000>;
-               };
-               partition@200000 {
-                       label = "root";
-                       reg = <0x00200000 0x03E00000>;
-               };
-       };
-};
-
-
diff --git a/Documentation/powerpc/dts-bindings/4xx/ppc440spe-adma.txt b/Documentation/powerpc/dts-bindings/4xx/ppc440spe-adma.txt
deleted file mode 100644 (file)
index 515ebcf..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-PPC440SPe DMA/XOR (DMA Controller and XOR Accelerator)
-
-Device nodes needed for operation of the ppc440spe-adma driver
-are specified hereby. These are I2O/DMA, DMA and XOR nodes
-for DMA engines and Memory Queue Module node. The latter is used
-by ADMA driver for configuration of RAID-6 H/W capabilities of
-the PPC440SPe. In addition to the nodes and properties described
-below, the ranges property of PLB node must specify ranges for
-DMA devices.
-
- i) The I2O node
-
- Required properties:
-
- - compatible          : "ibm,i2o-440spe";
- - reg                 : <registers mapping>
- - dcr-reg             : <DCR registers range>
-
- Example:
-
-       I2O: i2o@400100000 {
-               compatible = "ibm,i2o-440spe";
-               reg = <0x00000004 0x00100000 0x100>;
-               dcr-reg = <0x060 0x020>;
-       };
-
-
- ii) The DMA node
-
- Required properties:
-
- - compatible          : "ibm,dma-440spe";
- - cell-index          : 1 cell, hardware index of the DMA engine
-                         (typically 0x0 and 0x1 for DMA0 and DMA1)
- - reg                 : <registers mapping>
- - dcr-reg             : <DCR registers range>
- - interrupts          : <interrupt mapping for DMA0/1 interrupts sources:
-                          2 sources: DMAx CS FIFO Needs Service IRQ (on UIC0)
-                          and DMA Error IRQ (on UIC1). The latter is common
-                          for both DMA engines>.
- - interrupt-parent    : needed for interrupt mapping
-
- Example:
-
-       DMA0: dma0@400100100 {
-               compatible = "ibm,dma-440spe";
-               cell-index = <0>;
-               reg = <0x00000004 0x00100100 0x100>;
-               dcr-reg = <0x060 0x020>;
-               interrupt-parent = <&DMA0>;
-               interrupts = <0 1>;
-               #interrupt-cells = <1>;
-               #address-cells = <0>;
-               #size-cells = <0>;
-               interrupt-map = <
-                       0 &UIC0 0x14 4
-                       1 &UIC1 0x16 4>;
-       };
-
-
- iii) XOR Accelerator node
-
- Required properties:
-
- - compatible          : "amcc,xor-accelerator";
- - reg                 : <registers mapping>
- - interrupts          : <interrupt mapping for XOR interrupt source>
- - interrupt-parent    : for interrupt mapping
-
- Example:
-
-       xor-accel@400200000 {
-               compatible = "amcc,xor-accelerator";
-               reg = <0x00000004 0x00200000 0x400>;
-               interrupt-parent = <&UIC1>;
-               interrupts = <0x1f 4>;
-       };
-
-
- iv) Memory Queue Module node
-
- Required properties:
-
- - compatible          : "ibm,mq-440spe";
- - dcr-reg             : <DCR registers range>
-
- Example:
-
-       MQ0: mq {
-               compatible = "ibm,mq-440spe";
-               dcr-reg = <0x040 0x020>;
-       };
-
diff --git a/Documentation/powerpc/dts-bindings/4xx/reboot.txt b/Documentation/powerpc/dts-bindings/4xx/reboot.txt
deleted file mode 100644 (file)
index d721726..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-Reboot property to control system reboot on PPC4xx systems:
-
-By setting "reset_type" to one of the following values, the default
-software reset mechanism may be overidden. Here the possible values of
-"reset_type":
-
-      1 - PPC4xx core reset
-      2 - PPC4xx chip reset
-      3 - PPC4xx system reset (default)
-
-Example:
-
-               cpu@0 {
-                       device_type = "cpu";
-                       model = "PowerPC,440SPe";
-                       ...
-                       reset-type = <2>;       /* Use chip-reset */
-               };
diff --git a/Documentation/powerpc/dts-bindings/can/sja1000.txt b/Documentation/powerpc/dts-bindings/can/sja1000.txt
deleted file mode 100644 (file)
index d6d209d..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-Memory mapped SJA1000 CAN controller from NXP (formerly Philips)
-
-Required properties:
-
-- compatible : should be "nxp,sja1000".
-
-- reg : should specify the chip select, address offset and size required
-       to map the registers of the SJA1000. The size is usually 0x80.
-
-- interrupts: property with a value describing the interrupt source
-       (number and sensitivity) required for the SJA1000.
-
-Optional properties:
-
-- nxp,external-clock-frequency : Frequency of the external oscillator
-       clock in Hz. Note that the internal clock frequency used by the
-       SJA1000 is half of that value. If not specified, a default value
-       of 16000000 (16 MHz) is used.
-
-- nxp,tx-output-mode : operation mode of the TX output control logic:
-       <0x0> : bi-phase output mode
-       <0x1> : normal output mode (default)
-       <0x2> : test output mode
-       <0x3> : clock output mode
-
-- nxp,tx-output-config : TX output pin configuration:
-       <0x01> : TX0 invert
-       <0x02> : TX0 pull-down (default)
-       <0x04> : TX0 pull-up
-       <0x06> : TX0 push-pull
-       <0x08> : TX1 invert
-       <0x10> : TX1 pull-down
-       <0x20> : TX1 pull-up
-       <0x30> : TX1 push-pull
-
-- nxp,clock-out-frequency : clock frequency in Hz on the CLKOUT pin.
-       If not specified or if the specified value is 0, the CLKOUT pin
-       will be disabled.
-
-- nxp,no-comparator-bypass : Allows to disable the CAN input comperator.
-
-For futher information, please have a look to the SJA1000 data sheet.
-
-Examples:
-
-can@3,100 {
-       compatible = "nxp,sja1000";
-       reg = <3 0x100 0x80>;
-       interrupts = <2 0>;
-       interrupt-parent = <&mpic>;
-       nxp,external-clock-frequency = <16000000>;
-};
-
diff --git a/Documentation/powerpc/dts-bindings/ecm.txt b/Documentation/powerpc/dts-bindings/ecm.txt
deleted file mode 100644 (file)
index f514f29..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-=====================================================================
-E500 LAW & Coherency Module Device Tree Binding
-Copyright (C) 2009 Freescale Semiconductor Inc.
-=====================================================================
-
-Local Access Window (LAW) Node
-
-The LAW node represents the region of CCSR space where local access
-windows are configured.  For ECM based devices this is the first 4k
-of CCSR space that includes CCSRBAR, ALTCBAR, ALTCAR, BPTR, and some
-number of local access windows as specified by fsl,num-laws.
-
-PROPERTIES
-
-  - compatible
-      Usage: required
-      Value type: <string>
-      Definition: Must include "fsl,ecm-law"
-
-  - reg
-      Usage: required
-      Value type: <prop-encoded-array>
-      Definition: A standard property.  The value specifies the
-          physical address offset and length of the CCSR space
-          registers.
-
-  - fsl,num-laws
-      Usage: required
-      Value type: <u32>
-      Definition: The value specifies the number of local access
-          windows for this device.
-
-=====================================================================
-
-E500 Coherency Module Node
-
-The E500 LAW node represents the region of CCSR space where ECM config
-and error reporting registers exist, this is the second 4k (0x1000)
-of CCSR space.
-
-PROPERTIES
-
-  - compatible
-      Usage: required
-      Value type: <string>
-      Definition: Must include "fsl,CHIP-ecm", "fsl,ecm" where
-      CHIP is the processor (mpc8572, mpc8544, etc.)
-
-  - reg
-      Usage: required
-      Value type: <prop-encoded-array>
-      Definition: A standard property.  The value specifies the
-          physical address offset and length of the CCSR space
-          registers.
-
-   - interrupts
-      Usage: required
-      Value type: <prop-encoded-array>
-
-   - interrupt-parent
-      Usage: required
-      Value type: <phandle>
-
-=====================================================================
diff --git a/Documentation/powerpc/dts-bindings/eeprom.txt b/Documentation/powerpc/dts-bindings/eeprom.txt
deleted file mode 100644 (file)
index 4342c10..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-EEPROMs (I2C)
-
-Required properties:
-
-  - compatible : should be "<manufacturer>,<type>"
-                If there is no specific driver for <manufacturer>, a generic
-                driver based on <type> is selected. Possible types are:
-                24c00, 24c01, 24c02, 24c04, 24c08, 24c16, 24c32, 24c64,
-                24c128, 24c256, 24c512, 24c1024, spd
-
-  - reg : the I2C address of the EEPROM
-
-Optional properties:
-
-  - pagesize : the length of the pagesize for writing. Please consult the
-               manual of your device, that value varies a lot. A wrong value
-              may result in data loss! If not specified, a safety value of
-              '1' is used which will be very slow.
-
-  - read-only: this parameterless property disables writes to the eeprom
-
-Example:
-
-eeprom@52 {
-       compatible = "atmel,24c32";
-       reg = <0x52>;
-       pagesize = <32>;
-};
diff --git a/Documentation/powerpc/dts-bindings/fsl/83xx-512x-pci.txt b/Documentation/powerpc/dts-bindings/fsl/83xx-512x-pci.txt
deleted file mode 100644 (file)
index 35a4653..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-* Freescale 83xx and 512x PCI bridges
-
-Freescale 83xx and 512x SOCs include the same pci bridge core.
-
-83xx/512x specific notes:
-- reg: should contain two address length tuples
-    The first is for the internal pci bridge registers
-    The second is for the pci config space access registers
-
-Example (MPC8313ERDB)
-       pci0: pci@e0008500 {
-               cell-index = <1>;
-               interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
-               interrupt-map = <
-                               /* IDSEL 0x0E -mini PCI */
-                                0x7000 0x0 0x0 0x1 &ipic 18 0x8
-                                0x7000 0x0 0x0 0x2 &ipic 18 0x8
-                                0x7000 0x0 0x0 0x3 &ipic 18 0x8
-                                0x7000 0x0 0x0 0x4 &ipic 18 0x8
-
-                               /* IDSEL 0x0F - PCI slot */
-                                0x7800 0x0 0x0 0x1 &ipic 17 0x8
-                                0x7800 0x0 0x0 0x2 &ipic 18 0x8
-                                0x7800 0x0 0x0 0x3 &ipic 17 0x8
-                                0x7800 0x0 0x0 0x4 &ipic 18 0x8>;
-               interrupt-parent = <&ipic>;
-               interrupts = <66 0x8>;
-               bus-range = <0x0 0x0>;
-               ranges = <0x02000000 0x0 0x90000000 0x90000000 0x0 0x10000000
-                         0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000
-                         0x01000000 0x0 0x00000000 0xe2000000 0x0 0x00100000>;
-               clock-frequency = <66666666>;
-               #interrupt-cells = <1>;
-               #size-cells = <2>;
-               #address-cells = <3>;
-               reg = <0xe0008500 0x100         /* internal registers */
-                      0xe0008300 0x8>;         /* config space access registers */
-               compatible = "fsl,mpc8349-pci";
-               device_type = "pci";
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/8xxx_gpio.txt b/Documentation/powerpc/dts-bindings/fsl/8xxx_gpio.txt
deleted file mode 100644 (file)
index b0019eb..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-GPIO controllers on MPC8xxx SoCs
-
-This is for the non-QE/CPM/GUTs GPIO controllers as found on
-8349, 8572, 8610 and compatible.
-
-Every GPIO controller node must have #gpio-cells property defined,
-this information will be used to translate gpio-specifiers.
-
-Required properties:
-- compatible : "fsl,<CHIP>-gpio" followed by "fsl,mpc8349-gpio" for
-  83xx, "fsl,mpc8572-gpio" for 85xx and "fsl,mpc8610-gpio" for 86xx.
-- #gpio-cells : Should be two. The first cell is the pin number and the
-  second cell is used to specify optional parameters (currently unused).
- - interrupts : Interrupt mapping for GPIO IRQ.
- - interrupt-parent : Phandle for the interrupt controller that
-   services interrupts for this device.
-- gpio-controller : Marks the port as GPIO controller.
-
-Example of gpio-controller nodes for a MPC8347 SoC:
-
-       gpio1: gpio-controller@c00 {
-               #gpio-cells = <2>;
-               compatible = "fsl,mpc8347-gpio", "fsl,mpc8349-gpio";
-               reg = <0xc00 0x100>;
-               interrupts = <74 0x8>;
-               interrupt-parent = <&ipic>;
-               gpio-controller;
-       };
-
-       gpio2: gpio-controller@d00 {
-               #gpio-cells = <2>;
-               compatible = "fsl,mpc8347-gpio", "fsl,mpc8349-gpio";
-               reg = <0xd00 0x100>;
-               interrupts = <75 0x8>;
-               interrupt-parent = <&ipic>;
-               gpio-controller;
-       };
-
-See booting-without-of.txt for details of how to specify GPIO
-information for devices.
-
-To use GPIO pins as interrupt sources for peripherals, specify the
-GPIO controller as the interrupt parent and define GPIO number +
-trigger mode using the interrupts property, which is defined like
-this:
-
-interrupts = <number trigger>, where:
- - number: GPIO pin (0..31)
- - trigger: trigger mode:
-       2 = trigger on falling edge
-       3 = trigger on both edges
-
-Example of device using this is:
-
-       funkyfpga@0 {
-               compatible = "funky-fpga";
-               ...
-               interrupts = <4 3>;
-               interrupt-parent = <&gpio1>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/board.txt b/Documentation/powerpc/dts-bindings/fsl/board.txt
deleted file mode 100644 (file)
index 39e9415..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-* Board Control and Status (BCSR)
-
-Required properties:
-
- - compatible : Should be "fsl,<board>-bcsr"
- - reg : Offset and length of the register set for the device
-
-Example:
-
-       bcsr@f8000000 {
-               compatible = "fsl,mpc8360mds-bcsr";
-               reg = <f8000000 8000>;
-       };
-
-* Freescale on board FPGA
-
-This is the memory-mapped registers for on board FPGA.
-
-Required properities:
-- compatible : should be "fsl,fpga-pixis".
-- reg : should contain the address and the length of the FPPGA register
-  set.
-- interrupt-parent: should specify phandle for the interrupt controller.
-- interrupts : should specify event (wakeup) IRQ.
-
-Example (MPC8610HPCD):
-
-       board-control@e8000000 {
-               compatible = "fsl,fpga-pixis";
-               reg = <0xe8000000 32>;
-               interrupt-parent = <&mpic>;
-               interrupts = <8 8>;
-       };
-
-* Freescale BCSR GPIO banks
-
-Some BCSR registers act as simple GPIO controllers, each such
-register can be represented by the gpio-controller node.
-
-Required properities:
-- compatible : Should be "fsl,<board>-bcsr-gpio".
-- reg : Should contain the address and the length of the GPIO bank
-  register.
-- #gpio-cells : Should be two. The first cell is the pin number and the
-  second cell is used to specify optional parameters (currently unused).
-- gpio-controller : Marks the port as GPIO controller.
-
-Example:
-
-       bcsr@1,0 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "fsl,mpc8360mds-bcsr";
-               reg = <1 0 0x8000>;
-               ranges = <0 1 0 0x8000>;
-
-               bcsr13: gpio-controller@d {
-                       #gpio-cells = <2>;
-                       compatible = "fsl,mpc8360mds-bcsr-gpio";
-                       reg = <0xd 1>;
-                       gpio-controller;
-               };
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/can.txt b/Documentation/powerpc/dts-bindings/fsl/can.txt
deleted file mode 100644 (file)
index 2fa4fcd..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-CAN Device Tree Bindings
-------------------------
-
-(c) 2006-2009 Secret Lab Technologies Ltd
-Grant Likely <grant.likely@secretlab.ca>
-
-fsl,mpc5200-mscan nodes
------------------------
-In addition to the required compatible-, reg- and interrupt-properties, you can
-also specify which clock source shall be used for the controller:
-
-- fsl,mscan-clock-source : a string describing the clock source. Valid values
-                          are: "ip" for ip bus clock
-                                "ref" for reference clock (XTAL)
-                          "ref" is default in case this property is not
-                          present.
-
-fsl,mpc5121-mscan nodes
------------------------
-In addition to the required compatible-, reg- and interrupt-properties, you can
-also specify which clock source and divider shall be used for the controller:
-
-- fsl,mscan-clock-source : a string describing the clock source. Valid values
-                          are: "ip" for ip bus clock
-                               "ref" for reference clock
-                               "sys" for system clock
-                          If this property is not present, an optimal CAN
-                          clock source and frequency based on the system
-                          clock will be selected. If this is not possible,
-                          the reference clock will be used.
-
-- fsl,mscan-clock-divider: for the reference and system clock, an additional
-                          clock divider can be specified. By default, a
-                          value of 1 is used.
-
-Note that the MPC5121 Rev. 1 processor is not supported.
-
-Examples:
-       can@1300 {
-               compatible = "fsl,mpc5121-mscan";
-               interrupts = <12 0x8>;
-               interrupt-parent = <&ipic>;
-               reg = <0x1300 0x80>;
-       };
-
-       can@1380 {
-               compatible = "fsl,mpc5121-mscan";
-               interrupts = <13 0x8>;
-               interrupt-parent = <&ipic>;
-               reg = <0x1380 0x80>;
-               fsl,mscan-clock-source = "ref";
-               fsl,mscan-clock-divider = <3>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm.txt
deleted file mode 100644 (file)
index 160c752..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-* Freescale Communications Processor Module
-
-NOTE: This is an interim binding, and will likely change slightly,
-as more devices are supported.  The QE bindings especially are
-incomplete.
-
-* Root CPM node
-
-Properties:
-- compatible : "fsl,cpm1", "fsl,cpm2", or "fsl,qe".
-- reg : A 48-byte region beginning with CPCR.
-
-Example:
-     cpm@119c0 {
-       #address-cells = <1>;
-       #size-cells = <1>;
-       #interrupt-cells = <2>;
-       compatible = "fsl,mpc8272-cpm", "fsl,cpm2";
-       reg = <119c0 30>;
-     }
-
-* Properties common to multiple CPM/QE devices
-
-- fsl,cpm-command : This value is ORed with the opcode and command flag
-                    to specify the device on which a CPM command operates.
-
-- fsl,cpm-brg : Indicates which baud rate generator the device
-                is associated with.  If absent, an unused BRG
-                should be dynamically allocated.  If zero, the
-                device uses an external clock rather than a BRG.
-
-- reg : Unless otherwise specified, the first resource represents the
-        scc/fcc/ucc registers, and the second represents the device's
-        parameter RAM region (if it has one).
-
-* Multi-User RAM (MURAM)
-
-The multi-user/dual-ported RAM is expressed as a bus under the CPM node.
-
-Ranges must be set up subject to the following restrictions:
-
-- Children's reg nodes must be offsets from the start of all muram, even
-  if the user-data area does not begin at zero.
-- If multiple range entries are used, the difference between the parent
-  address and the child address must be the same in all, so that a single
-  mapping can cover them all while maintaining the ability to determine
-  CPM-side offsets with pointer subtraction.  It is recommended that
-  multiple range entries not be used.
-- A child address of zero must be translatable, even if no reg resources
-  contain it.
-
-A child "data" node must exist, compatible with "fsl,cpm-muram-data", to
-indicate the portion of muram that is usable by the OS for arbitrary
-purposes.  The data node may have an arbitrary number of reg resources,
-all of which contribute to the allocatable muram pool.
-
-Example, based on mpc8272:
-       muram@0 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               ranges = <0 0 10000>;
-
-               data@0 {
-                       compatible = "fsl,cpm-muram-data";
-                       reg = <0 2000 9800 800>;
-               };
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/brg.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/brg.txt
deleted file mode 100644 (file)
index 4c7d45e..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-* Baud Rate Generators
-
-Currently defined compatibles:
-fsl,cpm-brg
-fsl,cpm1-brg
-fsl,cpm2-brg
-
-Properties:
-- reg : There may be an arbitrary number of reg resources; BRG
-  numbers are assigned to these in order.
-- clock-frequency : Specifies the base frequency driving
-  the BRG.
-
-Example:
-       brg@119f0 {
-               compatible = "fsl,mpc8272-brg",
-                            "fsl,cpm2-brg",
-                            "fsl,cpm-brg";
-               reg = <119f0 10 115f0 10>;
-               clock-frequency = <d#25000000>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/i2c.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/i2c.txt
deleted file mode 100644 (file)
index 87bc604..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-* I2C
-
-The I2C controller is expressed as a bus under the CPM node.
-
-Properties:
-- compatible : "fsl,cpm1-i2c", "fsl,cpm2-i2c"
-- reg : On CPM2 devices, the second resource doesn't specify the I2C
-  Parameter RAM itself, but the I2C_BASE field of the CPM2 Parameter RAM
-  (typically 0x8afc 0x2).
-- #address-cells : Should be one. The cell is the i2c device address with
-  the r/w bit set to zero.
-- #size-cells : Should be zero.
-- clock-frequency : Can be used to set the i2c clock frequency. If
-  unspecified, a default frequency of 60kHz is being used.
-The following two properties are deprecated. They are only used by legacy
-i2c drivers to find the bus to probe:
-- linux,i2c-index : Can be used to hard code an i2c bus number. By default,
-  the bus number is dynamically assigned by the i2c core.
-- linux,i2c-class : Can be used to override the i2c class. The class is used
-  by legacy i2c device drivers to find a bus in a specific context like
-  system management, video or sound. By default, I2C_CLASS_HWMON (1) is
-  being used. The definition of the classes can be found in
-  include/i2c/i2c.h
-
-Example, based on mpc823:
-
-       i2c@860 {
-               compatible = "fsl,mpc823-i2c",
-                            "fsl,cpm1-i2c";
-               reg = <0x860 0x20 0x3c80 0x30>;
-               interrupts = <16>;
-               interrupt-parent = <&CPM_PIC>;
-               fsl,cpm-command = <0x10>;
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               rtc@68 {
-                       compatible = "dallas,ds1307";
-                       reg = <0x68>;
-               };
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/pic.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/pic.txt
deleted file mode 100644 (file)
index 8e3ee16..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-* Interrupt Controllers
-
-Currently defined compatibles:
-- fsl,cpm1-pic
-  - only one interrupt cell
-- fsl,pq1-pic
-- fsl,cpm2-pic
-  - second interrupt cell is level/sense:
-    - 2 is falling edge
-    - 8 is active low
-
-Example:
-       interrupt-controller@10c00 {
-               #interrupt-cells = <2>;
-               interrupt-controller;
-               reg = <10c00 80>;
-               compatible = "mpc8272-pic", "fsl,cpm2-pic";
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/usb.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/cpm/usb.txt
deleted file mode 100644 (file)
index 74bfda4..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-* USB (Universal Serial Bus Controller)
-
-Properties:
-- compatible : "fsl,cpm1-usb", "fsl,cpm2-usb", "fsl,qe-usb"
-
-Example:
-       usb@11bc0 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               compatible = "fsl,cpm2-usb";
-               reg = <11b60 18 8b00 100>;
-               interrupts = <b 8>;
-               interrupt-parent = <&PIC>;
-               fsl,cpm-command = <2e600000>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/gpio.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/gpio.txt
deleted file mode 100644 (file)
index 349f79f..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-Every GPIO controller node must have #gpio-cells property defined,
-this information will be used to translate gpio-specifiers.
-
-On CPM1 devices, all ports are using slightly different register layouts.
-Ports A, C and D are 16bit ports and Ports B and E are 32bit ports.
-
-On CPM2 devices, all ports are 32bit ports and use a common register layout.
-
-Required properties:
-- compatible : "fsl,cpm1-pario-bank-a", "fsl,cpm1-pario-bank-b",
-  "fsl,cpm1-pario-bank-c", "fsl,cpm1-pario-bank-d",
-  "fsl,cpm1-pario-bank-e", "fsl,cpm2-pario-bank"
-- #gpio-cells : Should be two. The first cell is the pin number and the
-  second cell is used to specify optional parameters (currently unused).
-- gpio-controller : Marks the port as GPIO controller.
-
-Example of three SOC GPIO banks defined as gpio-controller nodes:
-
-       CPM1_PIO_A: gpio-controller@950 {
-               #gpio-cells = <2>;
-               compatible = "fsl,cpm1-pario-bank-a";
-               reg = <0x950 0x10>;
-               gpio-controller;
-       };
-
-       CPM1_PIO_B: gpio-controller@ab8 {
-               #gpio-cells = <2>;
-               compatible = "fsl,cpm1-pario-bank-b";
-               reg = <0xab8 0x10>;
-               gpio-controller;
-       };
-
-       CPM1_PIO_E: gpio-controller@ac8 {
-               #gpio-cells = <2>;
-               compatible = "fsl,cpm1-pario-bank-e";
-               reg = <0xac8 0x18>;
-               gpio-controller;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/network.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/network.txt
deleted file mode 100644 (file)
index 0e42694..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-* Network
-
-Currently defined compatibles:
-- fsl,cpm1-scc-enet
-- fsl,cpm2-scc-enet
-- fsl,cpm1-fec-enet
-- fsl,cpm2-fcc-enet (third resource is GFEMR)
-- fsl,qe-enet
-
-Example:
-
-       ethernet@11300 {
-               device_type = "network";
-               compatible = "fsl,mpc8272-fcc-enet",
-                            "fsl,cpm2-fcc-enet";
-               reg = <11300 20 8400 100 11390 1>;
-               local-mac-address = [ 00 00 00 00 00 00 ];
-               interrupts = <20 8>;
-               interrupt-parent = <&PIC>;
-               phy-handle = <&PHY0>;
-               fsl,cpm-command = <12000300>;
-       };
-
-* MDIO
-
-Currently defined compatibles:
-fsl,pq1-fec-mdio (reg is same as first resource of FEC device)
-fsl,cpm2-mdio-bitbang (reg is port C registers)
-
-Properties for fsl,cpm2-mdio-bitbang:
-fsl,mdio-pin : pin of port C controlling mdio data
-fsl,mdc-pin : pin of port C controlling mdio clock
-
-Example:
-       mdio@10d40 {
-               device_type = "mdio";
-               compatible = "fsl,mpc8272ads-mdio-bitbang",
-                            "fsl,mpc8272-mdio-bitbang",
-                            "fsl,cpm2-mdio-bitbang";
-               reg = <10d40 14>;
-               #address-cells = <1>;
-               #size-cells = <0>;
-               fsl,mdio-pin = <12>;
-               fsl,mdc-pin = <13>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe.txt
deleted file mode 100644 (file)
index 4f89302..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-* Freescale QUICC Engine module (QE)
-This represents qe module that is installed on PowerQUICC II Pro.
-
-NOTE:  This is an interim binding; it should be updated to fit
-in with the CPM binding later in this document.
-
-Basically, it is a bus of devices, that could act more or less
-as a complete entity (UCC, USB etc ). All of them should be siblings on
-the "root" qe node, using the common properties from there.
-The description below applies to the qe of MPC8360 and
-more nodes and properties would be extended in the future.
-
-i) Root QE device
-
-Required properties:
-- compatible : should be "fsl,qe";
-- model : precise model of the QE, Can be "QE", "CPM", or "CPM2"
-- reg : offset and length of the device registers.
-- bus-frequency : the clock frequency for QUICC Engine.
-- fsl,qe-num-riscs: define how many RISC engines the QE has.
-- fsl,qe-num-snums: define how many serial number(SNUM) the QE can use for the
-  threads.
-
-Optional properties:
-- fsl,firmware-phandle:
-    Usage: required only if there is no fsl,qe-firmware child node
-    Value type: <phandle>
-    Definition: Points to a firmware node (see "QE Firmware Node" below)
-        that contains the firmware that should be uploaded for this QE.
-        The compatible property for the firmware node should say,
-        "fsl,qe-firmware".
-
-Recommended properties
-- brg-frequency : the internal clock source frequency for baud-rate
-  generators in Hz.
-
-Example:
-     qe@e0100000 {
-       #address-cells = <1>;
-       #size-cells = <1>;
-       #interrupt-cells = <2>;
-       compatible = "fsl,qe";
-       ranges = <0 e0100000 00100000>;
-       reg = <e0100000 480>;
-       brg-frequency = <0>;
-       bus-frequency = <179A7B00>;
-     }
-
-* Multi-User RAM (MURAM)
-
-Required properties:
-- compatible : should be "fsl,qe-muram", "fsl,cpm-muram".
-- mode : the could be "host" or "slave".
-- ranges : Should be defined as specified in 1) to describe the
-   translation of MURAM addresses.
-- data-only : sub-node which defines the address area under MURAM
-   bus that can be allocated as data/parameter
-
-Example:
-
-     muram@10000 {
-       compatible = "fsl,qe-muram", "fsl,cpm-muram";
-       ranges = <0 00010000 0000c000>;
-
-       data-only@0{
-               compatible = "fsl,qe-muram-data",
-                            "fsl,cpm-muram-data";
-               reg = <0 c000>;
-       };
-     };
-
-* QE Firmware Node
-
-This node defines a firmware binary that is embedded in the device tree, for
-the purpose of passing the firmware from bootloader to the kernel, or from
-the hypervisor to the guest.
-
-The firmware node itself contains the firmware binary contents, a compatible
-property, and any firmware-specific properties.  The node should be placed
-inside a QE node that needs it.  Doing so eliminates the need for a
-fsl,firmware-phandle property.  Other QE nodes that need the same firmware
-should define an fsl,firmware-phandle property that points to the firmware node
-in the first QE node.
-
-The fsl,firmware property can be specified in the DTS (possibly using incbin)
-or can be inserted by the boot loader at boot time.
-
-Required properties:
-  - compatible
-      Usage: required
-      Value type: <string>
-      Definition: A standard property.  Specify a string that indicates what
-          kind of firmware it is.  For QE, this should be "fsl,qe-firmware".
-
-   - fsl,firmware
-      Usage: required
-      Value type: <prop-encoded-array>, encoded as an array of bytes
-      Definition: A standard property.  This property contains the firmware
-          binary "blob".
-
-Example:
-       qe1@e0080000 {
-               compatible = "fsl,qe";
-               qe_firmware:qe-firmware {
-                       compatible = "fsl,qe-firmware";
-                       fsl,firmware = [0x70 0xcd 0x00 0x00 0x01 0x46 0x45 ...];
-               };
-               ...
-       };
-
-       qe2@e0090000 {
-               compatible = "fsl,qe";
-               fsl,firmware-phandle = <&qe_firmware>;
-               ...
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/firmware.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/firmware.txt
deleted file mode 100644 (file)
index 249db3a..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-* Uploaded QE firmware
-
-      If a new firmware has been uploaded to the QE (usually by the
-      boot loader), then a 'firmware' child node should be added to the QE
-      node.  This node provides information on the uploaded firmware that
-      device drivers may need.
-
-      Required properties:
-      - id: The string name of the firmware.  This is taken from the 'id'
-            member of the qe_firmware structure of the uploaded firmware.
-            Device drivers can search this string to determine if the
-            firmware they want is already present.
-      - extended-modes: The Extended Modes bitfield, taken from the
-                  firmware binary.  It is a 64-bit number represented
-                  as an array of two 32-bit numbers.
-      - virtual-traps: The virtual traps, taken from the firmware binary.
-                 It is an array of 8 32-bit numbers.
-
-Example:
-       firmware {
-               id = "Soft-UART";
-               extended-modes = <0 0>;
-               virtual-traps = <0 0 0 0 0 0 0 0>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/par_io.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/par_io.txt
deleted file mode 100644 (file)
index 6098426..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-* Parallel I/O Ports
-
-This node configures Parallel I/O ports for CPUs with QE support.
-The node should reside in the "soc" node of the tree.  For each
-device that using parallel I/O ports, a child node should be created.
-See the definition of the Pin configuration nodes below for more
-information.
-
-Required properties:
-- device_type : should be "par_io".
-- reg : offset to the register set and its length.
-- num-ports : number of Parallel I/O ports
-
-Example:
-par_io@1400 {
-       reg = <1400 100>;
-       #address-cells = <1>;
-       #size-cells = <0>;
-       device_type = "par_io";
-       num-ports = <7>;
-       ucc_pin@01 {
-               ......
-       };
-
-Note that "par_io" nodes are obsolete, and should not be used for
-the new device trees. Instead, each Par I/O bank should be represented
-via its own gpio-controller node:
-
-Required properties:
-- #gpio-cells : should be "2".
-- compatible : should be "fsl,<chip>-qe-pario-bank",
-  "fsl,mpc8323-qe-pario-bank".
-- reg : offset to the register set and its length.
-- gpio-controller : node to identify gpio controllers.
-
-Example:
-       qe_pio_a: gpio-controller@1400 {
-               #gpio-cells = <2>;
-               compatible = "fsl,mpc8360-qe-pario-bank",
-               "fsl,mpc8323-qe-pario-bank";
-               reg = <0x1400 0x18>;
-               gpio-controller;
-         };
-
-       qe_pio_e: gpio-controller@1460 {
-               #gpio-cells = <2>;
-               compatible = "fsl,mpc8360-qe-pario-bank",
-                            "fsl,mpc8323-qe-pario-bank";
-               reg = <0x1460 0x18>;
-               gpio-controller;
-         };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/pincfg.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/pincfg.txt
deleted file mode 100644 (file)
index c5b4306..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-* Pin configuration nodes
-
-Required properties:
-- linux,phandle : phandle of this node; likely referenced by a QE
-  device.
-- pio-map : array of pin configurations.  Each pin is defined by 6
-  integers.  The six numbers are respectively: port, pin, dir,
-  open_drain, assignment, has_irq.
-  - port : port number of the pin; 0-6 represent port A-G in UM.
-  - pin : pin number in the port.
-  - dir : direction of the pin, should encode as follows:
-
-     0 = The pin is disabled
-     1 = The pin is an output
-     2 = The pin is an input
-     3 = The pin is I/O
-
-  - open_drain : indicates the pin is normal or wired-OR:
-
-     0 = The pin is actively driven as an output
-     1 = The pin is an open-drain driver. As an output, the pin is
-         driven active-low, otherwise it is three-stated.
-
-  - assignment : function number of the pin according to the Pin Assignment
-    tables in User Manual.  Each pin can have up to 4 possible functions in
-    QE and two options for CPM.
-  - has_irq : indicates if the pin is used as source of external
-    interrupts.
-
-Example:
-     ucc_pin@01 {
-       linux,phandle = <140001>;
-       pio-map = <
-       /* port  pin  dir  open_drain  assignment  has_irq */
-               0  3  1  0  1  0        /* TxD0 */
-               0  4  1  0  1  0        /* TxD1 */
-               0  5  1  0  1  0        /* TxD2 */
-               0  6  1  0  1  0        /* TxD3 */
-               1  6  1  0  3  0        /* TxD4 */
-               1  7  1  0  1  0        /* TxD5 */
-               1  9  1  0  2  0        /* TxD6 */
-               1  a  1  0  2  0        /* TxD7 */
-               0  9  2  0  1  0        /* RxD0 */
-               0  a  2  0  1  0        /* RxD1 */
-               0  b  2  0  1  0        /* RxD2 */
-               0  c  2  0  1  0        /* RxD3 */
-               0  d  2  0  1  0        /* RxD4 */
-               1  1  2  0  2  0        /* RxD5 */
-               1  0  2  0  2  0        /* RxD6 */
-               1  4  2  0  2  0        /* RxD7 */
-               0  7  1  0  1  0        /* TX_EN */
-               0  8  1  0  1  0        /* TX_ER */
-               0  f  2  0  1  0        /* RX_DV */
-               0  10 2  0  1  0        /* RX_ER */
-               0  0  2  0  1  0        /* RX_CLK */
-               2  9  1  0  3  0        /* GTX_CLK - CLK10 */
-               2  8  2  0  1  0>;      /* GTX125 - CLK9 */
-     };
-
-
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/ucc.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/ucc.txt
deleted file mode 100644 (file)
index e47734b..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-* UCC (Unified Communications Controllers)
-
-Required properties:
-- device_type : should be "network", "hldc", "uart", "transparent"
-  "bisync", "atm", or "serial".
-- compatible : could be "ucc_geth" or "fsl_atm" and so on.
-- cell-index : the ucc number(1-8), corresponding to UCCx in UM.
-- reg : Offset and length of the register set for the device
-- interrupts : <a b> where a is the interrupt number and b is a
-  field that represents an encoding of the sense and level
-  information for the interrupt.  This should be encoded based on
-  the information in section 2) depending on the type of interrupt
-  controller you have.
-- interrupt-parent : the phandle for the interrupt controller that
-  services interrupts for this device.
-- pio-handle : The phandle for the Parallel I/O port configuration.
-- port-number : for UART drivers, the port number to use, between 0 and 3.
-  This usually corresponds to the /dev/ttyQE device, e.g. <0> = /dev/ttyQE0.
-  The port number is added to the minor number of the device.  Unlike the
-  CPM UART driver, the port-number is required for the QE UART driver.
-- soft-uart : for UART drivers, if specified this means the QE UART device
-  driver should use "Soft-UART" mode, which is needed on some SOCs that have
-  broken UART hardware.  Soft-UART is provided via a microcode upload.
-- rx-clock-name: the UCC receive clock source
-  "none": clock source is disabled
-  "brg1" through "brg16": clock source is BRG1-BRG16, respectively
-  "clk1" through "clk24": clock source is CLK1-CLK24, respectively
-- tx-clock-name: the UCC transmit clock source
-  "none": clock source is disabled
-  "brg1" through "brg16": clock source is BRG1-BRG16, respectively
-  "clk1" through "clk24": clock source is CLK1-CLK24, respectively
-The following two properties are deprecated.  rx-clock has been replaced
-with rx-clock-name, and tx-clock has been replaced with tx-clock-name.
-Drivers that currently use the deprecated properties should continue to
-do so, in order to support older device trees, but they should be updated
-to check for the new properties first.
-- rx-clock : represents the UCC receive clock source.
-  0x00 : clock source is disabled;
-  0x1~0x10 : clock source is BRG1~BRG16 respectively;
-  0x11~0x28: clock source is QE_CLK1~QE_CLK24 respectively.
-- tx-clock: represents the UCC transmit clock source;
-  0x00 : clock source is disabled;
-  0x1~0x10 : clock source is BRG1~BRG16 respectively;
-  0x11~0x28: clock source is QE_CLK1~QE_CLK24 respectively.
-
-Required properties for network device_type:
-- mac-address : list of bytes representing the ethernet address.
-- phy-handle : The phandle for the PHY connected to this controller.
-
-Recommended properties:
-- phy-connection-type : a string naming the controller/PHY interface type,
-  i.e., "mii" (default), "rmii", "gmii", "rgmii", "rgmii-id" (Internal
-  Delay), "rgmii-txid" (delay on TX only), "rgmii-rxid" (delay on RX only),
-  "tbi", or "rtbi".
-
-Example:
-       ucc@2000 {
-               device_type = "network";
-               compatible = "ucc_geth";
-               cell-index = <1>;
-               reg = <2000 200>;
-               interrupts = <a0 0>;
-               interrupt-parent = <700>;
-               mac-address = [ 00 04 9f 00 23 23 ];
-               rx-clock = "none";
-               tx-clock = "clk9";
-               phy-handle = <212000>;
-               phy-connection-type = "gmii";
-               pio-handle = <140001>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/usb.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/qe/usb.txt
deleted file mode 100644 (file)
index 9ccd5f3..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-Freescale QUICC Engine USB Controller
-
-Required properties:
-- compatible : should be "fsl,<chip>-qe-usb", "fsl,mpc8323-qe-usb".
-- reg : the first two cells should contain usb registers location and
-  length, the next two two cells should contain PRAM location and
-  length.
-- interrupts : should contain USB interrupt.
-- interrupt-parent : interrupt source phandle.
-- fsl,fullspeed-clock : specifies the full speed USB clock source:
-  "none": clock source is disabled
-  "brg1" through "brg16": clock source is BRG1-BRG16, respectively
-  "clk1" through "clk24": clock source is CLK1-CLK24, respectively
-- fsl,lowspeed-clock : specifies the low speed USB clock source:
-  "none": clock source is disabled
-  "brg1" through "brg16": clock source is BRG1-BRG16, respectively
-  "clk1" through "clk24": clock source is CLK1-CLK24, respectively
-- hub-power-budget : USB power budget for the root hub, in mA.
-- gpios : should specify GPIOs in this order: USBOE, USBTP, USBTN, USBRP,
-  USBRN, SPEED (optional), and POWER (optional).
-
-Example:
-
-usb@6c0 {
-       compatible = "fsl,mpc8360-qe-usb", "fsl,mpc8323-qe-usb";
-       reg = <0x6c0 0x40 0x8b00 0x100>;
-       interrupts = <11>;
-       interrupt-parent = <&qeic>;
-       fsl,fullspeed-clock = "clk21";
-       gpios = <&qe_pio_b  2 0 /* USBOE */
-                &qe_pio_b  3 0 /* USBTP */
-                &qe_pio_b  8 0 /* USBTN */
-                &qe_pio_b  9 0 /* USBRP */
-                &qe_pio_b 11 0 /* USBRN */
-                &qe_pio_e 20 0 /* SPEED */
-                &qe_pio_e 21 0 /* POWER */>;
-};
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/serial.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/serial.txt
deleted file mode 100644 (file)
index 2ea76d9..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-* Serial
-
-Currently defined compatibles:
-- fsl,cpm1-smc-uart
-- fsl,cpm2-smc-uart
-- fsl,cpm1-scc-uart
-- fsl,cpm2-scc-uart
-- fsl,qe-uart
-
-Modem control lines connected to GPIO controllers are listed in the gpios
-property as described in booting-without-of.txt, section IX.1 in the following
-order:
-
-CTS, RTS, DCD, DSR, DTR, and RI.
-
-The gpios property is optional and can be left out when control lines are
-not used.
-
-Example:
-
-       serial@11a00 {
-               device_type = "serial";
-               compatible = "fsl,mpc8272-scc-uart",
-                            "fsl,cpm2-scc-uart";
-               reg = <11a00 20 8000 100>;
-               interrupts = <28 8>;
-               interrupt-parent = <&PIC>;
-               fsl,cpm-brg = <1>;
-               fsl,cpm-command = <00800000>;
-               gpios = <&gpio_c 15 0
-                        &gpio_d 29 0>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/diu.txt b/Documentation/powerpc/dts-bindings/fsl/diu.txt
deleted file mode 100644 (file)
index b66cb6d..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-* Freescale Display Interface Unit
-
-The Freescale DIU is a LCD controller, with proper hardware, it can also
-drive DVI monitors.
-
-Required properties:
-- compatible : should be "fsl,diu" or "fsl,mpc5121-diu".
-- reg : should contain at least address and length of the DIU register
-  set.
-- interrupts : one DIU interrupt should be described here.
-- interrupt-parent : the phandle for the interrupt controller that
-  services interrupts for this device.
-
-Optional properties:
-- edid : verbatim EDID data block describing attached display.
-  Data from the detailed timing descriptor will be used to
-  program the display controller.
-
-Example (MPC8610HPCD):
-       display@2c000 {
-               compatible = "fsl,diu";
-               reg = <0x2c000 100>;
-               interrupts = <72 2>;
-               interrupt-parent = <&mpic>;
-       };
-
-Example for MPC5121:
-       display@2100 {
-               compatible = "fsl,mpc5121-diu";
-               reg = <0x2100 0x100>;
-               interrupts = <64 0x8>;
-               interrupt-parent = <&ipic>;
-               edid = [edid-data];
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/dma.txt b/Documentation/powerpc/dts-bindings/fsl/dma.txt
deleted file mode 100644 (file)
index 2a4b4bc..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-* Freescale 83xx DMA Controller
-
-Freescale PowerPC 83xx have on chip general purpose DMA controllers.
-
-Required properties:
-
-- compatible        : compatible list, contains 2 entries, first is
-                "fsl,CHIP-dma", where CHIP is the processor
-                (mpc8349, mpc8360, etc.) and the second is
-                "fsl,elo-dma"
-- reg               : <registers mapping for DMA general status reg>
-- ranges               : Should be defined as specified in 1) to describe the
-                 DMA controller channels.
-- cell-index        : controller index.  0 for controller @ 0x8100
-- interrupts        : <interrupt mapping for DMA IRQ>
-- interrupt-parent  : optional, if needed for interrupt mapping
-
-
-- DMA channel nodes:
-        - compatible        : compatible list, contains 2 entries, first is
-                        "fsl,CHIP-dma-channel", where CHIP is the processor
-                        (mpc8349, mpc8350, etc.) and the second is
-                        "fsl,elo-dma-channel". However, see note below.
-        - reg               : <registers mapping for channel>
-        - cell-index        : dma channel index starts at 0.
-
-Optional properties:
-        - interrupts        : <interrupt mapping for DMA channel IRQ>
-                         (on 83xx this is expected to be identical to
-                          the interrupts property of the parent node)
-        - interrupt-parent  : optional, if needed for interrupt mapping
-
-Example:
-       dma@82a8 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "fsl,mpc8349-dma", "fsl,elo-dma";
-               reg = <0x82a8 4>;
-               ranges = <0 0x8100 0x1a4>;
-               interrupt-parent = <&ipic>;
-               interrupts = <71 8>;
-               cell-index = <0>;
-               dma-channel@0 {
-                       compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
-                       cell-index = <0>;
-                       reg = <0 0x80>;
-                       interrupt-parent = <&ipic>;
-                       interrupts = <71 8>;
-               };
-               dma-channel@80 {
-                       compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
-                       cell-index = <1>;
-                       reg = <0x80 0x80>;
-                       interrupt-parent = <&ipic>;
-                       interrupts = <71 8>;
-               };
-               dma-channel@100 {
-                       compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
-                       cell-index = <2>;
-                       reg = <0x100 0x80>;
-                       interrupt-parent = <&ipic>;
-                       interrupts = <71 8>;
-               };
-               dma-channel@180 {
-                       compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
-                       cell-index = <3>;
-                       reg = <0x180 0x80>;
-                       interrupt-parent = <&ipic>;
-                       interrupts = <71 8>;
-               };
-       };
-
-* Freescale 85xx/86xx DMA Controller
-
-Freescale PowerPC 85xx/86xx have on chip general purpose DMA controllers.
-
-Required properties:
-
-- compatible        : compatible list, contains 2 entries, first is
-                "fsl,CHIP-dma", where CHIP is the processor
-                (mpc8540, mpc8540, etc.) and the second is
-                "fsl,eloplus-dma"
-- reg               : <registers mapping for DMA general status reg>
-- cell-index        : controller index.  0 for controller @ 0x21000,
-                                         1 for controller @ 0xc000
-- ranges               : Should be defined as specified in 1) to describe the
-                 DMA controller channels.
-
-- DMA channel nodes:
-        - compatible        : compatible list, contains 2 entries, first is
-                        "fsl,CHIP-dma-channel", where CHIP is the processor
-                        (mpc8540, mpc8560, etc.) and the second is
-                        "fsl,eloplus-dma-channel". However, see note below.
-        - cell-index        : dma channel index starts at 0.
-        - reg               : <registers mapping for channel>
-        - interrupts        : <interrupt mapping for DMA channel IRQ>
-        - interrupt-parent  : optional, if needed for interrupt mapping
-
-Example:
-       dma@21300 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "fsl,mpc8540-dma", "fsl,eloplus-dma";
-               reg = <0x21300 4>;
-               ranges = <0 0x21100 0x200>;
-               cell-index = <0>;
-               dma-channel@0 {
-                       compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel";
-                       reg = <0 0x80>;
-                       cell-index = <0>;
-                       interrupt-parent = <&mpic>;
-                       interrupts = <20 2>;
-               };
-               dma-channel@80 {
-                       compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel";
-                       reg = <0x80 0x80>;
-                       cell-index = <1>;
-                       interrupt-parent = <&mpic>;
-                       interrupts = <21 2>;
-               };
-               dma-channel@100 {
-                       compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel";
-                       reg = <0x100 0x80>;
-                       cell-index = <2>;
-                       interrupt-parent = <&mpic>;
-                       interrupts = <22 2>;
-               };
-               dma-channel@180 {
-                       compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel";
-                       reg = <0x180 0x80>;
-                       cell-index = <3>;
-                       interrupt-parent = <&mpic>;
-                       interrupts = <23 2>;
-               };
-       };
-
-Note on DMA channel compatible properties: The compatible property must say
-"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel" to be used by the Elo DMA
-driver (fsldma).  Any DMA channel used by fsldma cannot be used by another
-DMA driver, such as the SSI sound drivers for the MPC8610.  Therefore, any DMA
-channel that should be used for another driver should not use
-"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel".  For the SSI drivers, for
-example, the compatible property should be "fsl,ssi-dma-channel".  See ssi.txt
-for more information.
diff --git a/Documentation/powerpc/dts-bindings/fsl/esdhc.txt b/Documentation/powerpc/dts-bindings/fsl/esdhc.txt
deleted file mode 100644 (file)
index 64bcb8b..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-* Freescale Enhanced Secure Digital Host Controller (eSDHC)
-
-The Enhanced Secure Digital Host Controller provides an interface
-for MMC, SD, and SDIO types of memory cards.
-
-Required properties:
-  - compatible : should be
-    "fsl,<chip>-esdhc", "fsl,esdhc"
-  - reg : should contain eSDHC registers location and length.
-  - interrupts : should contain eSDHC interrupt.
-  - interrupt-parent : interrupt source phandle.
-  - clock-frequency : specifies eSDHC base clock frequency.
-  - sdhci,wp-inverted : (optional) specifies that eSDHC controller
-    reports inverted write-protect state;
-  - sdhci,1-bit-only : (optional) specifies that a controller can
-    only handle 1-bit data transfers.
-  - sdhci,auto-cmd12: (optional) specifies that a controller can
-    only handle auto CMD12.
-
-Example:
-
-sdhci@2e000 {
-       compatible = "fsl,mpc8378-esdhc", "fsl,esdhc";
-       reg = <0x2e000 0x1000>;
-       interrupts = <42 0x8>;
-       interrupt-parent = <&ipic>;
-       /* Filled in by U-Boot */
-       clock-frequency = <0>;
-};
diff --git a/Documentation/powerpc/dts-bindings/fsl/gtm.txt b/Documentation/powerpc/dts-bindings/fsl/gtm.txt
deleted file mode 100644 (file)
index 9a33efd..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-* Freescale General-purpose Timers Module
-
-Required properties:
-  - compatible : should be
-    "fsl,<chip>-gtm", "fsl,gtm" for SOC GTMs
-    "fsl,<chip>-qe-gtm", "fsl,qe-gtm", "fsl,gtm" for QE GTMs
-    "fsl,<chip>-cpm2-gtm", "fsl,cpm2-gtm", "fsl,gtm" for CPM2 GTMs
-  - reg : should contain gtm registers location and length (0x40).
-  - interrupts : should contain four interrupts.
-  - interrupt-parent : interrupt source phandle.
-  - clock-frequency : specifies the frequency driving the timer.
-
-Example:
-
-timer@500 {
-       compatible = "fsl,mpc8360-gtm", "fsl,gtm";
-       reg = <0x500 0x40>;
-       interrupts = <90 8 78 8 84 8 72 8>;
-       interrupt-parent = <&ipic>;
-       /* filled by u-boot */
-       clock-frequency = <0>;
-};
-
-timer@440 {
-       compatible = "fsl,mpc8360-qe-gtm", "fsl,qe-gtm", "fsl,gtm";
-       reg = <0x440 0x40>;
-       interrupts = <12 13 14 15>;
-       interrupt-parent = <&qeic>;
-       /* filled by u-boot */
-       clock-frequency = <0>;
-};
diff --git a/Documentation/powerpc/dts-bindings/fsl/guts.txt b/Documentation/powerpc/dts-bindings/fsl/guts.txt
deleted file mode 100644 (file)
index 9e7a241..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-* Global Utilities Block
-
-The global utilities block controls power management, I/O device
-enabling, power-on-reset configuration monitoring, general-purpose
-I/O signal configuration, alternate function selection for multiplexed
-signals, and clock control.
-
-Required properties:
-
- - compatible : Should define the compatible device type for
-   global-utilities.
- - reg : Offset and length of the register set for the device.
-
-Recommended properties:
-
- - fsl,has-rstcr : Indicates that the global utilities register set
-   contains a functioning "reset control register" (i.e. the board
-   is wired to reset upon setting the HRESET_REQ bit in this register).
-
-Example:
-       global-utilities@e0000 {        /* global utilities block */
-               compatible = "fsl,mpc8548-guts";
-               reg = <e0000 1000>;
-               fsl,has-rstcr;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/i2c.txt b/Documentation/powerpc/dts-bindings/fsl/i2c.txt
deleted file mode 100644 (file)
index 1eacd6b..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-* I2C
-
-Required properties :
-
- - reg : Offset and length of the register set for the device
- - compatible : should be "fsl,CHIP-i2c" where CHIP is the name of a
-   compatible processor, e.g. mpc8313, mpc8543, mpc8544, mpc5121,
-   mpc5200 or mpc5200b. For the mpc5121, an additional node
-   "fsl,mpc5121-i2c-ctrl" is required as shown in the example below.
-
-Recommended properties :
-
- - interrupts : <a b> where a is the interrupt number and b is a
-   field that represents an encoding of the sense and level
-   information for the interrupt.  This should be encoded based on
-   the information in section 2) depending on the type of interrupt
-   controller you have.
- - interrupt-parent : the phandle for the interrupt controller that
-   services interrupts for this device.
- - fsl,preserve-clocking : boolean; if defined, the clock settings
-   from the bootloader are preserved (not touched).
- - clock-frequency : desired I2C bus clock frequency in Hz.
- - fsl,timeout : I2C bus timeout in microseconds.
-
-Examples :
-
-       /* MPC5121 based board */
-       i2c@1740 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               compatible = "fsl,mpc5121-i2c", "fsl-i2c";
-               reg = <0x1740 0x20>;
-               interrupts = <11 0x8>;
-               interrupt-parent = <&ipic>;
-               clock-frequency = <100000>;
-       };
-
-       i2ccontrol@1760 {
-               compatible = "fsl,mpc5121-i2c-ctrl";
-               reg = <0x1760 0x8>;
-       };
-
-       /* MPC5200B based board */
-       i2c@3d00 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
-               reg = <0x3d00 0x40>;
-               interrupts = <2 15 0>;
-               interrupt-parent = <&mpc5200_pic>;
-               fsl,preserve-clocking;
-       };
-
-       /* MPC8544 base board */
-       i2c@3100 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               compatible = "fsl,mpc8544-i2c", "fsl-i2c";
-               reg = <0x3100 0x100>;
-               interrupts = <43 2>;
-               interrupt-parent = <&mpic>;
-               clock-frequency = <400000>;
-               fsl,timeout = <10000>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/lbc.txt b/Documentation/powerpc/dts-bindings/fsl/lbc.txt
deleted file mode 100644 (file)
index 3300fec..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-* Chipselect/Local Bus
-
-Properties:
-- name : Should be localbus
-- #address-cells : Should be either two or three.  The first cell is the
-                   chipselect number, and the remaining cells are the
-                   offset into the chipselect.
-- #size-cells : Either one or two, depending on how large each chipselect
-                can be.
-- ranges : Each range corresponds to a single chipselect, and cover
-           the entire access window as configured.
-
-Example:
-       localbus@f0010100 {
-               compatible = "fsl,mpc8272-localbus",
-                          "fsl,pq2-localbus";
-               #address-cells = <2>;
-               #size-cells = <1>;
-               reg = <f0010100 40>;
-
-               ranges = <0 0 fe000000 02000000
-                         1 0 f4500000 00008000>;
-
-               flash@0,0 {
-                       compatible = "jedec-flash";
-                       reg = <0 0 2000000>;
-                       bank-width = <4>;
-                       device-width = <1>;
-               };
-
-               board-control@1,0 {
-                       reg = <1 0 20>;
-                       compatible = "fsl,mpc8272ads-bcsr";
-               };
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/mcm.txt b/Documentation/powerpc/dts-bindings/fsl/mcm.txt
deleted file mode 100644 (file)
index 4ceda9b..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-=====================================================================
-MPX LAW & Coherency Module Device Tree Binding
-Copyright (C) 2009 Freescale Semiconductor Inc.
-=====================================================================
-
-Local Access Window (LAW) Node
-
-The LAW node represents the region of CCSR space where local access
-windows are configured.  For MCM based devices this is the first 4k
-of CCSR space that includes CCSRBAR, ALTCBAR, ALTCAR, BPTR, and some
-number of local access windows as specified by fsl,num-laws.
-
-PROPERTIES
-
-  - compatible
-      Usage: required
-      Value type: <string>
-      Definition: Must include "fsl,mcm-law"
-
-  - reg
-      Usage: required
-      Value type: <prop-encoded-array>
-      Definition: A standard property.  The value specifies the
-          physical address offset and length of the CCSR space
-          registers.
-
-  - fsl,num-laws
-      Usage: required
-      Value type: <u32>
-      Definition: The value specifies the number of local access
-          windows for this device.
-
-=====================================================================
-
-MPX Coherency Module Node
-
-The MPX LAW node represents the region of CCSR space where MCM config
-and error reporting registers exist, this is the second 4k (0x1000)
-of CCSR space.
-
-PROPERTIES
-
-  - compatible
-      Usage: required
-      Value type: <string>
-      Definition: Must include "fsl,CHIP-mcm", "fsl,mcm" where
-      CHIP is the processor (mpc8641, mpc8610, etc.)
-
-  - reg
-      Usage: required
-      Value type: <prop-encoded-array>
-      Definition: A standard property.  The value specifies the
-          physical address offset and length of the CCSR space
-          registers.
-
-   - interrupts
-      Usage: required
-      Value type: <prop-encoded-array>
-
-   - interrupt-parent
-      Usage: required
-      Value type: <phandle>
-
-=====================================================================
diff --git a/Documentation/powerpc/dts-bindings/fsl/mcu-mpc8349emitx.txt b/Documentation/powerpc/dts-bindings/fsl/mcu-mpc8349emitx.txt
deleted file mode 100644 (file)
index 0f76633..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-Freescale MPC8349E-mITX-compatible Power Management Micro Controller Unit (MCU)
-
-Required properties:
-- compatible : "fsl,<mcu-chip>-<board>", "fsl,mcu-mpc8349emitx".
-- reg : should specify I2C address (0x0a).
-- #gpio-cells : should be 2.
-- gpio-controller : should be present.
-
-Example:
-
-mcu@0a {
-       #gpio-cells = <2>;
-       compatible = "fsl,mc9s08qg8-mpc8349emitx",
-                    "fsl,mcu-mpc8349emitx";
-       reg = <0x0a>;
-       gpio-controller;
-};
diff --git a/Documentation/powerpc/dts-bindings/fsl/mpc5121-psc.txt b/Documentation/powerpc/dts-bindings/fsl/mpc5121-psc.txt
deleted file mode 100644 (file)
index 8832e87..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-MPC5121 PSC Device Tree Bindings
-
-PSC in UART mode
-----------------
-
-For PSC in UART mode the needed PSC serial devices
-are specified by fsl,mpc5121-psc-uart nodes in the
-fsl,mpc5121-immr SoC node. Additionally the PSC FIFO
-Controller node fsl,mpc5121-psc-fifo is requered there:
-
-fsl,mpc5121-psc-uart nodes
---------------------------
-
-Required properties :
- - compatible : Should contain "fsl,mpc5121-psc-uart" and "fsl,mpc5121-psc"
- - cell-index : Index of the PSC in hardware
- - reg : Offset and length of the register set for the PSC device
- - interrupts : <a b> where a is the interrupt number of the
-   PSC FIFO Controller and b is a field that represents an
-   encoding of the sense and level information for the interrupt.
- - interrupt-parent : the phandle for the interrupt controller that
-   services interrupts for this device.
-
-Recommended properties :
- - fsl,rx-fifo-size : the size of the RX fifo slice (a multiple of 4)
- - fsl,tx-fifo-size : the size of the TX fifo slice (a multiple of 4)
-
-
-fsl,mpc5121-psc-fifo node
--------------------------
-
-Required properties :
- - compatible : Should be "fsl,mpc5121-psc-fifo"
- - reg : Offset and length of the register set for the PSC
-         FIFO Controller
- - interrupts : <a b> where a is the interrupt number of the
-   PSC FIFO Controller and b is a field that represents an
-   encoding of the sense and level information for the interrupt.
- - interrupt-parent : the phandle for the interrupt controller that
-   services interrupts for this device.
-
-
-Example for a board using PSC0 and PSC1 devices in serial mode:
-
-serial@11000 {
-       compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
-       cell-index = <0>;
-       reg = <0x11000 0x100>;
-       interrupts = <40 0x8>;
-       interrupt-parent = < &ipic >;
-       fsl,rx-fifo-size = <16>;
-       fsl,tx-fifo-size = <16>;
-};
-
-serial@11100 {
-       compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc";
-       cell-index = <1>;
-       reg = <0x11100 0x100>;
-       interrupts = <40 0x8>;
-       interrupt-parent = < &ipic >;
-       fsl,rx-fifo-size = <16>;
-       fsl,tx-fifo-size = <16>;
-};
-
-pscfifo@11f00 {
-       compatible = "fsl,mpc5121-psc-fifo";
-       reg = <0x11f00 0x100>;
-       interrupts = <40 0x8>;
-       interrupt-parent = < &ipic >;
-};
diff --git a/Documentation/powerpc/dts-bindings/fsl/mpc5200.txt b/Documentation/powerpc/dts-bindings/fsl/mpc5200.txt
deleted file mode 100644 (file)
index 4ccb2cd..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-MPC5200 Device Tree Bindings
-----------------------------
-
-(c) 2006-2009 Secret Lab Technologies Ltd
-Grant Likely <grant.likely@secretlab.ca>
-
-Naming conventions
-------------------
-For mpc5200 on-chip devices, the format for each compatible value is
-<chip>-<device>[-<mode>].  The OS should be able to match a device driver
-to the device based solely on the compatible value.  If two drivers
-match on the compatible list; the 'most compatible' driver should be
-selected.
-
-The split between the MPC5200 and the MPC5200B leaves a bit of a
-conundrum.  How should the compatible property be set up to provide
-maximum compatibility information; but still accurately describe the
-chip?  For the MPC5200; the answer is easy.  Most of the SoC devices
-originally appeared on the MPC5200.  Since they didn't exist anywhere
-else; the 5200 compatible properties will contain only one item;
-"fsl,mpc5200-<device>".
-
-The 5200B is almost the same as the 5200, but not quite.  It fixes
-silicon bugs and it adds a small number of enhancements.  Most of the
-devices either provide exactly the same interface as on the 5200.  A few
-devices have extra functions but still have a backwards compatible mode.
-To express this information as completely as possible, 5200B device trees
-should have two items in the compatible list:
-       compatible = "fsl,mpc5200b-<device>","fsl,mpc5200-<device>";
-
-It is *strongly* recommended that 5200B device trees follow this convention
-(instead of only listing the base mpc5200 item).
-
-ie. ethernet on mpc5200: compatible = "fsl,mpc5200-fec";
-    ethernet on mpc5200b: compatible = "fsl,mpc5200b-fec", "fsl,mpc5200-fec";
-
-Modal devices, like PSCs, also append the configured function to the
-end of the compatible field.  ie. A PSC in i2s mode would specify
-"fsl,mpc5200-psc-i2s", not "fsl,mpc5200-i2s".  This convention is chosen to
-avoid naming conflicts with non-psc devices providing the same
-function.  For example, "fsl,mpc5200-spi" and "fsl,mpc5200-psc-spi" describe
-the mpc5200 simple spi device and a PSC spi mode respectively.
-
-At the time of writing, exact chip may be either 'fsl,mpc5200' or
-'fsl,mpc5200b'.
-
-The soc node
-------------
-This node describes the on chip SOC peripherals.  Every mpc5200 based
-board will have this node, and as such there is a common naming
-convention for SOC devices.
-
-Required properties:
-name                   description
-----                   -----------
-ranges                 Memory range of the internal memory mapped registers.
-                       Should be <0 [baseaddr] 0xc000>
-reg                    Should be <[baseaddr] 0x100>
-compatible             mpc5200: "fsl,mpc5200-immr"
-                       mpc5200b: "fsl,mpc5200b-immr"
-system-frequency       'fsystem' frequency in Hz; XLB, IPB, USB and PCI
-                       clocks are derived from the fsystem clock.
-bus-frequency          IPB bus frequency in Hz.  Clock rate
-                       used by most of the soc devices.
-
-soc child nodes
----------------
-Any on chip SOC devices available to Linux must appear as soc5200 child nodes.
-
-Note: The tables below show the value for the mpc5200.  A mpc5200b device
-tree should use the "fsl,mpc5200b-<device>","fsl,mpc5200-<device>" form.
-
-Required soc5200 child nodes:
-name                           compatible              Description
-----                           ----------              -----------
-cdm@<addr>                     fsl,mpc5200-cdm         Clock Distribution
-interrupt-controller@<addr>    fsl,mpc5200-pic         need an interrupt
-                                                       controller to boot
-bestcomm@<addr>                        fsl,mpc5200-bestcomm    Bestcomm DMA controller
-
-Recommended soc5200 child nodes; populate as needed for your board
-name           compatible              Description
-----           ----------              -----------
-timer@<addr>   fsl,mpc5200-gpt          General purpose timers
-gpio@<addr>    fsl,mpc5200-gpio         MPC5200 simple gpio controller
-gpio@<addr>    fsl,mpc5200-gpio-wkup    MPC5200 wakeup gpio controller
-rtc@<addr>     fsl,mpc5200-rtc          Real time clock
-mscan@<addr>   fsl,mpc5200-mscan        CAN bus controller
-pci@<addr>     fsl,mpc5200-pci          PCI bridge
-serial@<addr>  fsl,mpc5200-psc-uart     PSC in serial mode
-i2s@<addr>     fsl,mpc5200-psc-i2s      PSC in i2s mode
-ac97@<addr>    fsl,mpc5200-psc-ac97     PSC in ac97 mode
-spi@<addr>     fsl,mpc5200-psc-spi      PSC in spi mode
-irda@<addr>    fsl,mpc5200-psc-irda     PSC in IrDA mode
-spi@<addr>     fsl,mpc5200-spi          MPC5200 spi device
-ethernet@<addr>        fsl,mpc5200-fec          MPC5200 ethernet device
-ata@<addr>     fsl,mpc5200-ata          IDE ATA interface
-i2c@<addr>     fsl,mpc5200-i2c          I2C controller
-usb@<addr>     fsl,mpc5200-ohci,ohci-be USB controller
-xlb@<addr>     fsl,mpc5200-xlb          XLB arbitrator
-
-fsl,mpc5200-gpt nodes
----------------------
-On the mpc5200 and 5200b, GPT0 has a watchdog timer function.  If the board
-design supports the internal wdt, then the device node for GPT0 should
-include the empty property 'fsl,has-wdt'.  Note that this does not activate
-the watchdog.  The timer will function as a GPT if the timer api is used, and
-it will function as watchdog if the watchdog device is used.  The watchdog
-mode has priority over the gpt mode, i.e. if the watchdog is activated, any
-gpt api call to this timer will fail with -EBUSY.
-
-If you add the property
-       fsl,wdt-on-boot = <n>;
-GPT0 will be marked as in-use watchdog, i.e. blocking every gpt access to it.
-If n>0, the watchdog is started with a timeout of n seconds.  If n=0, the
-configuration of the watchdog is not touched.  This is useful in two cases:
-- just mark GPT0 as watchdog, blocking gpt accesses, and configure it later;
-- do not touch a configuration assigned by the boot loader which supervises
-  the boot process itself.
-
-The watchdog will respect the CONFIG_WATCHDOG_NOWAYOUT option.
-
-An mpc5200-gpt can be used as a single line GPIO controller.  To do so,
-add the following properties to the gpt node:
-       gpio-controller;
-       #gpio-cells = <2>;
-When referencing the GPIO line from another node, the first cell must always
-be zero and the second cell represents the gpio flags and described in the
-gpio device tree binding.
-
-An mpc5200-gpt can be used as a single line edge sensitive interrupt
-controller.  To do so, add the following properties to the gpt node:
-       interrupt-controller;
-       #interrupt-cells = <1>;
-When referencing the IRQ line from another node, the cell represents the
-sense mode; 1 for edge rising, 2 for edge falling.
-
-fsl,mpc5200-psc nodes
----------------------
-The PSCs should include a cell-index which is the index of the PSC in
-hardware.  cell-index is used to determine which shared SoC registers to
-use when setting up PSC clocking.  cell-index number starts at '0'.  ie:
-       PSC1 has 'cell-index = <0>'
-       PSC4 has 'cell-index = <3>'
-
-PSC in i2s mode:  The mpc5200 and mpc5200b PSCs are not compatible when in
-i2s mode.  An 'mpc5200b-psc-i2s' node cannot include 'mpc5200-psc-i2s' in the
-compatible field.
-
-
-fsl,mpc5200-gpio and fsl,mpc5200-gpio-wkup nodes
-------------------------------------------------
-Each GPIO controller node should have the empty property gpio-controller and
-#gpio-cells set to 2. First cell is the GPIO number which is interpreted
-according to the bit numbers in the GPIO control registers. The second cell
-is for flags which is currently unused.
-
-fsl,mpc5200-fec nodes
----------------------
-The FEC node can specify one of the following properties to configure
-the MII link:
-- fsl,7-wire-mode - An empty property that specifies the link uses 7-wire
-                    mode instead of MII
-- current-speed   - Specifies that the MII should be configured for a fixed
-                    speed.  This property should contain two cells.  The
-                    first cell specifies the speed in Mbps and the second
-                    should be '0' for half duplex and '1' for full duplex
-- phy-handle      - Contains a phandle to an Ethernet PHY.
-
-Interrupt controller (fsl,mpc5200-pic) node
--------------------------------------------
-The mpc5200 pic binding splits hardware IRQ numbers into two levels.  The
-split reflects the layout of the PIC hardware itself, which groups
-interrupts into one of three groups; CRIT, MAIN or PERP.  Also, the
-Bestcomm dma engine has it's own set of interrupt sources which are
-cascaded off of peripheral interrupt 0, which the driver interprets as a
-fourth group, SDMA.
-
-The interrupts property for device nodes using the mpc5200 pic consists
-of three cells; <L1 L2 level>
-
-    L1 := [CRIT=0, MAIN=1, PERP=2, SDMA=3]
-    L2 := interrupt number; directly mapped from the value in the
-          "ICTL PerStat, MainStat, CritStat Encoded Register"
-    level := [LEVEL_HIGH=0, EDGE_RISING=1, EDGE_FALLING=2, LEVEL_LOW=3]
-
-For external IRQs, use the following interrupt property values (how to
-specify external interrupts is a frequently asked question):
-External interrupts:
-       external irq0:  interrupts = <0 0 n>;
-       external irq1:  interrupts = <1 1 n>;
-       external irq2:  interrupts = <1 2 n>;
-       external irq3:  interrupts = <1 3 n>;
-'n' is sense (0: level high, 1: edge rising, 2: edge falling 3: level low)
-
-fsl,mpc5200-mscan nodes
------------------------
-See file can.txt in this directory.
diff --git a/Documentation/powerpc/dts-bindings/fsl/mpic.txt b/Documentation/powerpc/dts-bindings/fsl/mpic.txt
deleted file mode 100644 (file)
index 71e39cf..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-* OpenPIC and its interrupt numbers on Freescale's e500/e600 cores
-
-The OpenPIC specification does not specify which interrupt source has to
-become which interrupt number. This is up to the software implementation
-of the interrupt controller. The only requirement is that every
-interrupt source has to have an unique interrupt number / vector number.
-To accomplish this the current implementation assigns the number zero to
-the first source, the number one to the second source and so on until
-all interrupt sources have their unique number.
-Usually the assigned vector number equals the interrupt number mentioned
-in the documentation for a given core / CPU. This is however not true
-for the e500 cores (MPC85XX CPUs) where the documentation distinguishes
-between internal and external interrupt sources and starts counting at
-zero for both of them.
-
-So what to write for external interrupt source X or internal interrupt
-source Y into the device tree? Here is an example:
-
-The memory map for the interrupt controller in the MPC8544[0] shows,
-that the first interrupt source starts at 0x5_0000 (PIC Register Address
-Map-Interrupt Source Configuration Registers). This source becomes the
-number zero therefore:
- External interrupt 0 = interrupt number 0
- External interrupt 1 = interrupt number 1
- External interrupt 2 = interrupt number 2
- ...
-Every interrupt number allocates 0x20 bytes register space. So to get
-its number it is sufficient to shift the lower 16bits to right by five.
-So for the external interrupt 10 we have:
-  0x0140 >> 5 = 10
-
-After the external sources, the internal sources follow. The in core I2C
-controller on the MPC8544 for instance has the internal source number
-27. Oo obtain its interrupt number we take the lower 16bits of its memory
-address (0x5_0560) and shift it right:
- 0x0560 >> 5 = 43
-
-Therefore the I2C device node for the MPC8544 CPU has to have the
-interrupt number 43 specified in the device tree.
-
-[0] MPC8544E PowerQUICCTM III, Integrated Host Processor Family Reference Manual
-    MPC8544ERM Rev. 1 10/2007
diff --git a/Documentation/powerpc/dts-bindings/fsl/msi-pic.txt b/Documentation/powerpc/dts-bindings/fsl/msi-pic.txt
deleted file mode 100644 (file)
index bcc30ba..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-* Freescale MSI interrupt controller
-
-Required properties:
-- compatible : compatible list, contains 2 entries,
-  first is "fsl,CHIP-msi", where CHIP is the processor(mpc8610, mpc8572,
-  etc.) and the second is "fsl,mpic-msi" or "fsl,ipic-msi" depending on
-  the parent type.
-- reg : should contain the address and the length of the shared message
-  interrupt register set.
-- msi-available-ranges: use <start count> style section to define which
-  msi interrupt can be used in the 256 msi interrupts. This property is
-  optional, without this, all the 256 MSI interrupts can be used.
-- interrupts : each one of the interrupts here is one entry per 32 MSIs,
-  and routed to the host interrupt controller. the interrupts should
-  be set as edge sensitive.
-- interrupt-parent: the phandle for the interrupt controller
-  that services interrupts for this device. for 83xx cpu, the interrupts
-  are routed to IPIC, and for 85xx/86xx cpu the interrupts are routed
-  to MPIC.
-
-Example:
-       msi@41600 {
-               compatible = "fsl,mpc8610-msi", "fsl,mpic-msi";
-               reg = <0x41600 0x80>;
-               msi-available-ranges = <0 0x100>;
-               interrupts = <
-                       0xe0 0
-                       0xe1 0
-                       0xe2 0
-                       0xe3 0
-                       0xe4 0
-                       0xe5 0
-                       0xe6 0
-                       0xe7 0>;
-               interrupt-parent = <&mpic>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/pmc.txt b/Documentation/powerpc/dts-bindings/fsl/pmc.txt
deleted file mode 100644 (file)
index 07256b7..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-* Power Management Controller
-
-Properties:
-- compatible: "fsl,<chip>-pmc".
-
-  "fsl,mpc8349-pmc" should be listed for any chip whose PMC is
-  compatible.  "fsl,mpc8313-pmc" should also be listed for any chip
-  whose PMC is compatible, and implies deep-sleep capability.
-
-  "fsl,mpc8548-pmc" should be listed for any chip whose PMC is
-  compatible.  "fsl,mpc8536-pmc" should also be listed for any chip
-  whose PMC is compatible, and implies deep-sleep capability.
-
-  "fsl,mpc8641d-pmc" should be listed for any chip whose PMC is
-  compatible; all statements below that apply to "fsl,mpc8548-pmc" also
-  apply to "fsl,mpc8641d-pmc".
-
-  Compatibility does not include bit assignments in SCCR/PMCDR/DEVDISR; these
-  bit assignments are indicated via the sleep specifier in each device's
-  sleep property.
-
-- reg: For devices compatible with "fsl,mpc8349-pmc", the first resource
-  is the PMC block, and the second resource is the Clock Configuration
-  block.
-
-  For devices compatible with "fsl,mpc8548-pmc", the first resource
-  is a 32-byte block beginning with DEVDISR.
-
-- interrupts: For "fsl,mpc8349-pmc"-compatible devices, the first
-  resource is the PMC block interrupt.
-
-- fsl,mpc8313-wakeup-timer: For "fsl,mpc8313-pmc"-compatible devices,
-  this is a phandle to an "fsl,gtm" node on which timer 4 can be used as
-  a wakeup source from deep sleep.
-
-Sleep specifiers:
-
-  fsl,mpc8349-pmc: Sleep specifiers consist of one cell.  For each bit
-  that is set in the cell, the corresponding bit in SCCR will be saved
-  and cleared on suspend, and restored on resume.  This sleep controller
-  supports disabling and resuming devices at any time.
-
-  fsl,mpc8536-pmc: Sleep specifiers consist of three cells, the third of
-  which will be ORed into PMCDR upon suspend, and cleared from PMCDR
-  upon resume.  The first two cells are as described for fsl,mpc8578-pmc.
-  This sleep controller only supports disabling devices during system
-  sleep, or permanently.
-
-  fsl,mpc8548-pmc: Sleep specifiers consist of one or two cells, the
-  first of which will be ORed into DEVDISR (and the second into
-  DEVDISR2, if present -- this cell should be zero or absent if the
-  hardware does not have DEVDISR2) upon a request for permanent device
-  disabling.  This sleep controller does not support configuring devices
-  to disable during system sleep (unless supported by another compatible
-  match), or dynamically.
-
-Example:
-
-       power@b00 {
-               compatible = "fsl,mpc8313-pmc", "fsl,mpc8349-pmc";
-               reg = <0xb00 0x100 0xa00 0x100>;
-               interrupts = <80 8>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/sata.txt b/Documentation/powerpc/dts-bindings/fsl/sata.txt
deleted file mode 100644 (file)
index b46bcf4..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-* Freescale 8xxx/3.0 Gb/s SATA nodes
-
-SATA nodes are defined to describe on-chip Serial ATA controllers.
-Each SATA port should have its own node.
-
-Required properties:
-- compatible        : compatible list, contains 2 entries, first is
-                "fsl,CHIP-sata", where CHIP is the processor
-                (mpc8315, mpc8379, etc.) and the second is
-                "fsl,pq-sata"
-- interrupts        : <interrupt mapping for SATA IRQ>
-- cell-index        : controller index.
-                          1 for controller @ 0x18000
-                          2 for controller @ 0x19000
-                          3 for controller @ 0x1a000
-                          4 for controller @ 0x1b000
-
-Optional properties:
-- interrupt-parent  : optional, if needed for interrupt mapping
-- reg               : <registers mapping>
-
-Example:
-       sata@18000 {
-               compatible = "fsl,mpc8379-sata", "fsl,pq-sata";
-               reg = <0x18000 0x1000>;
-               cell-index = <1>;
-               interrupts = <2c 8>;
-               interrupt-parent = < &ipic >;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/sec.txt b/Documentation/powerpc/dts-bindings/fsl/sec.txt
deleted file mode 100644 (file)
index 2b6f2d4..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-Freescale SoC SEC Security Engines
-
-Required properties:
-
-- compatible : Should contain entries for this and backward compatible
-  SEC versions, high to low, e.g., "fsl,sec2.1", "fsl,sec2.0"
-- reg : Offset and length of the register set for the device
-- interrupts : the SEC's interrupt number
-- fsl,num-channels : An integer representing the number of channels
-  available.
-- fsl,channel-fifo-len : An integer representing the number of
-  descriptor pointers each channel fetch fifo can hold.
-- fsl,exec-units-mask : The bitmask representing what execution units
-  (EUs) are available. It's a single 32-bit cell. EU information
-  should be encoded following the SEC's Descriptor Header Dword
-  EU_SEL0 field documentation, i.e. as follows:
-
-       bit 0  = reserved - should be 0
-       bit 1  = set if SEC has the ARC4 EU (AFEU)
-       bit 2  = set if SEC has the DES/3DES EU (DEU)
-       bit 3  = set if SEC has the message digest EU (MDEU/MDEU-A)
-       bit 4  = set if SEC has the random number generator EU (RNG)
-       bit 5  = set if SEC has the public key EU (PKEU)
-       bit 6  = set if SEC has the AES EU (AESU)
-       bit 7  = set if SEC has the Kasumi EU (KEU)
-       bit 8  = set if SEC has the CRC EU (CRCU)
-       bit 11 = set if SEC has the message digest EU extended alg set (MDEU-B)
-
-remaining bits are reserved for future SEC EUs.
-
-- fsl,descriptor-types-mask : The bitmask representing what descriptors
-  are available. It's a single 32-bit cell. Descriptor type information
-  should be encoded following the SEC's Descriptor Header Dword DESC_TYPE
-  field documentation, i.e. as follows:
-
-       bit 0  = set if SEC supports the aesu_ctr_nonsnoop desc. type
-       bit 1  = set if SEC supports the ipsec_esp descriptor type
-       bit 2  = set if SEC supports the common_nonsnoop desc. type
-       bit 3  = set if SEC supports the 802.11i AES ccmp desc. type
-       bit 4  = set if SEC supports the hmac_snoop_no_afeu desc. type
-       bit 5  = set if SEC supports the srtp descriptor type
-       bit 6  = set if SEC supports the non_hmac_snoop_no_afeu desc.type
-       bit 7  = set if SEC supports the pkeu_assemble descriptor type
-       bit 8  = set if SEC supports the aesu_key_expand_output desc.type
-       bit 9  = set if SEC supports the pkeu_ptmul descriptor type
-       bit 10 = set if SEC supports the common_nonsnoop_afeu desc. type
-       bit 11 = set if SEC supports the pkeu_ptadd_dbl descriptor type
-
-  ..and so on and so forth.
-
-Optional properties:
-
-- interrupt-parent : the phandle for the interrupt controller that
-  services interrupts for this device.
-
-Example:
-
-       /* MPC8548E */
-       crypto@30000 {
-               compatible = "fsl,sec2.1", "fsl,sec2.0";
-               reg = <0x30000 0x10000>;
-               interrupts = <29 2>;
-               interrupt-parent = <&mpic>;
-               fsl,num-channels = <4>;
-               fsl,channel-fifo-len = <24>;
-               fsl,exec-units-mask = <0xfe>;
-               fsl,descriptor-types-mask = <0x12b0ebf>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/spi.txt b/Documentation/powerpc/dts-bindings/fsl/spi.txt
deleted file mode 100644 (file)
index 777abd7..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-* SPI (Serial Peripheral Interface)
-
-Required properties:
-- cell-index : QE SPI subblock index.
-               0: QE subblock SPI1
-               1: QE subblock SPI2
-- compatible : should be "fsl,spi".
-- mode : the SPI operation mode, it can be "cpu" or "cpu-qe".
-- reg : Offset and length of the register set for the device
-- interrupts : <a b> where a is the interrupt number and b is a
-  field that represents an encoding of the sense and level
-  information for the interrupt.  This should be encoded based on
-  the information in section 2) depending on the type of interrupt
-  controller you have.
-- interrupt-parent : the phandle for the interrupt controller that
-  services interrupts for this device.
-
-Optional properties:
-- gpios : specifies the gpio pins to be used for chipselects.
-  The gpios will be referred to as reg = <index> in the SPI child nodes.
-  If unspecified, a single SPI device without a chip select can be used.
-
-Example:
-       spi@4c0 {
-               cell-index = <0>;
-               compatible = "fsl,spi";
-               reg = <4c0 40>;
-               interrupts = <82 0>;
-               interrupt-parent = <700>;
-               mode = "cpu";
-               gpios = <&gpio 18 1     // device reg=<0>
-                        &gpio 19 1>;   // device reg=<1>
-       };
-
-
-* eSPI (Enhanced Serial Peripheral Interface)
-
-Required properties:
-- compatible : should be "fsl,mpc8536-espi".
-- reg : Offset and length of the register set for the device.
-- interrupts : should contain eSPI interrupt, the device has one interrupt.
-- fsl,espi-num-chipselects : the number of the chipselect signals.
-
-Example:
-       spi@110000 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               compatible = "fsl,mpc8536-espi";
-               reg = <0x110000 0x1000>;
-               interrupts = <53 0x2>;
-               interrupt-parent = <&mpic>;
-               fsl,espi-num-chipselects = <4>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/ssi.txt b/Documentation/powerpc/dts-bindings/fsl/ssi.txt
deleted file mode 100644 (file)
index 5ff76c9..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-Freescale Synchronous Serial Interface
-
-The SSI is a serial device that communicates with audio codecs.  It can
-be programmed in AC97, I2S, left-justified, or right-justified modes.
-
-Required properties:
-- compatible:       Compatible list, contains "fsl,ssi".
-- cell-index:       The SSI, <0> = SSI1, <1> = SSI2, and so on.
-- reg:              Offset and length of the register set for the device.
-- interrupts:       <a b> where a is the interrupt number and b is a
-                    field that represents an encoding of the sense and
-                    level information for the interrupt.  This should be
-                    encoded based on the information in section 2)
-                    depending on the type of interrupt controller you
-                    have.
-- interrupt-parent: The phandle for the interrupt controller that
-                    services interrupts for this device.
-- fsl,mode:         The operating mode for the SSI interface.
-                    "i2s-slave" - I2S mode, SSI is clock slave
-                    "i2s-master" - I2S mode, SSI is clock master
-                    "lj-slave" - left-justified mode, SSI is clock slave
-                    "lj-master" - l.j. mode, SSI is clock master
-                    "rj-slave" - right-justified mode, SSI is clock slave
-                    "rj-master" - r.j., SSI is clock master
-                    "ac97-slave" - AC97 mode, SSI is clock slave
-                    "ac97-master" - AC97 mode, SSI is clock master
-- fsl,playback-dma: Phandle to a node for the DMA channel to use for
-                    playback of audio.  This is typically dictated by SOC
-                    design.  See the notes below.
-- fsl,capture-dma:  Phandle to a node for the DMA channel to use for
-                    capture (recording) of audio.  This is typically dictated
-                    by SOC design.  See the notes below.
-- fsl,fifo-depth:   The number of elements in the transmit and receive FIFOs.
-                    This number is the maximum allowed value for SFCSR[TFWM0].
-- fsl,ssi-asynchronous:
-                    If specified, the SSI is to be programmed in asynchronous
-                    mode.  In this mode, pins SRCK, STCK, SRFS, and STFS must
-                    all be connected to valid signals.  In synchronous mode,
-                    SRCK and SRFS are ignored.  Asynchronous mode allows
-                    playback and capture to use different sample sizes and
-                    sample rates.  Some drivers may require that SRCK and STCK
-                    be connected together, and SRFS and STFS be connected
-                    together.  This would still allow different sample sizes,
-                    but not different sample rates.
-
-Optional properties:
-- codec-handle:     Phandle to a 'codec' node that defines an audio
-                    codec connected to this SSI.  This node is typically
-                    a child of an I2C or other control node.
-
-Child 'codec' node required properties:
-- compatible:       Compatible list, contains the name of the codec
-
-Child 'codec' node optional properties:
-- clock-frequency:  The frequency of the input clock, which typically comes
-                    from an on-board dedicated oscillator.
-
-Notes on fsl,playback-dma and fsl,capture-dma:
-
-On SOCs that have an SSI, specific DMA channels are hard-wired for playback
-and capture.  On the MPC8610, for example, SSI1 must use DMA channel 0 for
-playback and DMA channel 1 for capture.  SSI2 must use DMA channel 2 for
-playback and DMA channel 3 for capture.  The developer can choose which
-DMA controller to use, but the channels themselves are hard-wired.  The
-purpose of these two properties is to represent this hardware design.
-
-The device tree nodes for the DMA channels that are referenced by
-"fsl,playback-dma" and "fsl,capture-dma" must be marked as compatible with
-"fsl,ssi-dma-channel".  The SOC-specific compatible string (e.g.
-"fsl,mpc8610-dma-channel") can remain.  If these nodes are left as
-"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel", then the generic Elo DMA
-drivers (fsldma) will attempt to use them, and it will conflict with the
-sound drivers.
diff --git a/Documentation/powerpc/dts-bindings/fsl/tsec.txt b/Documentation/powerpc/dts-bindings/fsl/tsec.txt
deleted file mode 100644 (file)
index edb7ae1..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-* MDIO IO device
-
-The MDIO is a bus to which the PHY devices are connected.  For each
-device that exists on this bus, a child node should be created.  See
-the definition of the PHY node in booting-without-of.txt for an example
-of how to define a PHY.
-
-Required properties:
-  - reg : Offset and length of the register set for the device
-  - compatible : Should define the compatible device type for the
-    mdio.  Currently, this is most likely to be "fsl,gianfar-mdio"
-
-Example:
-
-       mdio@24520 {
-               reg = <24520 20>;
-               compatible = "fsl,gianfar-mdio";
-
-               ethernet-phy@0 {
-                       ......
-               };
-       };
-
-* TBI Internal MDIO bus
-
-As of this writing, every tsec is associated with an internal TBI PHY.
-This PHY is accessed through the local MDIO bus.  These buses are defined
-similarly to the mdio buses, except they are compatible with "fsl,gianfar-tbi".
-The TBI PHYs underneath them are similar to normal PHYs, but the reg property
-is considered instructive, rather than descriptive.  The reg property should
-be chosen so it doesn't interfere with other PHYs on the bus.
-
-* Gianfar-compatible ethernet nodes
-
-Properties:
-
-  - device_type : Should be "network"
-  - model : Model of the device.  Can be "TSEC", "eTSEC", or "FEC"
-  - compatible : Should be "gianfar"
-  - reg : Offset and length of the register set for the device
-  - local-mac-address : List of bytes representing the ethernet address of
-    this controller
-  - interrupts : For FEC devices, the first interrupt is the device's
-    interrupt.  For TSEC and eTSEC devices, the first interrupt is
-    transmit, the second is receive, and the third is error.
-  - phy-handle : The phandle for the PHY connected to this ethernet
-    controller.
-  - fixed-link : <a b c d e> where a is emulated phy id - choose any,
-    but unique to the all specified fixed-links, b is duplex - 0 half,
-    1 full, c is link speed - d#10/d#100/d#1000, d is pause - 0 no
-    pause, 1 pause, e is asym_pause - 0 no asym_pause, 1 asym_pause.
-  - phy-connection-type : a string naming the controller/PHY interface type,
-    i.e., "mii" (default), "rmii", "gmii", "rgmii", "rgmii-id", "sgmii",
-    "tbi", or "rtbi".  This property is only really needed if the connection
-    is of type "rgmii-id", as all other connection types are detected by
-    hardware.
-  - fsl,magic-packet : If present, indicates that the hardware supports
-    waking up via magic packet.
-  - bd-stash : If present, indicates that the hardware supports stashing
-    buffer descriptors in the L2.
-  - rx-stash-len : Denotes the number of bytes of a received buffer to stash
-    in the L2.
-  - rx-stash-idx : Denotes the index of the first byte from the received
-    buffer to stash in the L2.
-
-Example:
-       ethernet@24000 {
-               device_type = "network";
-               model = "TSEC";
-               compatible = "gianfar";
-               reg = <0x24000 0x1000>;
-               local-mac-address = [ 00 E0 0C 00 73 00 ];
-               interrupts = <29 2 30 2 34 2>;
-               interrupt-parent = <&mpic>;
-               phy-handle = <&phy0>
-       };
diff --git a/Documentation/powerpc/dts-bindings/fsl/upm-nand.txt b/Documentation/powerpc/dts-bindings/fsl/upm-nand.txt
deleted file mode 100644 (file)
index a48b2ca..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-Freescale Localbus UPM programmed to work with NAND flash
-
-Required properties:
-- compatible : "fsl,upm-nand".
-- reg : should specify localbus chip select and size used for the chip.
-- fsl,upm-addr-offset : UPM pattern offset for the address latch.
-- fsl,upm-cmd-offset : UPM pattern offset for the command latch.
-
-Optional properties:
-- fsl,upm-wait-flags : add chip-dependent short delays after running the
-       UPM pattern (0x1), after writing a data byte (0x2) or after
-       writing out a buffer (0x4).
-- fsl,upm-addr-line-cs-offsets : address offsets for multi-chip support.
-       The corresponding address lines are used to select the chip.
-- gpios : may specify optional GPIOs connected to the Ready-Not-Busy pins
-       (R/B#). For multi-chip devices, "n" GPIO definitions are required
-       according to the number of chips.
-- chip-delay : chip dependent delay for transfering data from array to
-       read registers (tR). Required if property "gpios" is not used
-       (R/B# pins not connected).
-
-Examples:
-
-upm@1,0 {
-       compatible = "fsl,upm-nand";
-       reg = <1 0 1>;
-       fsl,upm-addr-offset = <16>;
-       fsl,upm-cmd-offset = <8>;
-       gpios = <&qe_pio_e 18 0>;
-
-       flash {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "...";
-
-               partition@0 {
-                       ...
-               };
-       };
-};
-
-upm@3,0 {
-       #address-cells = <0>;
-       #size-cells = <0>;
-       compatible = "tqc,tqm8548-upm-nand", "fsl,upm-nand";
-       reg = <3 0x0 0x800>;
-       fsl,upm-addr-offset = <0x10>;
-       fsl,upm-cmd-offset = <0x08>;
-       /* Multi-chip NAND device */
-       fsl,upm-addr-line-cs-offsets = <0x0 0x200>;
-       fsl,upm-wait-flags = <0x5>;
-       chip-delay = <25>; // in micro-seconds
-
-       nand@0 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-
-               partition@0 {
-                           label = "fs";
-                           reg = <0x00000000 0x10000000>;
-               };
-       };
-};
diff --git a/Documentation/powerpc/dts-bindings/fsl/usb.txt b/Documentation/powerpc/dts-bindings/fsl/usb.txt
deleted file mode 100644 (file)
index bd5723f..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-Freescale SOC USB controllers
-
-The device node for a USB controller that is part of a Freescale
-SOC is as described in the document "Open Firmware Recommended
-Practice : Universal Serial Bus" with the following modifications
-and additions :
-
-Required properties :
- - compatible : Should be "fsl-usb2-mph" for multi port host USB
-   controllers, or "fsl-usb2-dr" for dual role USB controllers
-   or "fsl,mpc5121-usb2-dr" for dual role USB controllers of MPC5121
- - phy_type : For multi port host USB controllers, should be one of
-   "ulpi", or "serial". For dual role USB controllers, should be
-   one of "ulpi", "utmi", "utmi_wide", or "serial".
- - reg : Offset and length of the register set for the device
- - port0 : boolean; if defined, indicates port0 is connected for
-   fsl-usb2-mph compatible controllers.  Either this property or
-   "port1" (or both) must be defined for "fsl-usb2-mph" compatible
-   controllers.
- - port1 : boolean; if defined, indicates port1 is connected for
-   fsl-usb2-mph compatible controllers.  Either this property or
-   "port0" (or both) must be defined for "fsl-usb2-mph" compatible
-   controllers.
- - dr_mode : indicates the working mode for "fsl-usb2-dr" compatible
-   controllers.  Can be "host", "peripheral", or "otg".  Default to
-   "host" if not defined for backward compatibility.
-
-Recommended properties :
- - interrupts : <a b> where a is the interrupt number and b is a
-   field that represents an encoding of the sense and level
-   information for the interrupt.  This should be encoded based on
-   the information in section 2) depending on the type of interrupt
-   controller you have.
- - interrupt-parent : the phandle for the interrupt controller that
-   services interrupts for this device.
-
-Optional properties :
- - fsl,invert-drvvbus : boolean; for MPC5121 USB0 only. Indicates the
-   port power polarity of internal PHY signal DRVVBUS is inverted.
- - fsl,invert-pwr-fault : boolean; for MPC5121 USB0 only. Indicates
-   the PWR_FAULT signal polarity is inverted.
-
-Example multi port host USB controller device node :
-       usb@22000 {
-               compatible = "fsl-usb2-mph";
-               reg = <22000 1000>;
-               #address-cells = <1>;
-               #size-cells = <0>;
-               interrupt-parent = <700>;
-               interrupts = <27 1>;
-               phy_type = "ulpi";
-               port0;
-               port1;
-       };
-
-Example dual role USB controller device node :
-       usb@23000 {
-               compatible = "fsl-usb2-dr";
-               reg = <23000 1000>;
-               #address-cells = <1>;
-               #size-cells = <0>;
-               interrupt-parent = <700>;
-               interrupts = <26 1>;
-               dr_mode = "otg";
-               phy = "ulpi";
-       };
-
-Example dual role USB controller device node for MPC5121ADS:
-
-       usb@4000 {
-               compatible = "fsl,mpc5121-usb2-dr";
-               reg = <0x4000 0x1000>;
-               #address-cells = <1>;
-               #size-cells = <0>;
-               interrupt-parent = < &ipic >;
-               interrupts = <44 0x8>;
-               dr_mode = "otg";
-               phy_type = "utmi_wide";
-               fsl,invert-drvvbus;
-               fsl,invert-pwr-fault;
-       };
diff --git a/Documentation/powerpc/dts-bindings/gpio/gpio.txt b/Documentation/powerpc/dts-bindings/gpio/gpio.txt
deleted file mode 100644 (file)
index edaa84d..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-Specifying GPIO information for devices
-============================================
-
-1) gpios property
------------------
-
-Nodes that makes use of GPIOs should define them using `gpios' property,
-format of which is: <&gpio-controller1-phandle gpio1-specifier
-                    &gpio-controller2-phandle gpio2-specifier
-                    0 /* holes are permitted, means no GPIO 3 */
-                    &gpio-controller4-phandle gpio4-specifier
-                    ...>;
-
-Note that gpio-specifier length is controller dependent.
-
-gpio-specifier may encode: bank, pin position inside the bank,
-whether pin is open-drain and whether pin is logically inverted.
-
-Example of the node using GPIOs:
-
-       node {
-               gpios = <&qe_pio_e 18 0>;
-       };
-
-In this example gpio-specifier is "18 0" and encodes GPIO pin number,
-and empty GPIO flags as accepted by the "qe_pio_e" gpio-controller.
-
-2) gpio-controller nodes
-------------------------
-
-Every GPIO controller node must have #gpio-cells property defined,
-this information will be used to translate gpio-specifiers.
-
-Example of two SOC GPIO banks defined as gpio-controller nodes:
-
-       qe_pio_a: gpio-controller@1400 {
-               #gpio-cells = <2>;
-               compatible = "fsl,qe-pario-bank-a", "fsl,qe-pario-bank";
-               reg = <0x1400 0x18>;
-               gpio-controller;
-       };
-
-       qe_pio_e: gpio-controller@1460 {
-               #gpio-cells = <2>;
-               compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
-               reg = <0x1460 0x18>;
-               gpio-controller;
-       };
-
-
diff --git a/Documentation/powerpc/dts-bindings/gpio/led.txt b/Documentation/powerpc/dts-bindings/gpio/led.txt
deleted file mode 100644 (file)
index 064db92..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-LEDs connected to GPIO lines
-
-Required properties:
-- compatible : should be "gpio-leds".
-
-Each LED is represented as a sub-node of the gpio-leds device.  Each
-node's name represents the name of the corresponding LED.
-
-LED sub-node properties:
-- gpios :  Should specify the LED's GPIO, see "Specifying GPIO information
-  for devices" in Documentation/powerpc/booting-without-of.txt.  Active
-  low LEDs should be indicated using flags in the GPIO specifier.
-- label :  (optional) The label for this LED.  If omitted, the label is
-  taken from the node name (excluding the unit address).
-- linux,default-trigger :  (optional) This parameter, if present, is a
-  string defining the trigger assigned to the LED.  Current triggers are:
-    "backlight" - LED will act as a back-light, controlled by the framebuffer
-                 system
-    "default-on" - LED will turn on, but see "default-state" below
-    "heartbeat" - LED "double" flashes at a load average based rate
-    "ide-disk" - LED indicates disk activity
-    "timer" - LED flashes at a fixed, configurable rate
-- default-state:  (optional) The initial state of the LED.  Valid
-  values are "on", "off", and "keep".  If the LED is already on or off
-  and the default-state property is set the to same value, then no
-  glitch should be produced where the LED momentarily turns off (or
-  on).  The "keep" setting will keep the LED at whatever its current
-  state is, without producing a glitch.  The default is off if this
-  property is not present.
-
-Examples:
-
-leds {
-       compatible = "gpio-leds";
-       hdd {
-               label = "IDE Activity";
-               gpios = <&mcu_pio 0 1>; /* Active low */
-               linux,default-trigger = "ide-disk";
-       };
-
-       fault {
-               gpios = <&mcu_pio 1 0>;
-               /* Keep LED on if BIOS detected hardware fault */
-               default-state = "keep";
-       };
-};
-
-run-control {
-       compatible = "gpio-leds";
-       red {
-               gpios = <&mpc8572 6 0>;
-               default-state = "off";
-       };
-       green {
-               gpios = <&mpc8572 7 0>;
-               default-state = "on";
-       };
-}
diff --git a/Documentation/powerpc/dts-bindings/gpio/mdio.txt b/Documentation/powerpc/dts-bindings/gpio/mdio.txt
deleted file mode 100644 (file)
index bc95495..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-MDIO on GPIOs
-
-Currently defined compatibles:
-- virtual,gpio-mdio
-
-MDC and MDIO lines connected to GPIO controllers are listed in the
-gpios property as described in section VIII.1 in the following order:
-
-MDC, MDIO.
-
-Example:
-
-mdio {
-       compatible = "virtual,mdio-gpio";
-       #address-cells = <1>;
-       #size-cells = <0>;
-       gpios = <&qe_pio_a 11
-                &qe_pio_c 6>;
-};
diff --git a/Documentation/powerpc/dts-bindings/marvell.txt b/Documentation/powerpc/dts-bindings/marvell.txt
deleted file mode 100644 (file)
index f1533d9..0000000
+++ /dev/null
@@ -1,521 +0,0 @@
-Marvell Discovery mv64[345]6x System Controller chips
-===========================================================
-
-The Marvell mv64[345]60 series of system controller chips contain
-many of the peripherals needed to implement a complete computer
-system.  In this section, we define device tree nodes to describe
-the system controller chip itself and each of the peripherals
-which it contains.  Compatible string values for each node are
-prefixed with the string "marvell,", for Marvell Technology Group Ltd.
-
-1) The /system-controller node
-
-  This node is used to represent the system-controller and must be
-  present when the system uses a system controller chip. The top-level
-  system-controller node contains information that is global to all
-  devices within the system controller chip. The node name begins
-  with "system-controller" followed by the unit address, which is
-  the base address of the memory-mapped register set for the system
-  controller chip.
-
-  Required properties:
-
-    - ranges : Describes the translation of system controller addresses
-      for memory mapped registers.
-    - clock-frequency: Contains the main clock frequency for the system
-      controller chip.
-    - reg : This property defines the address and size of the
-      memory-mapped registers contained within the system controller
-      chip.  The address specified in the "reg" property should match
-      the unit address of the system-controller node.
-    - #address-cells : Address representation for system controller
-      devices.  This field represents the number of cells needed to
-      represent the address of the memory-mapped registers of devices
-      within the system controller chip.
-    - #size-cells : Size representation for the memory-mapped
-      registers within the system controller chip.
-    - #interrupt-cells : Defines the width of cells used to represent
-      interrupts.
-
-  Optional properties:
-
-    - model : The specific model of the system controller chip.  Such
-      as, "mv64360", "mv64460", or "mv64560".
-    - compatible : A string identifying the compatibility identifiers
-      of the system controller chip.
-
-  The system-controller node contains child nodes for each system
-  controller device that the platform uses.  Nodes should not be created
-  for devices which exist on the system controller chip but are not used
-
-  Example Marvell Discovery mv64360 system-controller node:
-
-    system-controller@f1000000 { /* Marvell Discovery mv64360 */
-           #address-cells = <1>;
-           #size-cells = <1>;
-           model = "mv64360";                      /* Default */
-           compatible = "marvell,mv64360";
-           clock-frequency = <133333333>;
-           reg = <0xf1000000 0x10000>;
-           virtual-reg = <0xf1000000>;
-           ranges = <0x88000000 0x88000000 0x1000000 /* PCI 0 I/O Space */
-                   0x80000000 0x80000000 0x8000000 /* PCI 0 MEM Space */
-                   0xa0000000 0xa0000000 0x4000000 /* User FLASH */
-                   0x00000000 0xf1000000 0x0010000 /* Bridge's regs */
-                   0xf2000000 0xf2000000 0x0040000>;/* Integrated SRAM */
-
-           [ child node definitions... ]
-    }
-
-2) Child nodes of /system-controller
-
-   a) Marvell Discovery MDIO bus
-
-   The MDIO is a bus to which the PHY devices are connected.  For each
-   device that exists on this bus, a child node should be created.  See
-   the definition of the PHY node below for an example of how to define
-   a PHY.
-
-   Required properties:
-     - #address-cells : Should be <1>
-     - #size-cells : Should be <0>
-     - device_type : Should be "mdio"
-     - compatible : Should be "marvell,mv64360-mdio"
-
-   Example:
-
-     mdio {
-            #address-cells = <1>;
-            #size-cells = <0>;
-            device_type = "mdio";
-            compatible = "marvell,mv64360-mdio";
-
-            ethernet-phy@0 {
-                    ......
-            };
-     };
-
-
-   b) Marvell Discovery ethernet controller
-
-   The Discover ethernet controller is described with two levels
-   of nodes.  The first level describes an ethernet silicon block
-   and the second level describes up to 3 ethernet nodes within
-   that block.  The reason for the multiple levels is that the
-   registers for the node are interleaved within a single set
-   of registers.  The "ethernet-block" level describes the
-   shared register set, and the "ethernet" nodes describe ethernet
-   port-specific properties.
-
-   Ethernet block node
-
-   Required properties:
-     - #address-cells : <1>
-     - #size-cells : <0>
-     - compatible : "marvell,mv64360-eth-block"
-     - reg : Offset and length of the register set for this block
-
-   Example Discovery Ethernet block node:
-     ethernet-block@2000 {
-            #address-cells = <1>;
-            #size-cells = <0>;
-            compatible = "marvell,mv64360-eth-block";
-            reg = <0x2000 0x2000>;
-            ethernet@0 {
-                    .......
-            };
-     };
-
-   Ethernet port node
-
-   Required properties:
-     - device_type : Should be "network".
-     - compatible : Should be "marvell,mv64360-eth".
-     - reg : Should be <0>, <1>, or <2>, according to which registers
-       within the silicon block the device uses.
-     - interrupts : <a> where a is the interrupt number for the port.
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-     - phy : the phandle for the PHY connected to this ethernet
-       controller.
-     - local-mac-address : 6 bytes, MAC address
-
-   Example Discovery Ethernet port node:
-     ethernet@0 {
-            device_type = "network";
-            compatible = "marvell,mv64360-eth";
-            reg = <0>;
-            interrupts = <32>;
-            interrupt-parent = <&PIC>;
-            phy = <&PHY0>;
-            local-mac-address = [ 00 00 00 00 00 00 ];
-     };
-
-
-
-   c) Marvell Discovery PHY nodes
-
-   Required properties:
-     - device_type : Should be "ethernet-phy"
-     - interrupts : <a> where a is the interrupt number for this phy.
-     - interrupt-parent : the phandle for the interrupt controller that
-       services interrupts for this device.
-     - reg : The ID number for the phy, usually a small integer
-
-   Example Discovery PHY node:
-     ethernet-phy@1 {
-            device_type = "ethernet-phy";
-            compatible = "broadcom,bcm5421";
-            interrupts = <76>;      /* GPP 12 */
-            interrupt-parent = <&PIC>;
-            reg = <1>;
-     };
-
-
-   d) Marvell Discovery SDMA nodes
-
-   Represent DMA hardware associated with the MPSC (multiprotocol
-   serial controllers).
-
-   Required properties:
-     - compatible : "marvell,mv64360-sdma"
-     - reg : Offset and length of the register set for this device
-     - interrupts : <a> where a is the interrupt number for the DMA
-       device.
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery SDMA node:
-     sdma@4000 {
-            compatible = "marvell,mv64360-sdma";
-            reg = <0x4000 0xc18>;
-            virtual-reg = <0xf1004000>;
-            interrupts = <36>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   e) Marvell Discovery BRG nodes
-
-   Represent baud rate generator hardware associated with the MPSC
-   (multiprotocol serial controllers).
-
-   Required properties:
-     - compatible : "marvell,mv64360-brg"
-     - reg : Offset and length of the register set for this device
-     - clock-src : A value from 0 to 15 which selects the clock
-       source for the baud rate generator.  This value corresponds
-       to the CLKS value in the BRGx configuration register.  See
-       the mv64x60 User's Manual.
-     - clock-frequence : The frequency (in Hz) of the baud rate
-       generator's input clock.
-     - current-speed : The current speed setting (presumably by
-       firmware) of the baud rate generator.
-
-   Example Discovery BRG node:
-     brg@b200 {
-            compatible = "marvell,mv64360-brg";
-            reg = <0xb200 0x8>;
-            clock-src = <8>;
-            clock-frequency = <133333333>;
-            current-speed = <9600>;
-     };
-
-
-   f) Marvell Discovery CUNIT nodes
-
-   Represent the Serial Communications Unit device hardware.
-
-   Required properties:
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery CUNIT node:
-     cunit@f200 {
-            reg = <0xf200 0x200>;
-     };
-
-
-   g) Marvell Discovery MPSCROUTING nodes
-
-   Represent the Discovery's MPSC routing hardware
-
-   Required properties:
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery CUNIT node:
-     mpscrouting@b500 {
-            reg = <0xb400 0xc>;
-     };
-
-
-   h) Marvell Discovery MPSCINTR nodes
-
-   Represent the Discovery's MPSC DMA interrupt hardware registers
-   (SDMA cause and mask registers).
-
-   Required properties:
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery MPSCINTR node:
-     mpsintr@b800 {
-            reg = <0xb800 0x100>;
-     };
-
-
-   i) Marvell Discovery MPSC nodes
-
-   Represent the Discovery's MPSC (Multiprotocol Serial Controller)
-   serial port.
-
-   Required properties:
-     - device_type : "serial"
-     - compatible : "marvell,mv64360-mpsc"
-     - reg : Offset and length of the register set for this device
-     - sdma : the phandle for the SDMA node used by this port
-     - brg : the phandle for the BRG node used by this port
-     - cunit : the phandle for the CUNIT node used by this port
-     - mpscrouting : the phandle for the MPSCROUTING node used by this port
-     - mpscintr : the phandle for the MPSCINTR node used by this port
-     - cell-index : the hardware index of this cell in the MPSC core
-     - max_idle : value needed for MPSC CHR3 (Maximum Frame Length)
-       register
-     - interrupts : <a> where a is the interrupt number for the MPSC.
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery MPSCINTR node:
-     mpsc@8000 {
-            device_type = "serial";
-            compatible = "marvell,mv64360-mpsc";
-            reg = <0x8000 0x38>;
-            virtual-reg = <0xf1008000>;
-            sdma = <&SDMA0>;
-            brg = <&BRG0>;
-            cunit = <&CUNIT>;
-            mpscrouting = <&MPSCROUTING>;
-            mpscintr = <&MPSCINTR>;
-            cell-index = <0>;
-            max_idle = <40>;
-            interrupts = <40>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   j) Marvell Discovery Watch Dog Timer nodes
-
-   Represent the Discovery's watchdog timer hardware
-
-   Required properties:
-     - compatible : "marvell,mv64360-wdt"
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery Watch Dog Timer node:
-     wdt@b410 {
-            compatible = "marvell,mv64360-wdt";
-            reg = <0xb410 0x8>;
-     };
-
-
-   k) Marvell Discovery I2C nodes
-
-   Represent the Discovery's I2C hardware
-
-   Required properties:
-     - device_type : "i2c"
-     - compatible : "marvell,mv64360-i2c"
-     - reg : Offset and length of the register set for this device
-     - interrupts : <a> where a is the interrupt number for the I2C.
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery I2C node:
-            compatible = "marvell,mv64360-i2c";
-            reg = <0xc000 0x20>;
-            virtual-reg = <0xf100c000>;
-            interrupts = <37>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   l) Marvell Discovery PIC (Programmable Interrupt Controller) nodes
-
-   Represent the Discovery's PIC hardware
-
-   Required properties:
-     - #interrupt-cells : <1>
-     - #address-cells : <0>
-     - compatible : "marvell,mv64360-pic"
-     - reg : Offset and length of the register set for this device
-     - interrupt-controller
-
-   Example Discovery PIC node:
-     pic {
-            #interrupt-cells = <1>;
-            #address-cells = <0>;
-            compatible = "marvell,mv64360-pic";
-            reg = <0x0 0x88>;
-            interrupt-controller;
-     };
-
-
-   m) Marvell Discovery MPP (Multipurpose Pins) multiplexing nodes
-
-   Represent the Discovery's MPP hardware
-
-   Required properties:
-     - compatible : "marvell,mv64360-mpp"
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery MPP node:
-     mpp@f000 {
-            compatible = "marvell,mv64360-mpp";
-            reg = <0xf000 0x10>;
-     };
-
-
-   n) Marvell Discovery GPP (General Purpose Pins) nodes
-
-   Represent the Discovery's GPP hardware
-
-   Required properties:
-     - compatible : "marvell,mv64360-gpp"
-     - reg : Offset and length of the register set for this device
-
-   Example Discovery GPP node:
-     gpp@f000 {
-            compatible = "marvell,mv64360-gpp";
-            reg = <0xf100 0x20>;
-     };
-
-
-   o) Marvell Discovery PCI host bridge node
-
-   Represents the Discovery's PCI host bridge device.  The properties
-   for this node conform to Rev 2.1 of the PCI Bus Binding to IEEE
-   1275-1994.  A typical value for the compatible property is
-   "marvell,mv64360-pci".
-
-   Example Discovery PCI host bridge node
-     pci@80000000 {
-            #address-cells = <3>;
-            #size-cells = <2>;
-            #interrupt-cells = <1>;
-            device_type = "pci";
-            compatible = "marvell,mv64360-pci";
-            reg = <0xcf8 0x8>;
-            ranges = <0x01000000 0x0        0x0
-                            0x88000000 0x0 0x01000000
-                      0x02000000 0x0 0x80000000
-                            0x80000000 0x0 0x08000000>;
-            bus-range = <0 255>;
-            clock-frequency = <66000000>;
-            interrupt-parent = <&PIC>;
-            interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
-            interrupt-map = <
-                    /* IDSEL 0x0a */
-                    0x5000 0 0 1 &PIC 80
-                    0x5000 0 0 2 &PIC 81
-                    0x5000 0 0 3 &PIC 91
-                    0x5000 0 0 4 &PIC 93
-
-                    /* IDSEL 0x0b */
-                    0x5800 0 0 1 &PIC 91
-                    0x5800 0 0 2 &PIC 93
-                    0x5800 0 0 3 &PIC 80
-                    0x5800 0 0 4 &PIC 81
-
-                    /* IDSEL 0x0c */
-                    0x6000 0 0 1 &PIC 91
-                    0x6000 0 0 2 &PIC 93
-                    0x6000 0 0 3 &PIC 80
-                    0x6000 0 0 4 &PIC 81
-
-                    /* IDSEL 0x0d */
-                    0x6800 0 0 1 &PIC 93
-                    0x6800 0 0 2 &PIC 80
-                    0x6800 0 0 3 &PIC 81
-                    0x6800 0 0 4 &PIC 91
-            >;
-     };
-
-
-   p) Marvell Discovery CPU Error nodes
-
-   Represent the Discovery's CPU error handler device.
-
-   Required properties:
-     - compatible : "marvell,mv64360-cpu-error"
-     - reg : Offset and length of the register set for this device
-     - interrupts : the interrupt number for this device
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery CPU Error node:
-     cpu-error@0070 {
-            compatible = "marvell,mv64360-cpu-error";
-            reg = <0x70 0x10 0x128 0x28>;
-            interrupts = <3>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   q) Marvell Discovery SRAM Controller nodes
-
-   Represent the Discovery's SRAM controller device.
-
-   Required properties:
-     - compatible : "marvell,mv64360-sram-ctrl"
-     - reg : Offset and length of the register set for this device
-     - interrupts : the interrupt number for this device
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery SRAM Controller node:
-     sram-ctrl@0380 {
-            compatible = "marvell,mv64360-sram-ctrl";
-            reg = <0x380 0x80>;
-            interrupts = <13>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   r) Marvell Discovery PCI Error Handler nodes
-
-   Represent the Discovery's PCI error handler device.
-
-   Required properties:
-     - compatible : "marvell,mv64360-pci-error"
-     - reg : Offset and length of the register set for this device
-     - interrupts : the interrupt number for this device
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery PCI Error Handler node:
-     pci-error@1d40 {
-            compatible = "marvell,mv64360-pci-error";
-            reg = <0x1d40 0x40 0xc28 0x4>;
-            interrupts = <12>;
-            interrupt-parent = <&PIC>;
-     };
-
-
-   s) Marvell Discovery Memory Controller nodes
-
-   Represent the Discovery's memory controller device.
-
-   Required properties:
-     - compatible : "marvell,mv64360-mem-ctrl"
-     - reg : Offset and length of the register set for this device
-     - interrupts : the interrupt number for this device
-     - interrupt-parent : the phandle for the interrupt controller
-       that services interrupts for this device.
-
-   Example Discovery Memory Controller node:
-     mem-ctrl@1400 {
-            compatible = "marvell,mv64360-mem-ctrl";
-            reg = <0x1400 0x60>;
-            interrupts = <17>;
-            interrupt-parent = <&PIC>;
-     };
-
-
diff --git a/Documentation/powerpc/dts-bindings/mmc-spi-slot.txt b/Documentation/powerpc/dts-bindings/mmc-spi-slot.txt
deleted file mode 100644 (file)
index c39ac28..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-MMC/SD/SDIO slot directly connected to a SPI bus
-
-Required properties:
-- compatible : should be "mmc-spi-slot".
-- reg : should specify SPI address (chip-select number).
-- spi-max-frequency : maximum frequency for this device (Hz).
-- voltage-ranges : two cells are required, first cell specifies minimum
-  slot voltage (mV), second cell specifies maximum slot voltage (mV).
-  Several ranges could be specified.
-- gpios : (optional) may specify GPIOs in this order: Card-Detect GPIO,
-  Write-Protect GPIO.
-
-Example:
-
-       mmc-slot@0 {
-               compatible = "fsl,mpc8323rdb-mmc-slot",
-                            "mmc-spi-slot";
-               reg = <0>;
-               gpios = <&qe_pio_d 14 1
-                        &qe_pio_d 15 0>;
-               voltage-ranges = <3300 3300>;
-               spi-max-frequency = <50000000>;
-       };
diff --git a/Documentation/powerpc/dts-bindings/mtd-physmap.txt b/Documentation/powerpc/dts-bindings/mtd-physmap.txt
deleted file mode 100644 (file)
index 80152cb..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-CFI or JEDEC memory-mapped NOR flash, MTD-RAM (NVRAM...)
-
-Flash chips (Memory Technology Devices) are often used for solid state
-file systems on embedded devices.
-
- - compatible : should contain the specific model of mtd chip(s)
-   used, if known, followed by either "cfi-flash", "jedec-flash"
-   or "mtd-ram".
- - reg : Address range(s) of the mtd chip(s)
-   It's possible to (optionally) define multiple "reg" tuples so that
-   non-identical chips can be described in one node.
- - bank-width : Width (in bytes) of the bank.  Equal to the
-   device width times the number of interleaved chips.
- - device-width : (optional) Width of a single mtd chip.  If
-   omitted, assumed to be equal to 'bank-width'.
- - #address-cells, #size-cells : Must be present if the device has
-   sub-nodes representing partitions (see below).  In this case
-   both #address-cells and #size-cells must be equal to 1.
-
-For JEDEC compatible devices, the following additional properties
-are defined:
-
- - vendor-id : Contains the flash chip's vendor id (1 byte).
- - device-id : Contains the flash chip's device id (1 byte).
-
-In addition to the information on the mtd bank itself, the
-device tree may optionally contain additional information
-describing partitions of the address space.  This can be
-used on platforms which have strong conventions about which
-portions of a flash are used for what purposes, but which don't
-use an on-flash partition table such as RedBoot.
-
-Each partition is represented as a sub-node of the mtd device.
-Each node's name represents the name of the corresponding
-partition of the mtd device.
-
-Flash partitions
- - reg : The partition's offset and size within the mtd bank.
- - label : (optional) The label / name for this partition.
-   If omitted, the label is taken from the node name (excluding
-   the unit address).
- - read-only : (optional) This parameter, if present, is a hint to
-   Linux that this partition should only be mounted
-   read-only.  This is usually used for flash partitions
-   containing early-boot firmware images or data which should not
-   be clobbered.
-
-Example:
-
-       flash@ff000000 {
-               compatible = "amd,am29lv128ml", "cfi-flash";
-               reg = <ff000000 01000000>;
-               bank-width = <4>;
-               device-width = <1>;
-               #address-cells = <1>;
-               #size-cells = <1>;
-               fs@0 {
-                       label = "fs";
-                       reg = <0 f80000>;
-               };
-               firmware@f80000 {
-                       label ="firmware";
-                       reg = <f80000 80000>;
-                       read-only;
-               };
-       };
-
-Here an example with multiple "reg" tuples:
-
-       flash@f0000000,0 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "intel,PC48F4400P0VB", "cfi-flash";
-               reg = <0 0x00000000 0x02000000
-                      0 0x02000000 0x02000000>;
-               bank-width = <2>;
-               partition@0 {
-                       label = "test-part1";
-                       reg = <0 0x04000000>;
-               };
-       };
-
-An example using SRAM:
-
-       sram@2,0 {
-               compatible = "samsung,k6f1616u6a", "mtd-ram";
-               reg = <2 0 0x00200000>;
-               bank-width = <2>;
-       };
-
diff --git a/Documentation/powerpc/dts-bindings/nintendo/gamecube.txt b/Documentation/powerpc/dts-bindings/nintendo/gamecube.txt
deleted file mode 100644 (file)
index b558585..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-
-Nintendo GameCube device tree
-=============================
-
-1) The "flipper" node
-
-  This node represents the multi-function "Flipper" chip, which packages
-  many of the devices found in the Nintendo GameCube.
-
-  Required properties:
-
-   - compatible : Should be "nintendo,flipper"
-
-1.a) The Video Interface (VI) node
-
-  Represents the interface between the graphics processor and a external
-  video encoder.
-
-  Required properties:
-
-   - compatible : should be "nintendo,flipper-vi"
-   - reg : should contain the VI registers location and length
-   - interrupts : should contain the VI interrupt
-
-1.b) The Processor Interface (PI) node
-
-  Represents the data and control interface between the main processor
-  and graphics and audio processor.
-
-  Required properties:
-
-  - compatible : should be "nintendo,flipper-pi"
-  - reg : should contain the PI registers location and length
-
-1.b.i) The "Flipper" interrupt controller node
-
-  Represents the interrupt controller within the "Flipper" chip.
-  The node for the "Flipper" interrupt controller must be placed under
-  the PI node.
-
-  Required properties:
-
-  - compatible : should be "nintendo,flipper-pic"
-
-1.c) The Digital Signal Procesor (DSP) node
-
-  Represents the digital signal processor interface, designed to offload
-  audio related tasks.
-
-  Required properties:
-
-   - compatible : should be "nintendo,flipper-dsp"
-   - reg : should contain the DSP registers location and length
-   - interrupts : should contain the DSP interrupt
-
-1.c.i) The Auxiliary RAM (ARAM) node
-
-  Represents the non cpu-addressable ram designed mainly to store audio
-  related information.
-  The ARAM node must be placed under the DSP node.
-
-  Required properties:
-
-   - compatible : should be "nintendo,flipper-aram"
-   - reg : should contain the ARAM start (zero-based) and length
-
-1.d) The Disk Interface (DI) node
-
-  Represents the interface used to communicate with mass storage devices.
-
-  Required properties:
-
-   - compatible : should be "nintendo,flipper-di"
-   - reg : should contain the DI registers location and length
-   - interrupts : should contain the DI interrupt
-
-1.e) The Audio Interface (AI) node
-
-  Represents the interface to the external 16-bit stereo digital-to-analog
-  converter.
-
-  Required properties:
-
-   - compatible : should be "nintendo,flipper-ai"
-   - reg : should contain the AI registers location and length
-   - interrupts : should contain the AI interrupt
-
-1.f) The Serial Interface (SI) node
-
-  Represents the interface to the four single bit serial interfaces.
-  The SI is a proprietary serial interface used normally to control gamepads.
-  It's NOT a RS232-type interface.
-
-  Required properties:
-
-   - compatible : should be "nintendo,flipper-si"
-   - reg : should contain the SI registers location and length
-   - interrupts : should contain the SI interrupt
-
-1.g) The External Interface (EXI) node
-
-  Represents the multi-channel SPI-like interface.
-
-  Required properties:
-
-   - compatible : should be "nintendo,flipper-exi"
-   - reg : should contain the EXI registers location and length
-   - interrupts : should contain the EXI interrupt
-
diff --git a/Documentation/powerpc/dts-bindings/nintendo/wii.txt b/Documentation/powerpc/dts-bindings/nintendo/wii.txt
deleted file mode 100644 (file)
index a7e155a..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-
-Nintendo Wii device tree
-========================
-
-0) The root node
-
-  This node represents the Nintendo Wii video game console.
-
-  Required properties:
-
-   - model : Should be "nintendo,wii"
-   - compatible : Should be "nintendo,wii"
-
-1) The "hollywood" node
-
-  This node represents the multi-function "Hollywood" chip, which packages
-  many of the devices found in the Nintendo Wii.
-
-  Required properties:
-
-   - compatible : Should be "nintendo,hollywood"
-
-1.a) The Video Interface (VI) node
-
-  Represents the interface between the graphics processor and a external
-  video encoder.
-
-  Required properties:
-
-   - compatible : should be "nintendo,hollywood-vi","nintendo,flipper-vi"
-   - reg : should contain the VI registers location and length
-   - interrupts : should contain the VI interrupt
-
-1.b) The Processor Interface (PI) node
-
-  Represents the data and control interface between the main processor
-  and graphics and audio processor.
-
-  Required properties:
-
-  - compatible : should be "nintendo,hollywood-pi","nintendo,flipper-pi"
-  - reg : should contain the PI registers location and length
-
-1.b.i) The "Flipper" interrupt controller node
-
-  Represents the "Flipper" interrupt controller within the "Hollywood" chip.
-  The node for the "Flipper" interrupt controller must be placed under
-  the PI node.
-
-  Required properties:
-
-  - #interrupt-cells : <1>
-  - compatible : should be "nintendo,flipper-pic"
-  - interrupt-controller
-
-1.c) The Digital Signal Procesor (DSP) node
-
-  Represents the digital signal processor interface, designed to offload
-  audio related tasks.
-
-  Required properties:
-
-   - compatible : should be "nintendo,hollywood-dsp","nintendo,flipper-dsp"
-   - reg : should contain the DSP registers location and length
-   - interrupts : should contain the DSP interrupt
-
-1.d) The Serial Interface (SI) node
-
-  Represents the interface to the four single bit serial interfaces.
-  The SI is a proprietary serial interface used normally to control gamepads.
-  It's NOT a RS232-type interface.
-
-  Required properties:
-
-   - compatible : should be "nintendo,hollywood-si","nintendo,flipper-si"
-   - reg : should contain the SI registers location and length
-   - interrupts : should contain the SI interrupt
-
-1.e) The Audio Interface (AI) node
-
-  Represents the interface to the external 16-bit stereo digital-to-analog
-  converter.
-
-  Required properties:
-
-   - compatible : should be "nintendo,hollywood-ai","nintendo,flipper-ai"
-   - reg : should contain the AI registers location and length
-   - interrupts : should contain the AI interrupt
-
-1.f) The External Interface (EXI) node
-
-  Represents the multi-channel SPI-like interface.
-
-  Required properties:
-
-   - compatible : should be "nintendo,hollywood-exi","nintendo,flipper-exi"
-   - reg : should contain the EXI registers location and length
-   - interrupts : should contain the EXI interrupt
-
-1.g) The Open Host Controller Interface (OHCI) nodes
-
-  Represent the USB 1.x Open Host Controller Interfaces.
-
-  Required properties:
-
-   - compatible : should be "nintendo,hollywood-usb-ohci","usb-ohci"
-   - reg : should contain the OHCI registers location and length
-   - interrupts : should contain the OHCI interrupt
-
-1.h) The Enhanced Host Controller Interface (EHCI) node
-
-  Represents the USB 2.0 Enhanced Host Controller Interface.
-
-  Required properties:
-
-   - compatible : should be "nintendo,hollywood-usb-ehci","usb-ehci"
-   - reg : should contain the EHCI registers location and length
-   - interrupts : should contain the EHCI interrupt
-
-1.i) The Secure Digital Host Controller Interface (SDHCI) nodes
-
-  Represent the Secure Digital Host Controller Interfaces.
-
-  Required properties:
-
-   - compatible : should be "nintendo,hollywood-sdhci","sdhci"
-   - reg : should contain the SDHCI registers location and length
-   - interrupts : should contain the SDHCI interrupt
-
-1.j) The Inter-Processsor Communication (IPC) node
-
-  Represent the Inter-Processor Communication interface. This interface
-  enables communications between the Broadway and the Starlet processors.
-
-   - compatible : should be "nintendo,hollywood-ipc"
-   - reg : should contain the IPC registers location and length
-   - interrupts : should contain the IPC interrupt
-
-1.k) The "Hollywood" interrupt controller node
-
-  Represents the "Hollywood" interrupt controller within the
-  "Hollywood" chip.
-
-  Required properties:
-
-  - #interrupt-cells : <1>
-  - compatible : should be "nintendo,hollywood-pic"
-  - reg : should contain the controller registers location and length
-  - interrupt-controller
-  - interrupts : should contain the cascade interrupt of the "flipper" pic
-  - interrupt-parent: should contain the phandle of the "flipper" pic
-
-1.l) The General Purpose I/O (GPIO) controller node
-
-  Represents the dual access 32 GPIO controller interface.
-
-  Required properties:
-
-  - #gpio-cells : <2>
-  - compatible : should be "nintendo,hollywood-gpio"
-  - reg : should contain the IPC registers location and length
-  - gpio-controller
-
-1.m) The control node
-
-  Represents the control interface used to setup several miscellaneous
-  settings of the "Hollywood" chip like boot memory mappings, resets,
-  disk interface mode, etc.
-
-  Required properties:
-
-   - compatible : should be "nintendo,hollywood-control"
-   - reg : should contain the control registers location and length
-
-1.n) The Disk Interface (DI) node
-
-  Represents the interface used to communicate with mass storage devices.
-
-  Required properties:
-
-   - compatible : should be "nintendo,hollywood-di"
-   - reg : should contain the DI registers location and length
-   - interrupts : should contain the DI interrupt
-
diff --git a/Documentation/powerpc/dts-bindings/phy.txt b/Documentation/powerpc/dts-bindings/phy.txt
deleted file mode 100644 (file)
index bb8c742..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-PHY nodes
-
-Required properties:
-
- - device_type : Should be "ethernet-phy"
- - interrupts : <a b> where a is the interrupt number and b is a
-   field that represents an encoding of the sense and level
-   information for the interrupt.  This should be encoded based on
-   the information in section 2) depending on the type of interrupt
-   controller you have.
- - interrupt-parent : the phandle for the interrupt controller that
-   services interrupts for this device.
- - reg : The ID number for the phy, usually a small integer
- - linux,phandle :  phandle for this node; likely referenced by an
-   ethernet controller node.
-
-Example:
-
-ethernet-phy@0 {
-       linux,phandle = <2452000>
-       interrupt-parent = <40000>;
-       interrupts = <35 1>;
-       reg = <0>;
-       device_type = "ethernet-phy";
-};
diff --git a/Documentation/powerpc/dts-bindings/spi-bus.txt b/Documentation/powerpc/dts-bindings/spi-bus.txt
deleted file mode 100644 (file)
index e782add..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-SPI (Serial Peripheral Interface) busses
-
-SPI busses can be described with a node for the SPI master device
-and a set of child nodes for each SPI slave on the bus.  For this
-discussion, it is assumed that the system's SPI controller is in
-SPI master mode.  This binding does not describe SPI controllers
-in slave mode.
-
-The SPI master node requires the following properties:
-- #address-cells  - number of cells required to define a chip select
-               address on the SPI bus.
-- #size-cells     - should be zero.
-- compatible      - name of SPI bus controller following generic names
-               recommended practice.
-No other properties are required in the SPI bus node.  It is assumed
-that a driver for an SPI bus device will understand that it is an SPI bus.
-However, the binding does not attempt to define the specific method for
-assigning chip select numbers.  Since SPI chip select configuration is
-flexible and non-standardized, it is left out of this binding with the
-assumption that board specific platform code will be used to manage
-chip selects.  Individual drivers can define additional properties to
-support describing the chip select layout.
-
-SPI slave nodes must be children of the SPI master node and can
-contain the following properties.
-- reg             - (required) chip select address of device.
-- compatible      - (required) name of SPI device following generic names
-               recommended practice
-- spi-max-frequency - (required) Maximum SPI clocking speed of device in Hz
-- spi-cpol        - (optional) Empty property indicating device requires
-               inverse clock polarity (CPOL) mode
-- spi-cpha        - (optional) Empty property indicating device requires
-               shifted clock phase (CPHA) mode
-- spi-cs-high     - (optional) Empty property indicating device requires
-               chip select active high
-
-SPI example for an MPC5200 SPI bus:
-       spi@f00 {
-               #address-cells = <1>;
-               #size-cells = <0>;
-               compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
-               reg = <0xf00 0x20>;
-               interrupts = <2 13 0 2 14 0>;
-               interrupt-parent = <&mpc5200_pic>;
-
-               ethernet-switch@0 {
-                       compatible = "micrel,ks8995m";
-                       spi-max-frequency = <1000000>;
-                       reg = <0>;
-               };
-
-               codec@1 {
-                       compatible = "ti,tlv320aic26";
-                       spi-max-frequency = <100000>;
-                       reg = <1>;
-               };
-       };
diff --git a/Documentation/powerpc/dts-bindings/usb-ehci.txt b/Documentation/powerpc/dts-bindings/usb-ehci.txt
deleted file mode 100644 (file)
index fa18612..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-USB EHCI controllers
-
-Required properties:
-  - compatible : should be "usb-ehci".
-  - reg : should contain at least address and length of the standard EHCI
-    register set for the device. Optional platform-dependent registers
-    (debug-port or other) can be also specified here, but only after
-    definition of standard EHCI registers.
-  - interrupts : one EHCI interrupt should be described here.
-If device registers are implemented in big endian mode, the device
-node should have "big-endian-regs" property.
-If controller implementation operates with big endian descriptors,
-"big-endian-desc" property should be specified.
-If both big endian registers and descriptors are used by the controller
-implementation, "big-endian" property can be specified instead of having
-both "big-endian-regs" and "big-endian-desc".
-
-Example (Sequoia 440EPx):
-    ehci@e0000300 {
-          compatible = "ibm,usb-ehci-440epx", "usb-ehci";
-          interrupt-parent = <&UIC0>;
-          interrupts = <1a 4>;
-          reg = <0 e0000300 90 0 e0000390 70>;
-          big-endian;
-   };
diff --git a/Documentation/powerpc/dts-bindings/xilinx.txt b/Documentation/powerpc/dts-bindings/xilinx.txt
deleted file mode 100644 (file)
index 299d092..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-   d) Xilinx IP cores
-
-   The Xilinx EDK toolchain ships with a set of IP cores (devices) for use
-   in Xilinx Spartan and Virtex FPGAs.  The devices cover the whole range
-   of standard device types (network, serial, etc.) and miscellaneous
-   devices (gpio, LCD, spi, etc).  Also, since these devices are
-   implemented within the fpga fabric every instance of the device can be
-   synthesised with different options that change the behaviour.
-
-   Each IP-core has a set of parameters which the FPGA designer can use to
-   control how the core is synthesized.  Historically, the EDK tool would
-   extract the device parameters relevant to device drivers and copy them
-   into an 'xparameters.h' in the form of #define symbols.  This tells the
-   device drivers how the IP cores are configured, but it requires the kernel
-   to be recompiled every time the FPGA bitstream is resynthesized.
-
-   The new approach is to export the parameters into the device tree and
-   generate a new device tree each time the FPGA bitstream changes.  The
-   parameters which used to be exported as #defines will now become
-   properties of the device node.  In general, device nodes for IP-cores
-   will take the following form:
-
-       (name): (generic-name)@(base-address) {
-               compatible = "xlnx,(ip-core-name)-(HW_VER)"
-                            [, (list of compatible devices), ...];
-               reg = <(baseaddr) (size)>;
-               interrupt-parent = <&interrupt-controller-phandle>;
-               interrupts = < ... >;
-               xlnx,(parameter1) = "(string-value)";
-               xlnx,(parameter2) = <(int-value)>;
-       };
-
-       (generic-name):   an open firmware-style name that describes the
-                       generic class of device.  Preferably, this is one word, such
-                       as 'serial' or 'ethernet'.
-       (ip-core-name): the name of the ip block (given after the BEGIN
-                       directive in system.mhs).  Should be in lowercase
-                       and all underscores '_' converted to dashes '-'.
-       (name):         is derived from the "PARAMETER INSTANCE" value.
-       (parameter#):   C_* parameters from system.mhs.  The C_ prefix is
-                       dropped from the parameter name, the name is converted
-                       to lowercase and all underscore '_' characters are
-                       converted to dashes '-'.
-       (baseaddr):     the baseaddr parameter value (often named C_BASEADDR).
-       (HW_VER):       from the HW_VER parameter.
-       (size):         the address range size (often C_HIGHADDR - C_BASEADDR + 1).
-
-   Typically, the compatible list will include the exact IP core version
-   followed by an older IP core version which implements the same
-   interface or any other device with the same interface.
-
-   'reg', 'interrupt-parent' and 'interrupts' are all optional properties.
-
-   For example, the following block from system.mhs:
-
-       BEGIN opb_uartlite
-               PARAMETER INSTANCE = opb_uartlite_0
-               PARAMETER HW_VER = 1.00.b
-               PARAMETER C_BAUDRATE = 115200
-               PARAMETER C_DATA_BITS = 8
-               PARAMETER C_ODD_PARITY = 0
-               PARAMETER C_USE_PARITY = 0
-               PARAMETER C_CLK_FREQ = 50000000
-               PARAMETER C_BASEADDR = 0xEC100000
-               PARAMETER C_HIGHADDR = 0xEC10FFFF
-               BUS_INTERFACE SOPB = opb_7
-               PORT OPB_Clk = CLK_50MHz
-               PORT Interrupt = opb_uartlite_0_Interrupt
-               PORT RX = opb_uartlite_0_RX
-               PORT TX = opb_uartlite_0_TX
-               PORT OPB_Rst = sys_bus_reset_0
-       END
-
-   becomes the following device tree node:
-
-       opb_uartlite_0: serial@ec100000 {
-               device_type = "serial";
-               compatible = "xlnx,opb-uartlite-1.00.b";
-               reg = <ec100000 10000>;
-               interrupt-parent = <&opb_intc_0>;
-               interrupts = <1 0>; // got this from the opb_intc parameters
-               current-speed = <d#115200>;     // standard serial device prop
-               clock-frequency = <d#50000000>; // standard serial device prop
-               xlnx,data-bits = <8>;
-               xlnx,odd-parity = <0>;
-               xlnx,use-parity = <0>;
-       };
-
-   Some IP cores actually implement 2 or more logical devices.  In
-   this case, the device should still describe the whole IP core with
-   a single node and add a child node for each logical device.  The
-   ranges property can be used to translate from parent IP-core to the
-   registers of each device.  In addition, the parent node should be
-   compatible with the bus type 'xlnx,compound', and should contain
-   #address-cells and #size-cells, as with any other bus.  (Note: this
-   makes the assumption that both logical devices have the same bus
-   binding.  If this is not true, then separate nodes should be used
-   for each logical device).  The 'cell-index' property can be used to
-   enumerate logical devices within an IP core.  For example, the
-   following is the system.mhs entry for the dual ps2 controller found
-   on the ml403 reference design.
-
-       BEGIN opb_ps2_dual_ref
-               PARAMETER INSTANCE = opb_ps2_dual_ref_0
-               PARAMETER HW_VER = 1.00.a
-               PARAMETER C_BASEADDR = 0xA9000000
-               PARAMETER C_HIGHADDR = 0xA9001FFF
-               BUS_INTERFACE SOPB = opb_v20_0
-               PORT Sys_Intr1 = ps2_1_intr
-               PORT Sys_Intr2 = ps2_2_intr
-               PORT Clkin1 = ps2_clk_rx_1
-               PORT Clkin2 = ps2_clk_rx_2
-               PORT Clkpd1 = ps2_clk_tx_1
-               PORT Clkpd2 = ps2_clk_tx_2
-               PORT Rx1 = ps2_d_rx_1
-               PORT Rx2 = ps2_d_rx_2
-               PORT Txpd1 = ps2_d_tx_1
-               PORT Txpd2 = ps2_d_tx_2
-       END
-
-   It would result in the following device tree nodes:
-
-       opb_ps2_dual_ref_0: opb-ps2-dual-ref@a9000000 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "xlnx,compound";
-               ranges = <0 a9000000 2000>;
-               // If this device had extra parameters, then they would
-               // go here.
-               ps2@0 {
-                       compatible = "xlnx,opb-ps2-dual-ref-1.00.a";
-                       reg = <0 40>;
-                       interrupt-parent = <&opb_intc_0>;
-                       interrupts = <3 0>;
-                       cell-index = <0>;
-               };
-               ps2@1000 {
-                       compatible = "xlnx,opb-ps2-dual-ref-1.00.a";
-                       reg = <1000 40>;
-                       interrupt-parent = <&opb_intc_0>;
-                       interrupts = <3 0>;
-                       cell-index = <0>;
-               };
-       };
-
-   Also, the system.mhs file defines bus attachments from the processor
-   to the devices.  The device tree structure should reflect the bus
-   attachments.  Again an example; this system.mhs fragment:
-
-       BEGIN ppc405_virtex4
-               PARAMETER INSTANCE = ppc405_0
-               PARAMETER HW_VER = 1.01.a
-               BUS_INTERFACE DPLB = plb_v34_0
-               BUS_INTERFACE IPLB = plb_v34_0
-       END
-
-       BEGIN opb_intc
-               PARAMETER INSTANCE = opb_intc_0
-               PARAMETER HW_VER = 1.00.c
-               PARAMETER C_BASEADDR = 0xD1000FC0
-               PARAMETER C_HIGHADDR = 0xD1000FDF
-               BUS_INTERFACE SOPB = opb_v20_0
-       END
-
-       BEGIN opb_uart16550
-               PARAMETER INSTANCE = opb_uart16550_0
-               PARAMETER HW_VER = 1.00.d
-               PARAMETER C_BASEADDR = 0xa0000000
-               PARAMETER C_HIGHADDR = 0xa0001FFF
-               BUS_INTERFACE SOPB = opb_v20_0
-       END
-
-       BEGIN plb_v34
-               PARAMETER INSTANCE = plb_v34_0
-               PARAMETER HW_VER = 1.02.a
-       END
-
-       BEGIN plb_bram_if_cntlr
-               PARAMETER INSTANCE = plb_bram_if_cntlr_0
-               PARAMETER HW_VER = 1.00.b
-               PARAMETER C_BASEADDR = 0xFFFF0000
-               PARAMETER C_HIGHADDR = 0xFFFFFFFF
-               BUS_INTERFACE SPLB = plb_v34_0
-       END
-
-       BEGIN plb2opb_bridge
-               PARAMETER INSTANCE = plb2opb_bridge_0
-               PARAMETER HW_VER = 1.01.a
-               PARAMETER C_RNG0_BASEADDR = 0x20000000
-               PARAMETER C_RNG0_HIGHADDR = 0x3FFFFFFF
-               PARAMETER C_RNG1_BASEADDR = 0x60000000
-               PARAMETER C_RNG1_HIGHADDR = 0x7FFFFFFF
-               PARAMETER C_RNG2_BASEADDR = 0x80000000
-               PARAMETER C_RNG2_HIGHADDR = 0xBFFFFFFF
-               PARAMETER C_RNG3_BASEADDR = 0xC0000000
-               PARAMETER C_RNG3_HIGHADDR = 0xDFFFFFFF
-               BUS_INTERFACE SPLB = plb_v34_0
-               BUS_INTERFACE MOPB = opb_v20_0
-       END
-
-   Gives this device tree (some properties removed for clarity):
-
-       plb@0 {
-               #address-cells = <1>;
-               #size-cells = <1>;
-               compatible = "xlnx,plb-v34-1.02.a";
-               device_type = "ibm,plb";
-               ranges; // 1:1 translation
-
-               plb_bram_if_cntrl_0: bram@ffff0000 {
-                       reg = <ffff0000 10000>;
-               }
-
-               opb@20000000 {
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       ranges = <20000000 20000000 20000000
-                                 60000000 60000000 20000000
-                                 80000000 80000000 40000000
-                                 c0000000 c0000000 20000000>;
-
-                       opb_uart16550_0: serial@a0000000 {
-                               reg = <a00000000 2000>;
-                       };
-
-                       opb_intc_0: interrupt-controller@d1000fc0 {
-                               reg = <d1000fc0 20>;
-                       };
-               };
-       };
-
-   That covers the general approach to binding xilinx IP cores into the
-   device tree.  The following are bindings for specific devices:
-
-      i) Xilinx ML300 Framebuffer
-
-      Simple framebuffer device from the ML300 reference design (also on the
-      ML403 reference design as well as others).
-
-      Optional properties:
-       - resolution = <xres yres> : pixel resolution of framebuffer.  Some
-                                    implementations use a different resolution.
-                                    Default is <d#640 d#480>
-       - virt-resolution = <xvirt yvirt> : Size of framebuffer in memory.
-                                           Default is <d#1024 d#480>.
-       - rotate-display (empty) : rotate display 180 degrees.
-
-      ii) Xilinx SystemACE
-
-      The Xilinx SystemACE device is used to program FPGAs from an FPGA
-      bitstream stored on a CF card.  It can also be used as a generic CF
-      interface device.
-
-      Optional properties:
-       - 8-bit (empty) : Set this property for SystemACE in 8 bit mode
-
-      iii) Xilinx EMAC and Xilinx TEMAC
-
-      Xilinx Ethernet devices.  In addition to general xilinx properties
-      listed above, nodes for these devices should include a phy-handle
-      property, and may include other common network device properties
-      like local-mac-address.
-
-      iv) Xilinx Uartlite
-
-      Xilinx uartlite devices are simple fixed speed serial ports.
-
-      Required properties:
-       - current-speed : Baud rate of uartlite
-
-      v) Xilinx hwicap
-
-               Xilinx hwicap devices provide access to the configuration logic
-               of the FPGA through the Internal Configuration Access Port
-               (ICAP).  The ICAP enables partial reconfiguration of the FPGA,
-               readback of the configuration information, and some control over
-               'warm boots' of the FPGA fabric.
-
-               Required properties:
-               - xlnx,family : The family of the FPGA, necessary since the
-                      capabilities of the underlying ICAP hardware
-                      differ between different families.  May be
-                      'virtex2p', 'virtex4', or 'virtex5'.
-
-      vi) Xilinx Uart 16550
-
-      Xilinx UART 16550 devices are very similar to the NS16550 but with
-      different register spacing and an offset from the base address.
-
-      Required properties:
-       - clock-frequency : Frequency of the clock input
-       - reg-offset : A value of 3 is required
-       - reg-shift : A value of 2 is required
-
-      vii) Xilinx USB Host controller
-
-      The Xilinx USB host controller is EHCI compatible but with a different
-      base address for the EHCI registers, and it is always a big-endian
-      USB Host controller. The hardware can be configured as high speed only,
-      or high speed/full speed hybrid.
-
-      Required properties:
-      - xlnx,support-usb-fs: A value 0 means the core is built as high speed
-                             only. A value 1 means the core also supports
-                             full speed devices.
-
index 9104c10..2501604 100644 (file)
@@ -178,38 +178,29 @@ RTC class framework, but can't be supported by the older driver.
        setting the longer alarm time and enabling its IRQ using a single
        request (using the same model as EFI firmware).
 
-    *  RTC_UIE_ON, RTC_UIE_OFF ... if the RTC offers IRQs, it probably
-       also offers update IRQs whenever the "seconds" counter changes.
-       If needed, the RTC framework can emulate this mechanism.
+    *  RTC_UIE_ON, RTC_UIE_OFF ... if the RTC offers IRQs, the RTC framework
+       will emulate this mechanism.
 
-    *  RTC_PIE_ON, RTC_PIE_OFF, RTC_IRQP_SET, RTC_IRQP_READ ... another
-       feature often accessible with an IRQ line is a periodic IRQ, issued
-       at settable frequencies (usually 2^N Hz).
+    *  RTC_PIE_ON, RTC_PIE_OFF, RTC_IRQP_SET, RTC_IRQP_READ ... these icotls
+       are emulated via a kernel hrtimer.
 
 In many cases, the RTC alarm can be a system wake event, used to force
 Linux out of a low power sleep state (or hibernation) back to a fully
 operational state.  For example, a system could enter a deep power saving
 state until it's time to execute some scheduled tasks.
 
-Note that many of these ioctls need not actually be implemented by your
-driver.  The common rtc-dev interface handles many of these nicely if your
-driver returns ENOIOCTLCMD.  Some common examples:
+Note that many of these ioctls are handled by the common rtc-dev interface.
+Some common examples:
 
     *  RTC_RD_TIME, RTC_SET_TIME: the read_time/set_time functions will be
        called with appropriate values.
 
-    *  RTC_ALM_SET, RTC_ALM_READ, RTC_WKALM_SET, RTC_WKALM_RD: the
-       set_alarm/read_alarm functions will be called.
+    *  RTC_ALM_SET, RTC_ALM_READ, RTC_WKALM_SET, RTC_WKALM_RD: gets or sets
+       the alarm rtc_timer. May call the set_alarm driver function.
 
-    *  RTC_IRQP_SET, RTC_IRQP_READ: the irq_set_freq function will be called
-       to set the frequency while the framework will handle the read for you
-       since the frequency is stored in the irq_freq member of the rtc_device
-       structure.  Your driver needs to initialize the irq_freq member during
-       init.  Make sure you check the requested frequency is in range of your
-       hardware in the irq_set_freq function.  If it isn't, return -EINVAL.  If
-       you cannot actually change the frequency, do not define irq_set_freq.
+    *  RTC_IRQP_SET, RTC_IRQP_READ: These are emulated by the generic code.
 
-    *  RTC_PIE_ON, RTC_PIE_OFF: the irq_set_state function will be called.
+    *  RTC_PIE_ON, RTC_PIE_OFF: These are also emulated by the generic code.
 
 If all else fails, check out the rtc-test.c driver!
 
index 01e6940..1cd5d51 100644 (file)
@@ -1,3 +1,7 @@
+Version 15 of schedstats dropped counters for some sched_yield:
+yld_exp_empty, yld_act_empty and yld_both_empty. Otherwise, it is
+identical to version 14.
+
 Version 14 of schedstats includes support for sched_domains, which hit the
 mainline kernel in 2.6.20 although it is identical to the stats from version
 12 which was in the kernel from 2.6.13-2.6.19 (version 13 never saw a kernel
@@ -28,32 +32,25 @@ to write their own scripts, the fields are described here.
 
 CPU statistics
 --------------
-cpu<N> 1 2 3 4 5 6 7 8 9 10 11 12
-
-NOTE: In the sched_yield() statistics, the active queue is considered empty
-    if it has only one process in it, since obviously the process calling
-    sched_yield() is that process.
+cpu<N> 1 2 3 4 5 6 7 8 9
 
-First four fields are sched_yield() statistics:
-     1) # of times both the active and the expired queue were empty
-     2) # of times just the active queue was empty
-     3) # of times just the expired queue was empty
-     4) # of times sched_yield() was called
+First field is a sched_yield() statistic:
+     1) # of times sched_yield() was called
 
 Next three are schedule() statistics:
-     5) # of times we switched to the expired queue and reused it
-     6) # of times schedule() was called
-     7) # of times schedule() left the processor idle
+     2) # of times we switched to the expired queue and reused it
+     3) # of times schedule() was called
+     4) # of times schedule() left the processor idle
 
 Next two are try_to_wake_up() statistics:
-     8) # of times try_to_wake_up() was called
-     9) # of times try_to_wake_up() was called to wake up the local cpu
+     5) # of times try_to_wake_up() was called
+     6) # of times try_to_wake_up() was called to wake up the local cpu
 
 Next three are statistics describing scheduling latency:
-    10) sum of all time spent running by tasks on this processor (in jiffies)
-    11) sum of all time spent waiting to run by tasks on this processor (in
+     7) sum of all time spent running by tasks on this processor (in jiffies)
+     8) sum of all time spent waiting to run by tasks on this processor (in
         jiffies)
-    12) # of timeslices run on this cpu
+     9) # of timeslices run on this cpu
 
 
 Domain statistics
index 16ae430..0caf77e 100644 (file)
@@ -296,6 +296,7 @@ Conexant 5066
 =============
   laptop       Basic Laptop config (default)
   hp-laptop    HP laptops, e g G60
+  asus         Asus K52JU, Lenovo G560
   dell-laptop  Dell laptops
   dell-vostro  Dell Vostro
   olpc-xo-1_5  OLPC XO 1.5
index 178c831..2e3c64b 100644 (file)
@@ -86,7 +86,7 @@ to change the variables it has to get an exclusive write lock.
 
 The routines look the same as above:
 
-   rwlock_t xxx_lock = RW_LOCK_UNLOCKED;
+   rwlock_t xxx_lock = __RW_LOCK_UNLOCKED(xxx_lock);
 
        unsigned long flags;
 
@@ -196,25 +196,3 @@ appropriate:
 
 For static initialization, use DEFINE_SPINLOCK() / DEFINE_RWLOCK() or
 __SPIN_LOCK_UNLOCKED() / __RW_LOCK_UNLOCKED() as appropriate.
-
-SPIN_LOCK_UNLOCKED and RW_LOCK_UNLOCKED are deprecated.  These interfere
-with lockdep state tracking.
-
-Most of the time, you can simply turn:
-       static spinlock_t xxx_lock = SPIN_LOCK_UNLOCKED;
-into:
-       static DEFINE_SPINLOCK(xxx_lock);
-
-Static structure member variables go from:
-
-       struct foo bar {
-               .lock   =       SPIN_LOCK_UNLOCKED;
-       };
-
-to:
-
-       struct foo bar {
-               .lock   =       __SPIN_LOCK_UNLOCKED(bar.lock);
-       };
-
-Declaration of static rw_locks undergo a similar transformation.
index dc52bd4..79fcafc 100644 (file)
@@ -247,6 +247,13 @@ You need very few things to get the syscalls tracing in an arch.
 - Support the TIF_SYSCALL_TRACEPOINT thread flags.
 - Put the trace_sys_enter() and trace_sys_exit() tracepoints calls from ptrace
   in the ptrace syscalls tracing path.
+- If the system call table on this arch is more complicated than a simple array
+  of addresses of the system calls, implement an arch_syscall_addr to return
+  the address of a given system call.
+- If the symbol names of the system calls do not match the function names on
+  this arch, define ARCH_HAS_SYSCALL_MATCH_SYM_NAME in asm/ftrace.h and
+  implement arch_syscall_match_sym_name with the appropriate logic to return
+  true if the function name corresponds with the symbol name.
 - Tag this arch as HAVE_SYSCALL_TRACEPOINTS.
 
 
index 557c1ed..1ebc24c 100644 (file)
@@ -80,11 +80,11 @@ of ftrace. Here is a list of some of the key files:
        tracers listed here can be configured by
        echoing their name into current_tracer.
 
-  tracing_enabled:
+  tracing_on:
 
-       This sets or displays whether the current_tracer
-       is activated and tracing or not. Echo 0 into this
-       file to disable the tracer or 1 to enable it.
+       This sets or displays whether writing to the trace
+       ring buffer is enabled. Echo 0 into this file to disable
+       the tracer or 1 to enable it.
 
   trace:
 
@@ -202,10 +202,6 @@ Here is the list of current tracers that may be configured.
        to draw a graph of function calls similar to C code
        source.
 
-  "sched_switch"
-
-       Traces the context switches and wakeups between tasks.
-
   "irqsoff"
 
        Traces the areas that disable interrupts and saves
@@ -273,39 +269,6 @@ format, the function name that was traced "path_put" and the
 parent function that called this function "path_walk". The
 timestamp is the time at which the function was entered.
 
-The sched_switch tracer also includes tracing of task wakeups
-and context switches.
-
-     ksoftirqd/1-7     [01]  1453.070013:      7:115:R   +  2916:115:S
-     ksoftirqd/1-7     [01]  1453.070013:      7:115:R   +    10:115:S
-     ksoftirqd/1-7     [01]  1453.070013:      7:115:R ==>    10:115:R
-        events/1-10    [01]  1453.070013:     10:115:S ==>  2916:115:R
-     kondemand/1-2916  [01]  1453.070013:   2916:115:S ==>     7:115:R
-     ksoftirqd/1-7     [01]  1453.070013:      7:115:S ==>     0:140:R
-
-Wake ups are represented by a "+" and the context switches are
-shown as "==>".  The format is:
-
- Context switches:
-
-       Previous task              Next Task
-
-  <pid>:<prio>:<state>  ==>  <pid>:<prio>:<state>
-
- Wake ups:
-
-       Current task               Task waking up
-
-  <pid>:<prio>:<state>    +  <pid>:<prio>:<state>
-
-The prio is the internal kernel priority, which is the inverse
-of the priority that is usually displayed by user-space tools.
-Zero represents the highest priority (99). Prio 100 starts the
-"nice" priorities with 100 being equal to nice -20 and 139 being
-nice 19. The prio "140" is reserved for the idle task which is
-the lowest priority thread (pid 0).
-
-
 Latency trace format
 --------------------
 
@@ -491,78 +454,10 @@ x494] <- /root/a.out[+0x4a8] <- /lib/libc-2.7.so[+0x1e1a6]
                    latencies, as described in "Latency
                    trace format".
 
-sched_switch
-------------
-
-This tracer simply records schedule switches. Here is an example
-of how to use it.
-
- # echo sched_switch > current_tracer
- # echo 1 > tracing_enabled
- # sleep 1
- # echo 0 > tracing_enabled
- # cat trace
-
-# tracer: sched_switch
-#
-#           TASK-PID   CPU#    TIMESTAMP  FUNCTION
-#              | |      |          |         |
-            bash-3997  [01]   240.132281:   3997:120:R   +  4055:120:R
-            bash-3997  [01]   240.132284:   3997:120:R ==>  4055:120:R
-           sleep-4055  [01]   240.132371:   4055:120:S ==>  3997:120:R
-            bash-3997  [01]   240.132454:   3997:120:R   +  4055:120:S
-            bash-3997  [01]   240.132457:   3997:120:R ==>  4055:120:R
-           sleep-4055  [01]   240.132460:   4055:120:D ==>  3997:120:R
-            bash-3997  [01]   240.132463:   3997:120:R   +  4055:120:D
-            bash-3997  [01]   240.132465:   3997:120:R ==>  4055:120:R
-          <idle>-0     [00]   240.132589:      0:140:R   +     4:115:S
-          <idle>-0     [00]   240.132591:      0:140:R ==>     4:115:R
-     ksoftirqd/0-4     [00]   240.132595:      4:115:S ==>     0:140:R
-          <idle>-0     [00]   240.132598:      0:140:R   +     4:115:S
-          <idle>-0     [00]   240.132599:      0:140:R ==>     4:115:R
-     ksoftirqd/0-4     [00]   240.132603:      4:115:S ==>     0:140:R
-           sleep-4055  [01]   240.133058:   4055:120:S ==>  3997:120:R
- [...]
-
-
-As we have discussed previously about this format, the header
-shows the name of the trace and points to the options. The
-"FUNCTION" is a misnomer since here it represents the wake ups
-and context switches.
-
-The sched_switch file only lists the wake ups (represented with
-'+') and context switches ('==>') with the previous task or
-current task first followed by the next task or task waking up.
-The format for both of these is PID:KERNEL-PRIO:TASK-STATE.
-Remember that the KERNEL-PRIO is the inverse of the actual
-priority with zero (0) being the highest priority and the nice
-values starting at 100 (nice -20). Below is a quick chart to map
-the kernel priority to user land priorities.
-
-   Kernel Space                     User Space
- ===============================================================
-   0(high) to  98(low)     user RT priority 99(high) to 1(low)
-                           with SCHED_RR or SCHED_FIFO
- ---------------------------------------------------------------
-  99                       sched_priority is not used in scheduling
-                           decisions(it must be specified as 0)
- ---------------------------------------------------------------
- 100(high) to 139(low)     user nice -20(high) to 19(low)
- ---------------------------------------------------------------
- 140                       idle task priority
- ---------------------------------------------------------------
-
-The task states are:
-
- R - running : wants to run, may not actually be running
- S - sleep   : process is waiting to be woken up (handles signals)
- D - disk sleep (uninterruptible sleep) : process must be woken up
-                                       (ignores signals)
- T - stopped : process suspended
- t - traced  : process is being traced (with something like gdb)
- Z - zombie  : process waiting to be cleaned up
- X - unknown
-
+  overwrite - This controls what happens when the trace buffer is
+              full. If "1" (default), the oldest events are
+              discarded and overwritten. If "0", then the newest
+              events are discarded.
 
 ftrace_enabled
 --------------
@@ -607,10 +502,10 @@ an example:
  # echo irqsoff > current_tracer
  # echo latency-format > trace_options
  # echo 0 > tracing_max_latency
- # echo 1 > tracing_enabled
+ # echo 1 > tracing_on
  # ls -ltr
  [...]
- # echo 0 > tracing_enabled
+ # echo 0 > tracing_on
  # cat trace
 # tracer: irqsoff
 #
@@ -715,10 +610,10 @@ is much like the irqsoff tracer.
  # echo preemptoff > current_tracer
  # echo latency-format > trace_options
  # echo 0 > tracing_max_latency
- # echo 1 > tracing_enabled
+ # echo 1 > tracing_on
  # ls -ltr
  [...]
- # echo 0 > tracing_enabled
+ # echo 0 > tracing_on
  # cat trace
 # tracer: preemptoff
 #
@@ -863,10 +758,10 @@ tracers.
  # echo preemptirqsoff > current_tracer
  # echo latency-format > trace_options
  # echo 0 > tracing_max_latency
- # echo 1 > tracing_enabled
+ # echo 1 > tracing_on
  # ls -ltr
  [...]
- # echo 0 > tracing_enabled
+ # echo 0 > tracing_on
  # cat trace
 # tracer: preemptirqsoff
 #
@@ -1026,9 +921,9 @@ Instead of performing an 'ls', we will run 'sleep 1' under
  # echo wakeup > current_tracer
  # echo latency-format > trace_options
  # echo 0 > tracing_max_latency
- # echo 1 > tracing_enabled
+ # echo 1 > tracing_on
  # chrt -f 5 sleep 1
- # echo 0 > tracing_enabled
+ # echo 0 > tracing_on
  # cat trace
 # tracer: wakeup
 #
@@ -1140,9 +1035,9 @@ ftrace_enabled is set; otherwise this tracer is a nop.
 
  # sysctl kernel.ftrace_enabled=1
  # echo function > current_tracer
- # echo 1 > tracing_enabled
+ # echo 1 > tracing_on
  # usleep 1
- # echo 0 > tracing_enabled
+ # echo 0 > tracing_on
  # cat trace
 # tracer: function
 #
@@ -1180,7 +1075,7 @@ int trace_fd;
 [...]
 int main(int argc, char *argv[]) {
        [...]
-       trace_fd = open(tracing_file("tracing_enabled"), O_WRONLY);
+       trace_fd = open(tracing_file("tracing_on"), O_WRONLY);
        [...]
        if (condition_hit()) {
                write(trace_fd, "0", 1);
@@ -1631,9 +1526,9 @@ If I am only interested in sys_nanosleep and hrtimer_interrupt:
  # echo sys_nanosleep hrtimer_interrupt \
                > set_ftrace_filter
  # echo function > current_tracer
- # echo 1 > tracing_enabled
+ # echo 1 > tracing_on
  # usleep 1
- # echo 0 > tracing_enabled
+ # echo 0 > tracing_on
  # cat trace
 # tracer: ftrace
 #
@@ -1879,9 +1774,9 @@ different. The trace is live.
  # echo function > current_tracer
  # cat trace_pipe > /tmp/trace.out &
 [1] 4153
- # echo 1 > tracing_enabled
+ # echo 1 > tracing_on
  # usleep 1
- # echo 0 > tracing_enabled
+ # echo 0 > tracing_on
  # cat trace
 # tracer: function
 #
index 5f77d94..6d27ab8 100644 (file)
@@ -42,11 +42,25 @@ Synopsis of kprobe_events
   +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**)
   NAME=FETCHARG : Set NAME as the argument name of FETCHARG.
   FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types
-                 (u8/u16/u32/u64/s8/s16/s32/s64) and string are supported.
+                 (u8/u16/u32/u64/s8/s16/s32/s64), "string" and bitfield
+                 are supported.
 
   (*) only for return probe.
   (**) this is useful for fetching a field of data structures.
 
+Types
+-----
+Several types are supported for fetch-args. Kprobe tracer will access memory
+by given type. Prefix 's' and 'u' means those types are signed and unsigned
+respectively. Traced arguments are shown in decimal (signed) or hex (unsigned).
+String type is a special type, which fetches a "null-terminated" string from
+kernel space. This means it will fail and store NULL if the string container
+has been paged out.
+Bitfield is another special type, which takes 3 parameters, bit-width, bit-
+offset, and container-size (usually 32). The syntax is;
+
+ b<bit-width>@<bit-offset>/<container-size>
+
 
 Per-Probe Event Filtering
 -------------------------
index 996a27d..01c513f 100644 (file)
@@ -190,9 +190,9 @@ resources, scheduled and executed.
        * Long running CPU intensive workloads which can be better
          managed by the system scheduler.
 
-  WQ_FREEZEABLE
+  WQ_FREEZABLE
 
-       A freezeable wq participates in the freeze phase of the system
+       A freezable wq participates in the freeze phase of the system
        suspend operations.  Work items on the wq are drained and no
        new work item starts execution until thawed.
 
index cf0f3a5..f1bc3dc 100644 (file)
@@ -885,7 +885,7 @@ S:  Supported
 
 ARM/QUALCOMM MSM MACHINE SUPPORT
 M:     David Brown <davidb@codeaurora.org>
-M:     Daniel Walker <dwalker@codeaurora.org>
+M:     Daniel Walker <dwalker@fifo99.com>
 M:     Bryan Huntsman <bryanh@codeaurora.org>
 L:     linux-arm-msm@vger.kernel.org
 F:     arch/arm/mach-msm/
@@ -978,6 +978,8 @@ S:  Maintained
 F:     arch/arm/plat-samsung/
 F:     arch/arm/plat-s3c24xx/
 F:     arch/arm/plat-s5p/
+F:     drivers/*/*s3c2410*
+F:     drivers/*/*/*s3c2410*
 
 ARM/S3C2410 ARM ARCHITECTURE
 M:     Ben Dooks <ben-linux@fluff.org>
@@ -1008,6 +1010,15 @@ L:       linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-s5p*/
 
+ARM/SAMSUNG MOBILE MACHINE SUPPORT
+M:     Kyungmin Park <kyungmin.park@samsung.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     arch/arm/mach-s5pv210/mach-aquila.c
+F:     arch/arm/mach-s5pv210/mach-goni.c
+F:     arch/arm/mach-exynos4/mach-universal_c210.c
+F:     arch/arm/mach-exynos4/mach-nuri.c
+
 ARM/SAMSUNG S5P SERIES FIMC SUPPORT
 M:     Kyungmin Park <kyungmin.park@samsung.com>
 M:     Sylwester Nawrocki <s.nawrocki@samsung.com>
@@ -1465,6 +1476,7 @@ F:        include/net/bluetooth/
 
 BONDING DRIVER
 M:     Jay Vosburgh <fubar@us.ibm.com>
+M:     Andy Gospodarek <andy@greyhouse.net>
 L:     netdev@vger.kernel.org
 W:     http://sourceforge.net/projects/bonding/
 S:     Supported
@@ -1690,6 +1702,13 @@ M:       Andy Whitcroft <apw@canonical.com>
 S:     Supported
 F:     scripts/checkpatch.pl
 
+CHINESE DOCUMENTATION
+M:     Harry Wei <harryxiyou@gmail.com>
+L:     xiyoulinuxkernelgroup@googlegroups.com
+L:     linux-kernel@zh-kernel.org (moderated for non-subscribers)
+S:     Maintained
+F:     Documentation/zh_CN/
+
 CISCO VIC ETHERNET NIC DRIVER
 M:     Vasanthy Kolluri <vkolluri@cisco.com>
 M:     Roopa Prabhu <roprabhu@cisco.com>
@@ -2024,7 +2043,7 @@ F:        Documentation/scsi/dc395x.txt
 F:     drivers/scsi/dc395x.*
 
 DCCP PROTOCOL
-M:     Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
+M:     Gerrit Renker <gerrit@erg.abdn.ac.uk>
 L:     dccp@vger.kernel.org
 W:     http://www.linuxfoundation.org/collaborate/workgroups/networking/dccp
 S:     Maintained
@@ -2124,6 +2143,7 @@ S:        Supported
 F:     fs/dlm/
 
 DMA GENERIC OFFLOAD ENGINE SUBSYSTEM
+M:     Vinod Koul <vinod.koul@intel.com>
 M:     Dan Williams <dan.j.williams@intel.com>
 S:     Supported
 F:     drivers/dma/
@@ -2772,6 +2792,15 @@ F:       Documentation/isdn/README.gigaset
 F:     drivers/isdn/gigaset/
 F:     include/linux/gigaset_dev.h
 
+GPIO SUBSYSTEM
+M:     Grant Likely <grant.likely@secretlab.ca>
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+T:     git git://git.secretlab.ca/git/linux-2.6.git
+F:     Documentation/gpio/gpio.txt
+F:     drivers/gpio/
+F:     include/linux/gpio*
+
 GRETH 10/100/1G Ethernet MAC device driver
 M:     Kristoffer Glembo <kristoffer@gaisler.com>
 L:     netdev@vger.kernel.org
@@ -2861,7 +2890,6 @@ M:        Guenter Roeck <guenter.roeck@ericsson.com>
 L:     lm-sensors@lm-sensors.org
 W:     http://www.lm-sensors.org/
 T:     quilt kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-hwmon/
-T:     quilt kernel.org/pub/linux/kernel/people/groeck/linux-staging/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
 S:     Maintained
 F:     Documentation/hwmon/
@@ -3139,6 +3167,12 @@ S:       Maintained
 F:     net/ieee802154/
 F:     drivers/ieee802154/
 
+IKANOS/ADI EAGLE ADSL USB DRIVER
+M:     Matthieu Castet <castet.matthieu@free.fr>
+M:     Stanislaw Gruszka <stf_xl@wp.pl>
+S:     Maintained
+F:     drivers/usb/atm/ueagle-atm.c
+
 INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
 M:     Mimi Zohar <zohar@us.ibm.com>
 S:     Supported
@@ -3327,7 +3361,6 @@ F:        drivers/net/wimax/i2400m/
 F:     include/linux/wimax/i2400m.h
 
 INTEL WIRELESS WIFI LINK (iwlwifi)
-M:     Reinette Chatre <reinette.chatre@intel.com>
 M:     Wey-Yi Guy <wey-yi.w.guy@intel.com>
 M:     Intel Linux Wireless <ilw@linux.intel.com>
 L:     linux-wireless@vger.kernel.org
@@ -3496,7 +3529,7 @@ F:        drivers/hwmon/jc42.c
 F:     Documentation/hwmon/jc42
 
 JFS FILESYSTEM
-M:     Dave Kleikamp <shaggy@linux.vnet.ibm.com>
+M:     Dave Kleikamp <shaggy@kernel.org>
 L:     jfs-discussion@lists.sourceforge.net
 W:     http://jfs.sourceforge.net/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/shaggy/jfs-2.6.git
@@ -4259,10 +4292,7 @@ S:       Maintained
 F:     net/sched/sch_netem.c
 
 NETERION 10GbE DRIVERS (s2io/vxge)
-M:     Ramkrishna Vepa <ramkrishna.vepa@exar.com>
-M:     Sivakumar Subramani <sivakumar.subramani@exar.com>
-M:     Sreenivasa Honnur <sreenivasa.honnur@exar.com>
-M:     Jon Mason <jon.mason@exar.com>
+M:     Jon Mason <jdmason@kudzu.us>
 L:     netdev@vger.kernel.org
 W:     http://trac.neterion.com/cgi-bin/trac.cgi/wiki/Linux?Anonymous
 W:     http://trac.neterion.com/cgi-bin/trac.cgi/wiki/X3100Linux?Anonymous
@@ -4584,7 +4614,7 @@ F:        drivers/i2c/busses/i2c-ocores.c
 
 OPEN FIRMWARE AND FLATTENED DEVICE TREE
 M:     Grant Likely <grant.likely@secretlab.ca>
-L:     devicetree-discuss@lists.ozlabs.org
+L:     devicetree-discuss@lists.ozlabs.org (moderated for non-subscribers)
 W:     http://fdt.secretlab.ca
 T:     git git://git.secretlab.ca/git/linux-2.6.git
 S:     Maintained
@@ -5148,6 +5178,7 @@ F:        drivers/char/random.c
 
 RAPIDIO SUBSYSTEM
 M:     Matt Porter <mporter@kernel.crashing.org>
+M:     Alexandre Bounine <alexandre.bounine@idt.com>
 S:     Maintained
 F:     drivers/rapidio/
 
@@ -5250,7 +5281,7 @@ S:        Maintained
 F:     drivers/net/wireless/rtl818x/rtl8180/
 
 RTL8187 WIRELESS DRIVER
-M:     Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+M:     Herton Ronaldo Krzesinski <herton@canonical.com>
 M:     Hin-Tak Leung <htl10@users.sourceforge.net>
 M:     Larry Finger <Larry.Finger@lwfinger.net>
 L:     linux-wireless@vger.kernel.org
@@ -5544,12 +5575,11 @@ S:      Supported
 F:     drivers/scsi/be2iscsi/
 
 SERVER ENGINES 10Gbps NIC - BladeEngine 2 DRIVER
-M:     Sathya Perla <sathyap@serverengines.com>
-M:     Subbu Seetharaman <subbus@serverengines.com>
-M:     Sarveshwar Bandi <sarveshwarb@serverengines.com>
-M:     Ajit Khaparde <ajitk@serverengines.com>
+M:     Sathya Perla <sathya.perla@emulex.com>
+M:     Subbu Seetharaman <subbu.seetharaman@emulex.com>
+M:     Ajit Khaparde <ajit.khaparde@emulex.com>
 L:     netdev@vger.kernel.org
-W:     http://www.serverengines.com
+W:     http://www.emulex.com
 S:     Supported
 F:     drivers/net/benet/
 
@@ -5609,18 +5639,20 @@ F:      include/linux/sfi*.h
 
 SIMTEC EB110ATX (Chalice CATS)
 P:     Ben Dooks
-M:     Vincent Sanders <support@simtec.co.uk>
+P:     Vincent Sanders <vince@simtec.co.uk>
+M:     Simtec Linux Team <linux@simtec.co.uk>
 W:     http://www.simtec.co.uk/products/EB110ATX/
 S:     Supported
 
 SIMTEC EB2410ITX (BAST)
 P:     Ben Dooks
-M:     Vincent Sanders <support@simtec.co.uk>
+P:     Vincent Sanders <vince@simtec.co.uk>
+M:     Simtec Linux Team <linux@simtec.co.uk>
 W:     http://www.simtec.co.uk/products/EB2410ITX/
 S:     Supported
-F:     arch/arm/mach-s3c2410/
-F:     drivers/*/*s3c2410*
-F:     drivers/*/*/*s3c2410*
+F:     arch/arm/mach-s3c2410/mach-bast.c
+F:     arch/arm/mach-s3c2410/bast-ide.c
+F:     arch/arm/mach-s3c2410/bast-irq.c
 
 TI DAVINCI MACHINE SUPPORT
 M:     Kevin Hilman <khilman@deeprootsystems.com>
@@ -6087,7 +6119,7 @@ S:        Maintained
 F:     security/tomoyo/
 
 TOPSTAR LAPTOP EXTRAS DRIVER
-M:     Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+M:     Herton Ronaldo Krzesinski <herton@canonical.com>
 L:     platform-driver-x86@vger.kernel.org
 S:     Maintained
 F:     drivers/platform/x86/topstar-laptop.c
@@ -6595,6 +6627,16 @@ S:       Maintained
 F:     drivers/char/virtio_console.c
 F:     include/linux/virtio_console.h
 
+VIRTIO CORE, NET AND BLOCK DRIVERS
+M:     Rusty Russell <rusty@rustcorp.com.au>
+M:     "Michael S. Tsirkin" <mst@redhat.com>
+L:     virtualization@lists.linux-foundation.org
+S:     Maintained
+F:     drivers/virtio/
+F:     drivers/net/virtio_net.c
+F:     drivers/block/virtio_blk.c
+F:     include/linux/virtio_*.h
+
 VIRTIO HOST (VHOST)
 M:     "Michael S. Tsirkin" <mst@redhat.com>
 L:     kvm@vger.kernel.org
@@ -6768,12 +6810,12 @@ S:      Maintained
 F:     drivers/net/wireless/wl1251/*
 
 WL1271 WIRELESS DRIVER
-M:     Luciano Coelho <luciano.coelho@nokia.com>
+M:     Luciano Coelho <coelho@ti.com>
 L:     linux-wireless@vger.kernel.org
-W:     http://wireless.kernel.org
+W:     http://wireless.kernel.org/en/users/Drivers/wl12xx
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git
 S:     Maintained
-F:     drivers/net/wireless/wl12xx/wl1271*
+F:     drivers/net/wireless/wl12xx/
 F:     include/linux/wl12xx.h
 
 WL3501 WIRELESS PCMCIA CARD DRIVER
index 1f47495..d6592b6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 38
-EXTRAVERSION = -rc2
+EXTRAVERSION =
 NAME = Flesh-Eating Bats with Fangs
 
 # *DOCUMENTATION*
index 47f63d4..cc31bec 100644 (file)
@@ -11,6 +11,7 @@ config ALPHA
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_PROBE
        select AUTO_IRQ_AFFINITY if SMP
+       select GENERIC_HARDIRQS_NO_DEPRECATED
        help
          The Alpha is a 64-bit general-purpose processor designed and
          marketed by the Digital Equipment Corporation of blessed memory,
index 70145cb..1b71ca7 100644 (file)
@@ -31,6 +31,8 @@
 #define __O_SYNC       020000000
 #define O_SYNC         (__O_SYNC|O_DSYNC)
 
+#define O_PATH         040000000
+
 #define F_GETLK                7
 #define F_SETLK                8
 #define F_SETLKW       9
index 945de22..e8a761a 100644 (file)
@@ -29,7 +29,7 @@
        :       "r" (uaddr), "r"(oparg)                         \
        :       "memory")
 
-static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
 {
        int op = (encoded_op >> 28) & 7;
        int cmp = (encoded_op >> 24) & 15;
@@ -39,7 +39,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
        if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
                oparg = 1 << oparg;
 
-       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
        pagefault_disable();
@@ -81,21 +81,23 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
 }
 
 static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+                             u32 oldval, u32 newval)
 {
-       int prev, cmp;
+       int ret = 0, cmp;
+       u32 prev;
 
-       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
        __asm__ __volatile__ (
                __ASM_SMP_MB
-       "1:     ldl_l   %0,0(%2)\n"
-       "       cmpeq   %0,%3,%1\n"
-       "       beq     %1,3f\n"
-       "       mov     %4,%1\n"
-       "2:     stl_c   %1,0(%2)\n"
-       "       beq     %1,4f\n"
+       "1:     ldl_l   %1,0(%3)\n"
+       "       cmpeq   %1,%4,%2\n"
+       "       beq     %2,3f\n"
+       "       mov     %5,%2\n"
+       "2:     stl_c   %2,0(%3)\n"
+       "       beq     %2,4f\n"
        "3:     .subsection 2\n"
        "4:     br      1b\n"
        "       .previous\n"
@@ -105,11 +107,12 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
        "       .long   2b-.\n"
        "       lda     $31,3b-2b(%0)\n"
        "       .previous\n"
-       :       "=&r"(prev), "=&r"(cmp)
+       :       "+r"(ret), "=&r"(prev), "=&r"(cmp)
        :       "r"(uaddr), "r"((long)oldval), "r"(newval)
        :       "memory");
 
-       return prev;
+       *uval = prev;
+       return ret;
 }
 
 #endif /* __KERNEL__ */
index 1570c0b..a83bbea 100644 (file)
 #ifdef __KERNEL__
 
 #include <linux/compiler.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
 
-struct rwsem_waiter;
-
-extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
-extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
-extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *);
-extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
-
-/*
- * the semaphore definition
- */
-struct rw_semaphore {
-       long                    count;
 #define RWSEM_UNLOCKED_VALUE           0x0000000000000000L
 #define RWSEM_ACTIVE_BIAS              0x0000000000000001L
 #define RWSEM_ACTIVE_MASK              0x00000000ffffffffL
 #define RWSEM_WAITING_BIAS             (-0x0000000100000000L)
 #define RWSEM_ACTIVE_READ_BIAS         RWSEM_ACTIVE_BIAS
 #define RWSEM_ACTIVE_WRITE_BIAS                (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
-       spinlock_t              wait_lock;
-       struct list_head        wait_list;
-};
-
-#define __RWSEM_INITIALIZER(name) \
-       { RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \
-       LIST_HEAD_INIT((name).wait_list) }
-
-#define DECLARE_RWSEM(name) \
-       struct rw_semaphore name = __RWSEM_INITIALIZER(name)
-
-static inline void init_rwsem(struct rw_semaphore *sem)
-{
-       sem->count = RWSEM_UNLOCKED_VALUE;
-       spin_lock_init(&sem->wait_lock);
-       INIT_LIST_HEAD(&sem->wait_list);
-}
 
 static inline void __down_read(struct rw_semaphore *sem)
 {
@@ -250,10 +219,5 @@ static inline long rwsem_atomic_update(long val, struct rw_semaphore *sem)
 #endif
 }
 
-static inline int rwsem_is_locked(struct rw_semaphore *sem)
-{
-       return (sem->count != 0);
-}
-
 #endif /* __KERNEL__ */
 #endif /* _ALPHA_RWSEM_H */
index 9ab234f..a19d600 100644 (file)
@@ -44,11 +44,16 @@ static char irq_user_affinity[NR_IRQS];
 
 int irq_select_affinity(unsigned int irq)
 {
-       struct irq_desc *desc = irq_to_desc[irq];
+       struct irq_data *data = irq_get_irq_data(irq);
+       struct irq_chip *chip;
        static int last_cpu;
        int cpu = last_cpu + 1;
 
-       if (!desc || !get_irq_desc_chip(desc)->set_affinity || irq_user_affinity[irq])
+       if (!data)
+               return 1;
+       chip = irq_data_get_irq_chip(data);
+
+       if (!chip->irq_set_affinity || irq_user_affinity[irq])
                return 1;
 
        while (!cpu_possible(cpu) ||
@@ -56,8 +61,8 @@ int irq_select_affinity(unsigned int irq)
                cpu = (cpu < (NR_CPUS-1) ? cpu + 1 : 0);
        last_cpu = cpu;
 
-       cpumask_copy(desc->affinity, cpumask_of(cpu));
-       get_irq_desc_chip(desc)->set_affinity(irq, cpumask_of(cpu));
+       cpumask_copy(data->affinity, cpumask_of(cpu));
+       chip->irq_set_affinity(data, cpumask_of(cpu), false);
        return 0;
 }
 #endif /* CONFIG_SMP */
index 2d0679b..411ca11 100644 (file)
@@ -228,14 +228,9 @@ struct irqaction timer_irqaction = {
 void __init
 init_rtc_irq(void)
 {
-       struct irq_desc *desc = irq_to_desc(RTC_IRQ);
-
-       if (desc) {
-               desc->status |= IRQ_DISABLED;
-               set_irq_chip_and_handler_name(RTC_IRQ, &no_irq_chip,
-                       handle_simple_irq, "RTC");
-               setup_irq(RTC_IRQ, &timer_irqaction);
-       }
+       set_irq_chip_and_handler_name(RTC_IRQ, &no_irq_chip,
+                                     handle_simple_irq, "RTC");
+       setup_irq(RTC_IRQ, &timer_irqaction);
 }
 
 /* Dummy irqactions.  */
index 956ea0e..c7cc981 100644 (file)
@@ -33,10 +33,10 @@ i8259_update_irq_hw(unsigned int irq, unsigned long mask)
 }
 
 inline void
-i8259a_enable_irq(unsigned int irq)
+i8259a_enable_irq(struct irq_data *d)
 {
        spin_lock(&i8259_irq_lock);
-       i8259_update_irq_hw(irq, cached_irq_mask &= ~(1 << irq));
+       i8259_update_irq_hw(d->irq, cached_irq_mask &= ~(1 << d->irq));
        spin_unlock(&i8259_irq_lock);
 }
 
@@ -47,16 +47,18 @@ __i8259a_disable_irq(unsigned int irq)
 }
 
 void
-i8259a_disable_irq(unsigned int irq)
+i8259a_disable_irq(struct irq_data *d)
 {
        spin_lock(&i8259_irq_lock);
-       __i8259a_disable_irq(irq);
+       __i8259a_disable_irq(d->irq);
        spin_unlock(&i8259_irq_lock);
 }
 
 void
-i8259a_mask_and_ack_irq(unsigned int irq)
+i8259a_mask_and_ack_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
+
        spin_lock(&i8259_irq_lock);
        __i8259a_disable_irq(irq);
 
@@ -71,9 +73,9 @@ i8259a_mask_and_ack_irq(unsigned int irq)
 
 struct irq_chip i8259a_irq_type = {
        .name           = "XT-PIC",
-       .unmask         = i8259a_enable_irq,
-       .mask           = i8259a_disable_irq,
-       .mask_ack       = i8259a_mask_and_ack_irq,
+       .irq_unmask     = i8259a_enable_irq,
+       .irq_mask       = i8259a_disable_irq,
+       .irq_mask_ack   = i8259a_mask_and_ack_irq,
 };
 
 void __init
index b63ccd7..d507a23 100644 (file)
@@ -31,11 +31,9 @@ extern void init_rtc_irq(void);
 
 extern void common_init_isa_dma(void);
 
-extern void i8259a_enable_irq(unsigned int);
-extern void i8259a_disable_irq(unsigned int);
-extern void i8259a_mask_and_ack_irq(unsigned int);
-extern unsigned int i8259a_startup_irq(unsigned int);
-extern void i8259a_end_irq(unsigned int);
+extern void i8259a_enable_irq(struct irq_data *d);
+extern void i8259a_disable_irq(struct irq_data *d);
+extern void i8259a_mask_and_ack_irq(struct irq_data *d);
 extern struct irq_chip i8259a_irq_type;
 extern void init_i8259a_irqs(void);
 
index 2863458..b30227f 100644 (file)
@@ -29,21 +29,21 @@ pyxis_update_irq_hw(unsigned long mask)
 }
 
 static inline void
-pyxis_enable_irq(unsigned int irq)
+pyxis_enable_irq(struct irq_data *d)
 {
-       pyxis_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16));
+       pyxis_update_irq_hw(cached_irq_mask |= 1UL << (d->irq - 16));
 }
 
 static void
-pyxis_disable_irq(unsigned int irq)
+pyxis_disable_irq(struct irq_data *d)
 {
-       pyxis_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16)));
+       pyxis_update_irq_hw(cached_irq_mask &= ~(1UL << (d->irq - 16)));
 }
 
 static void
-pyxis_mask_and_ack_irq(unsigned int irq)
+pyxis_mask_and_ack_irq(struct irq_data *d)
 {
-       unsigned long bit = 1UL << (irq - 16);
+       unsigned long bit = 1UL << (d->irq - 16);
        unsigned long mask = cached_irq_mask &= ~bit;
 
        /* Disable the interrupt.  */
@@ -58,9 +58,9 @@ pyxis_mask_and_ack_irq(unsigned int irq)
 
 static struct irq_chip pyxis_irq_type = {
        .name           = "PYXIS",
-       .mask_ack       = pyxis_mask_and_ack_irq,
-       .mask           = pyxis_disable_irq,
-       .unmask         = pyxis_enable_irq,
+       .irq_mask_ack   = pyxis_mask_and_ack_irq,
+       .irq_mask       = pyxis_disable_irq,
+       .irq_unmask     = pyxis_enable_irq,
 };
 
 void 
@@ -103,7 +103,7 @@ init_pyxis_irqs(unsigned long ignore_mask)
                if ((ignore_mask >> i) & 1)
                        continue;
                set_irq_chip_and_handler(i, &pyxis_irq_type, handle_level_irq);
-               irq_to_desc(i)->status |= IRQ_LEVEL;
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 
        setup_irq(16+7, &isa_cascade_irqaction);
index 0e57e82..82a47bb 100644 (file)
 DEFINE_SPINLOCK(srm_irq_lock);
 
 static inline void
-srm_enable_irq(unsigned int irq)
+srm_enable_irq(struct irq_data *d)
 {
        spin_lock(&srm_irq_lock);
-       cserve_ena(irq - 16);
+       cserve_ena(d->irq - 16);
        spin_unlock(&srm_irq_lock);
 }
 
 static void
-srm_disable_irq(unsigned int irq)
+srm_disable_irq(struct irq_data *d)
 {
        spin_lock(&srm_irq_lock);
-       cserve_dis(irq - 16);
+       cserve_dis(d->irq - 16);
        spin_unlock(&srm_irq_lock);
 }
 
 /* Handle interrupts from the SRM, assuming no additional weirdness.  */
 static struct irq_chip srm_irq_type = {
        .name           = "SRM",
-       .unmask         = srm_enable_irq,
-       .mask           = srm_disable_irq,
-       .mask_ack       = srm_disable_irq,
+       .irq_unmask     = srm_enable_irq,
+       .irq_mask       = srm_disable_irq,
+       .irq_mask_ack   = srm_disable_irq,
 };
 
 void __init
@@ -52,7 +52,7 @@ init_srm_irqs(long max, unsigned long ignore_mask)
                if (i < 64 && ((ignore_mask >> i) & 1))
                        continue;
                set_irq_chip_and_handler(i, &srm_irq_type, handle_level_irq);
-               irq_to_desc(i)->status |= IRQ_LEVEL;
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 }
 
index fe698b5..376f221 100644 (file)
@@ -230,44 +230,24 @@ linux_to_osf_statfs(struct kstatfs *linux_stat, struct osf_statfs __user *osf_st
        return copy_to_user(osf_stat, &tmp_stat, bufsiz) ? -EFAULT : 0;
 }
 
-static int
-do_osf_statfs(struct path *path, struct osf_statfs __user *buffer,
-             unsigned long bufsiz)
+SYSCALL_DEFINE3(osf_statfs, const char __user *, pathname,
+               struct osf_statfs __user *, buffer, unsigned long, bufsiz)
 {
        struct kstatfs linux_stat;
-       int error = vfs_statfs(path, &linux_stat);
+       int error = user_statfs(pathname, &linux_stat);
        if (!error)
                error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz);
        return error;   
 }
 
-SYSCALL_DEFINE3(osf_statfs, const char __user *, pathname,
-               struct osf_statfs __user *, buffer, unsigned long, bufsiz)
-{
-       struct path path;
-       int retval;
-
-       retval = user_path(pathname, &path);
-       if (!retval) {
-               retval = do_osf_statfs(&path, buffer, bufsiz);
-               path_put(&path);
-       }
-       return retval;
-}
-
 SYSCALL_DEFINE3(osf_fstatfs, unsigned long, fd,
                struct osf_statfs __user *, buffer, unsigned long, bufsiz)
 {
-       struct file *file;
-       int retval;
-
-       retval = -EBADF;
-       file = fget(fd);
-       if (file) {
-               retval = do_osf_statfs(&file->f_path, buffer, bufsiz);
-               fput(file);
-       }
-       return retval;
+       struct kstatfs linux_stat;
+       int error = fd_statfs(fd, &linux_stat);
+       if (!error)
+               error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz);
+       return error;
 }
 
 /*
index 7bef617..88d95e8 100644 (file)
@@ -44,31 +44,31 @@ alcor_update_irq_hw(unsigned long mask)
 }
 
 static inline void
-alcor_enable_irq(unsigned int irq)
+alcor_enable_irq(struct irq_data *d)
 {
-       alcor_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16));
+       alcor_update_irq_hw(cached_irq_mask |= 1UL << (d->irq - 16));
 }
 
 static void
-alcor_disable_irq(unsigned int irq)
+alcor_disable_irq(struct irq_data *d)
 {
-       alcor_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16)));
+       alcor_update_irq_hw(cached_irq_mask &= ~(1UL << (d->irq - 16)));
 }
 
 static void
-alcor_mask_and_ack_irq(unsigned int irq)
+alcor_mask_and_ack_irq(struct irq_data *d)
 {
-       alcor_disable_irq(irq);
+       alcor_disable_irq(d);
 
        /* On ALCOR/XLT, need to dismiss interrupt via GRU. */
-       *(vuip)GRU_INT_CLEAR = 1 << (irq - 16); mb();
+       *(vuip)GRU_INT_CLEAR = 1 << (d->irq - 16); mb();
        *(vuip)GRU_INT_CLEAR = 0; mb();
 }
 
 static void
-alcor_isa_mask_and_ack_irq(unsigned int irq)
+alcor_isa_mask_and_ack_irq(struct irq_data *d)
 {
-       i8259a_mask_and_ack_irq(irq);
+       i8259a_mask_and_ack_irq(d);
 
        /* On ALCOR/XLT, need to dismiss interrupt via GRU. */
        *(vuip)GRU_INT_CLEAR = 0x80000000; mb();
@@ -77,9 +77,9 @@ alcor_isa_mask_and_ack_irq(unsigned int irq)
 
 static struct irq_chip alcor_irq_type = {
        .name           = "ALCOR",
-       .unmask         = alcor_enable_irq,
-       .mask           = alcor_disable_irq,
-       .mask_ack       = alcor_mask_and_ack_irq,
+       .irq_unmask     = alcor_enable_irq,
+       .irq_mask       = alcor_disable_irq,
+       .irq_mask_ack   = alcor_mask_and_ack_irq,
 };
 
 static void
@@ -126,9 +126,9 @@ alcor_init_irq(void)
                if (i >= 16+20 && i <= 16+30)
                        continue;
                set_irq_chip_and_handler(i, &alcor_irq_type, handle_level_irq);
-               irq_to_desc(i)->status |= IRQ_LEVEL;
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
-       i8259a_irq_type.ack = alcor_isa_mask_and_ack_irq;
+       i8259a_irq_type.irq_ack = alcor_isa_mask_and_ack_irq;
 
        init_i8259a_irqs();
        common_init_isa_dma();
index b0c9164..57eb630 100644 (file)
@@ -46,22 +46,22 @@ cabriolet_update_irq_hw(unsigned int irq, unsigned long mask)
 }
 
 static inline void
-cabriolet_enable_irq(unsigned int irq)
+cabriolet_enable_irq(struct irq_data *d)
 {
-       cabriolet_update_irq_hw(irq, cached_irq_mask &= ~(1UL << irq));
+       cabriolet_update_irq_hw(d->irq, cached_irq_mask &= ~(1UL << d->irq));
 }
 
 static void
-cabriolet_disable_irq(unsigned int irq)
+cabriolet_disable_irq(struct irq_data *d)
 {
-       cabriolet_update_irq_hw(irq, cached_irq_mask |= 1UL << irq);
+       cabriolet_update_irq_hw(d->irq, cached_irq_mask |= 1UL << d->irq);
 }
 
 static struct irq_chip cabriolet_irq_type = {
        .name           = "CABRIOLET",
-       .unmask         = cabriolet_enable_irq,
-       .mask           = cabriolet_disable_irq,
-       .mask_ack       = cabriolet_disable_irq,
+       .irq_unmask     = cabriolet_enable_irq,
+       .irq_mask       = cabriolet_disable_irq,
+       .irq_mask_ack   = cabriolet_disable_irq,
 };
 
 static void 
@@ -107,7 +107,7 @@ common_init_irq(void (*srm_dev_int)(unsigned long v))
                for (i = 16; i < 35; ++i) {
                        set_irq_chip_and_handler(i, &cabriolet_irq_type,
                                handle_level_irq);
-                       irq_to_desc(i)->status |= IRQ_LEVEL;
+                       irq_set_status_flags(i, IRQ_LEVEL);
                }
        }
 
index edad5f7..481df4e 100644 (file)
@@ -98,37 +98,37 @@ tsunami_update_irq_hw(unsigned long mask)
 }
 
 static void
-dp264_enable_irq(unsigned int irq)
+dp264_enable_irq(struct irq_data *d)
 {
        spin_lock(&dp264_irq_lock);
-       cached_irq_mask |= 1UL << irq;
+       cached_irq_mask |= 1UL << d->irq;
        tsunami_update_irq_hw(cached_irq_mask);
        spin_unlock(&dp264_irq_lock);
 }
 
 static void
-dp264_disable_irq(unsigned int irq)
+dp264_disable_irq(struct irq_data *d)
 {
        spin_lock(&dp264_irq_lock);
-       cached_irq_mask &= ~(1UL << irq);
+       cached_irq_mask &= ~(1UL << d->irq);
        tsunami_update_irq_hw(cached_irq_mask);
        spin_unlock(&dp264_irq_lock);
 }
 
 static void
-clipper_enable_irq(unsigned int irq)
+clipper_enable_irq(struct irq_data *d)
 {
        spin_lock(&dp264_irq_lock);
-       cached_irq_mask |= 1UL << (irq - 16);
+       cached_irq_mask |= 1UL << (d->irq - 16);
        tsunami_update_irq_hw(cached_irq_mask);
        spin_unlock(&dp264_irq_lock);
 }
 
 static void
-clipper_disable_irq(unsigned int irq)
+clipper_disable_irq(struct irq_data *d)
 {
        spin_lock(&dp264_irq_lock);
-       cached_irq_mask &= ~(1UL << (irq - 16));
+       cached_irq_mask &= ~(1UL << (d->irq - 16));
        tsunami_update_irq_hw(cached_irq_mask);
        spin_unlock(&dp264_irq_lock);
 }
@@ -149,10 +149,11 @@ cpu_set_irq_affinity(unsigned int irq, cpumask_t affinity)
 }
 
 static int
-dp264_set_affinity(unsigned int irq, const struct cpumask *affinity)
-{ 
+dp264_set_affinity(struct irq_data *d, const struct cpumask *affinity,
+                  bool force)
+{
        spin_lock(&dp264_irq_lock);
-       cpu_set_irq_affinity(irq, *affinity);
+       cpu_set_irq_affinity(d->irq, *affinity);
        tsunami_update_irq_hw(cached_irq_mask);
        spin_unlock(&dp264_irq_lock);
 
@@ -160,10 +161,11 @@ dp264_set_affinity(unsigned int irq, const struct cpumask *affinity)
 }
 
 static int
-clipper_set_affinity(unsigned int irq, const struct cpumask *affinity)
-{ 
+clipper_set_affinity(struct irq_data *d, const struct cpumask *affinity,
+                    bool force)
+{
        spin_lock(&dp264_irq_lock);
-       cpu_set_irq_affinity(irq - 16, *affinity);
+       cpu_set_irq_affinity(d->irq - 16, *affinity);
        tsunami_update_irq_hw(cached_irq_mask);
        spin_unlock(&dp264_irq_lock);
 
@@ -171,19 +173,19 @@ clipper_set_affinity(unsigned int irq, const struct cpumask *affinity)
 }
 
 static struct irq_chip dp264_irq_type = {
-       .name           = "DP264",
-       .unmask         = dp264_enable_irq,
-       .mask           = dp264_disable_irq,
-       .mask_ack       = dp264_disable_irq,
-       .set_affinity   = dp264_set_affinity,
+       .name                   = "DP264",
+       .irq_unmask             = dp264_enable_irq,
+       .irq_mask               = dp264_disable_irq,
+       .irq_mask_ack           = dp264_disable_irq,
+       .irq_set_affinity       = dp264_set_affinity,
 };
 
 static struct irq_chip clipper_irq_type = {
-       .name           = "CLIPPER",
-       .unmask         = clipper_enable_irq,
-       .mask           = clipper_disable_irq,
-       .mask_ack       = clipper_disable_irq,
-       .set_affinity   = clipper_set_affinity,
+       .name                   = "CLIPPER",
+       .irq_unmask             = clipper_enable_irq,
+       .irq_mask               = clipper_disable_irq,
+       .irq_mask_ack           = clipper_disable_irq,
+       .irq_set_affinity       = clipper_set_affinity,
 };
 
 static void
@@ -268,8 +270,8 @@ init_tsunami_irqs(struct irq_chip * ops, int imin, int imax)
 {
        long i;
        for (i = imin; i <= imax; ++i) {
-               irq_to_desc(i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i, ops, handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 }
 
index ae5f29d..402e908 100644 (file)
@@ -44,22 +44,22 @@ eb64p_update_irq_hw(unsigned int irq, unsigned long mask)
 }
 
 static inline void
-eb64p_enable_irq(unsigned int irq)
+eb64p_enable_irq(struct irq_data *d)
 {
-       eb64p_update_irq_hw(irq, cached_irq_mask &= ~(1 << irq));
+       eb64p_update_irq_hw(d->irq, cached_irq_mask &= ~(1 << d->irq));
 }
 
 static void
-eb64p_disable_irq(unsigned int irq)
+eb64p_disable_irq(struct irq_data *d)
 {
-       eb64p_update_irq_hw(irq, cached_irq_mask |= 1 << irq);
+       eb64p_update_irq_hw(d->irq, cached_irq_mask |= 1 << d->irq);
 }
 
 static struct irq_chip eb64p_irq_type = {
        .name           = "EB64P",
-       .unmask         = eb64p_enable_irq,
-       .mask           = eb64p_disable_irq,
-       .mask_ack       = eb64p_disable_irq,
+       .irq_unmask     = eb64p_enable_irq,
+       .irq_mask       = eb64p_disable_irq,
+       .irq_mask_ack   = eb64p_disable_irq,
 };
 
 static void 
@@ -118,9 +118,9 @@ eb64p_init_irq(void)
        init_i8259a_irqs();
 
        for (i = 16; i < 32; ++i) {
-               irq_to_desc(i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i, &eb64p_irq_type, handle_level_irq);
-       }               
+               irq_set_status_flags(i, IRQ_LEVEL);
+       }
 
        common_init_isa_dma();
        setup_irq(16+5, &isa_cascade_irqaction);
index 1121bc5..0b44a54 100644 (file)
@@ -51,16 +51,18 @@ eiger_update_irq_hw(unsigned long irq, unsigned long mask)
 }
 
 static inline void
-eiger_enable_irq(unsigned int irq)
+eiger_enable_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
        unsigned long mask;
        mask = (cached_irq_mask[irq >= 64] &= ~(1UL << (irq & 63)));
        eiger_update_irq_hw(irq, mask);
 }
 
 static void
-eiger_disable_irq(unsigned int irq)
+eiger_disable_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
        unsigned long mask;
        mask = (cached_irq_mask[irq >= 64] |= 1UL << (irq & 63));
        eiger_update_irq_hw(irq, mask);
@@ -68,9 +70,9 @@ eiger_disable_irq(unsigned int irq)
 
 static struct irq_chip eiger_irq_type = {
        .name           = "EIGER",
-       .unmask         = eiger_enable_irq,
-       .mask           = eiger_disable_irq,
-       .mask_ack       = eiger_disable_irq,
+       .irq_unmask     = eiger_enable_irq,
+       .irq_mask       = eiger_disable_irq,
+       .irq_mask_ack   = eiger_disable_irq,
 };
 
 static void
@@ -136,8 +138,8 @@ eiger_init_irq(void)
        init_i8259a_irqs();
 
        for (i = 16; i < 128; ++i) {
-               irq_to_desc(i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i, &eiger_irq_type, handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 }
 
index 34f55e0..00341b7 100644 (file)
  */
 
 static void
-jensen_local_enable(unsigned int irq)
+jensen_local_enable(struct irq_data *d)
 {
        /* the parport is really hw IRQ 1, silly Jensen.  */
-       if (irq == 7)
-               i8259a_enable_irq(1);
+       if (d->irq == 7)
+               i8259a_enable_irq(d);
 }
 
 static void
-jensen_local_disable(unsigned int irq)
+jensen_local_disable(struct irq_data *d)
 {
        /* the parport is really hw IRQ 1, silly Jensen.  */
-       if (irq == 7)
-               i8259a_disable_irq(1);
+       if (d->irq == 7)
+               i8259a_disable_irq(d);
 }
 
 static void
-jensen_local_mask_ack(unsigned int irq)
+jensen_local_mask_ack(struct irq_data *d)
 {
        /* the parport is really hw IRQ 1, silly Jensen.  */
-       if (irq == 7)
-               i8259a_mask_and_ack_irq(1);
+       if (d->irq == 7)
+               i8259a_mask_and_ack_irq(d);
 }
 
 static struct irq_chip jensen_local_irq_type = {
        .name           = "LOCAL",
-       .unmask         = jensen_local_enable,
-       .mask           = jensen_local_disable,
-       .mask_ack       = jensen_local_mask_ack,
+       .irq_unmask     = jensen_local_enable,
+       .irq_mask       = jensen_local_disable,
+       .irq_mask_ack   = jensen_local_mask_ack,
 };
 
 static void 
index 2bfc9f1..e619107 100644 (file)
@@ -104,9 +104,10 @@ io7_get_irq_ctl(unsigned int irq, struct io7 **pio7)
 }
 
 static void
-io7_enable_irq(unsigned int irq)
+io7_enable_irq(struct irq_data *d)
 {
        volatile unsigned long *ctl;
+       unsigned int irq = d->irq;
        struct io7 *io7;
 
        ctl = io7_get_irq_ctl(irq, &io7);
@@ -115,7 +116,7 @@ io7_enable_irq(unsigned int irq)
                       __func__, irq);
                return;
        }
-               
+
        spin_lock(&io7->irq_lock);
        *ctl |= 1UL << 24;
        mb();
@@ -124,9 +125,10 @@ io7_enable_irq(unsigned int irq)
 }
 
 static void
-io7_disable_irq(unsigned int irq)
+io7_disable_irq(struct irq_data *d)
 {
        volatile unsigned long *ctl;
+       unsigned int irq = d->irq;
        struct io7 *io7;
 
        ctl = io7_get_irq_ctl(irq, &io7);
@@ -135,7 +137,7 @@ io7_disable_irq(unsigned int irq)
                       __func__, irq);
                return;
        }
-               
+
        spin_lock(&io7->irq_lock);
        *ctl &= ~(1UL << 24);
        mb();
@@ -144,35 +146,29 @@ io7_disable_irq(unsigned int irq)
 }
 
 static void
-marvel_irq_noop(unsigned int irq) 
-{ 
-       return; 
-}
-
-static unsigned int
-marvel_irq_noop_return(unsigned int irq) 
-{ 
-       return 0; 
+marvel_irq_noop(struct irq_data *d)
+{
+       return;
 }
 
 static struct irq_chip marvel_legacy_irq_type = {
        .name           = "LEGACY",
-       .mask           = marvel_irq_noop,
-       .unmask         = marvel_irq_noop,
+       .irq_mask       = marvel_irq_noop,
+       .irq_unmask     = marvel_irq_noop,
 };
 
 static struct irq_chip io7_lsi_irq_type = {
        .name           = "LSI",
-       .unmask         = io7_enable_irq,
-       .mask           = io7_disable_irq,
-       .mask_ack       = io7_disable_irq,
+       .irq_unmask     = io7_enable_irq,
+       .irq_mask       = io7_disable_irq,
+       .irq_mask_ack   = io7_disable_irq,
 };
 
 static struct irq_chip io7_msi_irq_type = {
        .name           = "MSI",
-       .unmask         = io7_enable_irq,
-       .mask           = io7_disable_irq,
-       .ack            = marvel_irq_noop,
+       .irq_unmask     = io7_enable_irq,
+       .irq_mask       = io7_disable_irq,
+       .irq_ack        = marvel_irq_noop,
 };
 
 static void
@@ -280,8 +276,8 @@ init_io7_irqs(struct io7 *io7,
 
        /* Set up the lsi irqs.  */
        for (i = 0; i < 128; ++i) {
-               irq_to_desc(base + i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(base + i, lsi_ops, handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 
        /* Disable the implemented irqs in hardware.  */
@@ -294,8 +290,8 @@ init_io7_irqs(struct io7 *io7,
 
        /* Set up the msi irqs.  */
        for (i = 128; i < (128 + 512); ++i) {
-               irq_to_desc(base + i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(base + i, msi_ops, handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 
        for (i = 0; i < 16; ++i)
index bcc1639..cf7f43d 100644 (file)
@@ -43,22 +43,22 @@ mikasa_update_irq_hw(int mask)
 }
 
 static inline void
-mikasa_enable_irq(unsigned int irq)
+mikasa_enable_irq(struct irq_data *d)
 {
-       mikasa_update_irq_hw(cached_irq_mask |= 1 << (irq - 16));
+       mikasa_update_irq_hw(cached_irq_mask |= 1 << (d->irq - 16));
 }
 
 static void
-mikasa_disable_irq(unsigned int irq)
+mikasa_disable_irq(struct irq_data *d)
 {
-       mikasa_update_irq_hw(cached_irq_mask &= ~(1 << (irq - 16)));
+       mikasa_update_irq_hw(cached_irq_mask &= ~(1 << (d->irq - 16)));
 }
 
 static struct irq_chip mikasa_irq_type = {
        .name           = "MIKASA",
-       .unmask         = mikasa_enable_irq,
-       .mask           = mikasa_disable_irq,
-       .mask_ack       = mikasa_disable_irq,
+       .irq_unmask     = mikasa_enable_irq,
+       .irq_mask       = mikasa_disable_irq,
+       .irq_mask_ack   = mikasa_disable_irq,
 };
 
 static void 
@@ -98,8 +98,8 @@ mikasa_init_irq(void)
        mikasa_update_irq_hw(0);
 
        for (i = 16; i < 32; ++i) {
-               irq_to_desc(i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i, &mikasa_irq_type, handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 
        init_i8259a_irqs();
index e88f4ae..92bc188 100644 (file)
@@ -48,22 +48,22 @@ noritake_update_irq_hw(int irq, int mask)
 }
 
 static void
-noritake_enable_irq(unsigned int irq)
+noritake_enable_irq(struct irq_data *d)
 {
-       noritake_update_irq_hw(irq, cached_irq_mask |= 1 << (irq - 16));
+       noritake_update_irq_hw(d->irq, cached_irq_mask |= 1 << (d->irq - 16));
 }
 
 static void
-noritake_disable_irq(unsigned int irq)
+noritake_disable_irq(struct irq_data *d)
 {
-       noritake_update_irq_hw(irq, cached_irq_mask &= ~(1 << (irq - 16)));
+       noritake_update_irq_hw(d->irq, cached_irq_mask &= ~(1 << (d->irq - 16)));
 }
 
 static struct irq_chip noritake_irq_type = {
        .name           = "NORITAKE",
-       .unmask         = noritake_enable_irq,
-       .mask           = noritake_disable_irq,
-       .mask_ack       = noritake_disable_irq,
+       .irq_unmask     = noritake_enable_irq,
+       .irq_mask       = noritake_disable_irq,
+       .irq_mask_ack   = noritake_disable_irq,
 };
 
 static void 
@@ -127,8 +127,8 @@ noritake_init_irq(void)
        outw(0, 0x54c);
 
        for (i = 16; i < 48; ++i) {
-               irq_to_desc(i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i, &noritake_irq_type, handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 
        init_i8259a_irqs();
index 6a51364..936d414 100644 (file)
@@ -56,9 +56,10 @@ rawhide_update_irq_hw(int hose, int mask)
   (((h) < MCPCIA_MAX_HOSES) && (cached_irq_masks[(h)] != 0))
 
 static inline void 
-rawhide_enable_irq(unsigned int irq)
+rawhide_enable_irq(struct irq_data *d)
 {
        unsigned int mask, hose;
+       unsigned int irq = d->irq;
 
        irq -= 16;
        hose = irq / 24;
@@ -76,9 +77,10 @@ rawhide_enable_irq(unsigned int irq)
 }
 
 static void 
-rawhide_disable_irq(unsigned int irq)
+rawhide_disable_irq(struct irq_data *d)
 {
        unsigned int mask, hose;
+       unsigned int irq = d->irq;
 
        irq -= 16;
        hose = irq / 24;
@@ -96,9 +98,10 @@ rawhide_disable_irq(unsigned int irq)
 }
 
 static void
-rawhide_mask_and_ack_irq(unsigned int irq)
+rawhide_mask_and_ack_irq(struct irq_data *d)
 {
        unsigned int mask, mask1, hose;
+       unsigned int irq = d->irq;
 
        irq -= 16;
        hose = irq / 24;
@@ -123,9 +126,9 @@ rawhide_mask_and_ack_irq(unsigned int irq)
 
 static struct irq_chip rawhide_irq_type = {
        .name           = "RAWHIDE",
-       .unmask         = rawhide_enable_irq,
-       .mask           = rawhide_disable_irq,
-       .mask_ack       = rawhide_mask_and_ack_irq,
+       .irq_unmask     = rawhide_enable_irq,
+       .irq_mask       = rawhide_disable_irq,
+       .irq_mask_ack   = rawhide_mask_and_ack_irq,
 };
 
 static void 
@@ -177,8 +180,8 @@ rawhide_init_irq(void)
        }
 
        for (i = 16; i < 128; ++i) {
-               irq_to_desc(i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i, &rawhide_irq_type, handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 
        init_i8259a_irqs();
index 89e7e37..cea22a6 100644 (file)
@@ -47,22 +47,22 @@ rx164_update_irq_hw(unsigned long mask)
 }
 
 static inline void
-rx164_enable_irq(unsigned int irq)
+rx164_enable_irq(struct irq_data *d)
 {
-       rx164_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16));
+       rx164_update_irq_hw(cached_irq_mask |= 1UL << (d->irq - 16));
 }
 
 static void
-rx164_disable_irq(unsigned int irq)
+rx164_disable_irq(struct irq_data *d)
 {
-       rx164_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16)));
+       rx164_update_irq_hw(cached_irq_mask &= ~(1UL << (d->irq - 16)));
 }
 
 static struct irq_chip rx164_irq_type = {
        .name           = "RX164",
-       .unmask         = rx164_enable_irq,
-       .mask           = rx164_disable_irq,
-       .mask_ack       = rx164_disable_irq,
+       .irq_unmask     = rx164_enable_irq,
+       .irq_mask       = rx164_disable_irq,
+       .irq_mask_ack   = rx164_disable_irq,
 };
 
 static void 
@@ -99,8 +99,8 @@ rx164_init_irq(void)
 
        rx164_update_irq_hw(0);
        for (i = 16; i < 40; ++i) {
-               irq_to_desc(i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i, &rx164_irq_type, handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 
        init_i8259a_irqs();
index 5c4423d..a349538 100644 (file)
@@ -443,11 +443,11 @@ lynx_swizzle(struct pci_dev *dev, u8 *pinp)
 /* GENERIC irq routines */
 
 static inline void
-sable_lynx_enable_irq(unsigned int irq)
+sable_lynx_enable_irq(struct irq_data *d)
 {
        unsigned long bit, mask;
 
-       bit = sable_lynx_irq_swizzle->irq_to_mask[irq];
+       bit = sable_lynx_irq_swizzle->irq_to_mask[d->irq];
        spin_lock(&sable_lynx_irq_lock);
        mask = sable_lynx_irq_swizzle->shadow_mask &= ~(1UL << bit);
        sable_lynx_irq_swizzle->update_irq_hw(bit, mask);
@@ -459,11 +459,11 @@ sable_lynx_enable_irq(unsigned int irq)
 }
 
 static void
-sable_lynx_disable_irq(unsigned int irq)
+sable_lynx_disable_irq(struct irq_data *d)
 {
        unsigned long bit, mask;
 
-       bit = sable_lynx_irq_swizzle->irq_to_mask[irq];
+       bit = sable_lynx_irq_swizzle->irq_to_mask[d->irq];
        spin_lock(&sable_lynx_irq_lock);
        mask = sable_lynx_irq_swizzle->shadow_mask |= 1UL << bit;
        sable_lynx_irq_swizzle->update_irq_hw(bit, mask);
@@ -475,11 +475,11 @@ sable_lynx_disable_irq(unsigned int irq)
 }
 
 static void
-sable_lynx_mask_and_ack_irq(unsigned int irq)
+sable_lynx_mask_and_ack_irq(struct irq_data *d)
 {
        unsigned long bit, mask;
 
-       bit = sable_lynx_irq_swizzle->irq_to_mask[irq];
+       bit = sable_lynx_irq_swizzle->irq_to_mask[d->irq];
        spin_lock(&sable_lynx_irq_lock);
        mask = sable_lynx_irq_swizzle->shadow_mask |= 1UL << bit;
        sable_lynx_irq_swizzle->update_irq_hw(bit, mask);
@@ -489,9 +489,9 @@ sable_lynx_mask_and_ack_irq(unsigned int irq)
 
 static struct irq_chip sable_lynx_irq_type = {
        .name           = "SABLE/LYNX",
-       .unmask         = sable_lynx_enable_irq,
-       .mask           = sable_lynx_disable_irq,
-       .mask_ack       = sable_lynx_mask_and_ack_irq,
+       .irq_unmask     = sable_lynx_enable_irq,
+       .irq_mask       = sable_lynx_disable_irq,
+       .irq_mask_ack   = sable_lynx_mask_and_ack_irq,
 };
 
 static void 
@@ -518,9 +518,9 @@ sable_lynx_init_irq(int nr_of_irqs)
        long i;
 
        for (i = 0; i < nr_of_irqs; ++i) {
-               irq_to_desc(i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i, &sable_lynx_irq_type,
                        handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 
        common_init_isa_dma();
index f8a1e8a..42a5331 100644 (file)
@@ -45,16 +45,18 @@ takara_update_irq_hw(unsigned long irq, unsigned long mask)
 }
 
 static inline void
-takara_enable_irq(unsigned int irq)
+takara_enable_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
        unsigned long mask;
        mask = (cached_irq_mask[irq >= 64] &= ~(1UL << (irq & 63)));
        takara_update_irq_hw(irq, mask);
 }
 
 static void
-takara_disable_irq(unsigned int irq)
+takara_disable_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
        unsigned long mask;
        mask = (cached_irq_mask[irq >= 64] |= 1UL << (irq & 63));
        takara_update_irq_hw(irq, mask);
@@ -62,9 +64,9 @@ takara_disable_irq(unsigned int irq)
 
 static struct irq_chip takara_irq_type = {
        .name           = "TAKARA",
-       .unmask         = takara_enable_irq,
-       .mask           = takara_disable_irq,
-       .mask_ack       = takara_disable_irq,
+       .irq_unmask     = takara_enable_irq,
+       .irq_mask       = takara_disable_irq,
+       .irq_mask_ack   = takara_disable_irq,
 };
 
 static void
@@ -136,8 +138,8 @@ takara_init_irq(void)
                takara_update_irq_hw(i, -1);
 
        for (i = 16; i < 128; ++i) {
-               irq_to_desc(i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i, &takara_irq_type, handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 
        common_init_isa_dma();
index e02494b..8c13a0c 100644 (file)
@@ -112,8 +112,9 @@ titan_update_irq_hw(unsigned long mask)
 }
 
 static inline void
-titan_enable_irq(unsigned int irq)
+titan_enable_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
        spin_lock(&titan_irq_lock);
        titan_cached_irq_mask |= 1UL << (irq - 16);
        titan_update_irq_hw(titan_cached_irq_mask);
@@ -121,8 +122,9 @@ titan_enable_irq(unsigned int irq)
 }
 
 static inline void
-titan_disable_irq(unsigned int irq)
+titan_disable_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
        spin_lock(&titan_irq_lock);
        titan_cached_irq_mask &= ~(1UL << (irq - 16));
        titan_update_irq_hw(titan_cached_irq_mask);
@@ -144,8 +146,10 @@ titan_cpu_set_irq_affinity(unsigned int irq, cpumask_t affinity)
 }
 
 static int
-titan_set_irq_affinity(unsigned int irq, const struct cpumask *affinity)
+titan_set_irq_affinity(struct irq_data *d, const struct cpumask *affinity,
+                      bool force)
 { 
+       unsigned int irq = d->irq;
        spin_lock(&titan_irq_lock);
        titan_cpu_set_irq_affinity(irq - 16, *affinity);
        titan_update_irq_hw(titan_cached_irq_mask);
@@ -175,17 +179,17 @@ init_titan_irqs(struct irq_chip * ops, int imin, int imax)
 {
        long i;
        for (i = imin; i <= imax; ++i) {
-               irq_to_desc(i)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i, ops, handle_level_irq);
+               irq_set_status_flags(i, IRQ_LEVEL);
        }
 }
 
 static struct irq_chip titan_irq_type = {
-       .name           = "TITAN",
-       .unmask         = titan_enable_irq,
-       .mask           = titan_disable_irq,
-       .mask_ack       = titan_disable_irq,
-       .set_affinity   = titan_set_irq_affinity,
+       .name                   = "TITAN",
+       .irq_unmask             = titan_enable_irq,
+       .irq_mask               = titan_disable_irq,
+       .irq_mask_ack           = titan_disable_irq,
+       .irq_set_affinity       = titan_set_irq_affinity,
 };
 
 static irqreturn_t
index eec5259..ca60a38 100644 (file)
@@ -104,10 +104,12 @@ wildfire_init_irq_hw(void)
 }
 
 static void
-wildfire_enable_irq(unsigned int irq)
+wildfire_enable_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
+
        if (irq < 16)
-               i8259a_enable_irq(irq);
+               i8259a_enable_irq(d);
 
        spin_lock(&wildfire_irq_lock);
        set_bit(irq, &cached_irq_mask);
@@ -116,10 +118,12 @@ wildfire_enable_irq(unsigned int irq)
 }
 
 static void
-wildfire_disable_irq(unsigned int irq)
+wildfire_disable_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
+
        if (irq < 16)
-               i8259a_disable_irq(irq);
+               i8259a_disable_irq(d);
 
        spin_lock(&wildfire_irq_lock);
        clear_bit(irq, &cached_irq_mask);
@@ -128,10 +132,12 @@ wildfire_disable_irq(unsigned int irq)
 }
 
 static void
-wildfire_mask_and_ack_irq(unsigned int irq)
+wildfire_mask_and_ack_irq(struct irq_data *d)
 {
+       unsigned int irq = d->irq;
+
        if (irq < 16)
-               i8259a_mask_and_ack_irq(irq);
+               i8259a_mask_and_ack_irq(d);
 
        spin_lock(&wildfire_irq_lock);
        clear_bit(irq, &cached_irq_mask);
@@ -141,9 +147,9 @@ wildfire_mask_and_ack_irq(unsigned int irq)
 
 static struct irq_chip wildfire_irq_type = {
        .name           = "WILDFIRE",
-       .unmask         = wildfire_enable_irq,
-       .mask           = wildfire_disable_irq,
-       .mask_ack       = wildfire_mask_and_ack_irq,
+       .irq_unmask     = wildfire_enable_irq,
+       .irq_mask       = wildfire_disable_irq,
+       .irq_mask_ack   = wildfire_mask_and_ack_irq,
 };
 
 static void __init
@@ -177,21 +183,21 @@ wildfire_init_irq_per_pca(int qbbno, int pcano)
        for (i = 0; i < 16; ++i) {
                if (i == 2)
                        continue;
-               irq_to_desc(i+irq_bias)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i+irq_bias, &wildfire_irq_type,
                        handle_level_irq);
+               irq_set_status_flags(i + irq_bias, IRQ_LEVEL);
        }
 
-       irq_to_desc(36+irq_bias)->status |= IRQ_LEVEL;
        set_irq_chip_and_handler(36+irq_bias, &wildfire_irq_type,
                handle_level_irq);
+       irq_set_status_flags(36 + irq_bias, IRQ_LEVEL);
        for (i = 40; i < 64; ++i) {
-               irq_to_desc(i+irq_bias)->status |= IRQ_LEVEL;
                set_irq_chip_and_handler(i+irq_bias, &wildfire_irq_type,
                        handle_level_irq);
+               irq_set_status_flags(i + irq_bias, IRQ_LEVEL);
        }
 
-       setup_irq(32+irq_bias, &isa_enable);    
+       setup_irq(32+irq_bias, &isa_enable);
 }
 
 static void __init
index c1f3e7c..a58e84f 100644 (file)
@@ -159,7 +159,7 @@ void read_persistent_clock(struct timespec *ts)
 
 /*
  * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
+ * as well as call the "xtime_update()" routine every clocktick
  */
 irqreturn_t timer_interrupt(int irq, void *dev)
 {
@@ -172,8 +172,6 @@ irqreturn_t timer_interrupt(int irq, void *dev)
        profile_tick(CPU_PROFILING);
 #endif
 
-       write_seqlock(&xtime_lock);
-
        /*
         * Calculate how many ticks have passed since the last update,
         * including any previous partial leftover.  Save any resulting
@@ -187,9 +185,7 @@ irqreturn_t timer_interrupt(int irq, void *dev)
        nticks = delta >> FIX_SHIFT;
 
        if (nticks)
-               do_timer(nticks);
-
-       write_sequnlock(&xtime_lock);
+               xtime_update(nticks);
 
        if (test_irq_work_pending()) {
                clear_irq_work_pending();
index 5cff165..166efa2 100644 (file)
@@ -1177,6 +1177,31 @@ config ARM_ERRATA_743622
          visible impact on the overall performance or power consumption of the
          processor.
 
+config ARM_ERRATA_751472
+       bool "ARM errata: Interrupted ICIALLUIS may prevent completion of broadcasted operation"
+       depends on CPU_V7 && SMP
+       help
+         This option enables the workaround for the 751472 Cortex-A9 (prior
+         to r3p0) erratum. An interrupted ICIALLUIS operation may prevent the
+         completion of a following broadcasted operation if the second
+         operation is received by a CPU before the ICIALLUIS has completed,
+         potentially leading to corrupted entries in the cache or TLB.
+
+config ARM_ERRATA_753970
+       bool "ARM errata: cache sync operation may be faulty"
+       depends on CACHE_PL310
+       help
+         This option enables the workaround for the 753970 PL310 (r3p0) erratum.
+
+         Under some condition the effect of cache sync operation on
+         the store buffer still remains when the operation completes.
+         This means that the store buffer is always asked to drain and
+         this prevents it from merging any further writes. The workaround
+         is to replace the normal offset of cache sync operation (0x730)
+         by another offset targeting an unmapped PL310 register 0x740.
+         This has the same effect as the cache sync operation: store buffer
+         drain and waiting for all buffers empty.
+
 endmenu
 
 source "arch/arm/common/Kconfig"
@@ -1391,7 +1416,7 @@ config AEABI
 
 config OABI_COMPAT
        bool "Allow old ABI binaries to run with this kernel (EXPERIMENTAL)"
-       depends on AEABI && EXPERIMENTAL
+       depends on AEABI && EXPERIMENTAL && !THUMB2_KERNEL
        default y
        help
          This option preserves the old syscall interface along with the
index c22c1ad..6f7b292 100644 (file)
@@ -15,7 +15,7 @@ ifeq ($(CONFIG_CPU_ENDIAN_BE8),y)
 LDFLAGS_vmlinux        += --be8
 endif
 
-OBJCOPYFLAGS   :=-O binary -R .note -R .note.gnu.build-id -R .comment -S
+OBJCOPYFLAGS   :=-O binary -R .comment -S
 GZFLAGS                :=-9
 #KBUILD_CFLAGS +=-pipe
 # Explicitly specifiy 32-bit ARM ISA since toolchain default can be -mthumb:
index ab204db..c602896 100644 (file)
@@ -1,3 +1,7 @@
 font.c
-piggy.gz
+lib1funcs.S
+piggy.gzip
+piggy.lzo
+piggy.lzma
+vmlinux
 vmlinux.lds
index 778655f..ea5ee4d 100644 (file)
@@ -6,6 +6,8 @@ config ARM_VIC
 
 config ARM_VIC_NR
        int
+       default 4 if ARCH_S5PV210
+       default 3 if ARCH_S5P6442 || ARCH_S5PC100
        default 2
        depends on ARM_VIC
        help
index b33fe70..199a6b6 100644 (file)
@@ -35,7 +35,7 @@
        : "cc", "memory")
 
 static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
 {
        int op = (encoded_op >> 28) & 7;
        int cmp = (encoded_op >> 24) & 15;
@@ -46,7 +46,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
        if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
                oparg = 1 << oparg;
 
-       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
        pagefault_disable();    /* implies preempt_disable() */
@@ -88,36 +88,35 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
 }
 
 static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+                             u32 oldval, u32 newval)
 {
-       int val;
+       int ret = 0;
+       u32 val;
 
-       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
-       pagefault_disable();    /* implies preempt_disable() */
-
        __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
-       "1:     " T(ldr) "      %0, [%3]\n"
-       "       teq     %0, %1\n"
+       "1:     " T(ldr) "      %1, [%4]\n"
+       "       teq     %1, %2\n"
        "       it      eq      @ explicit IT needed for the 2b label\n"
-       "2:     " T(streq) "    %2, [%3]\n"
+       "2:     " T(streq) "    %3, [%4]\n"
        "3:\n"
        "       .pushsection __ex_table,\"a\"\n"
        "       .align  3\n"
        "       .long   1b, 4f, 2b, 4f\n"
        "       .popsection\n"
        "       .pushsection .fixup,\"ax\"\n"
-       "4:     mov     %0, %4\n"
+       "4:     mov     %0, %5\n"
        "       b       3b\n"
        "       .popsection"
-       : "=&r" (val)
+       : "+r" (ret), "=&r" (val)
        : "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT)
        : "cc", "memory");
 
-       pagefault_enable();     /* subsumes preempt_enable() */
-
-       return val;
+       *uval = val;
+       return ret;
 }
 
 #endif /* !SMP */
index 5aeec1e..16bd480 100644 (file)
@@ -36,6 +36,7 @@
 #define L2X0_RAW_INTR_STAT             0x21C
 #define L2X0_INTR_CLEAR                        0x220
 #define L2X0_CACHE_SYNC                        0x730
+#define L2X0_DUMMY_REG                 0x740
 #define L2X0_INV_LINE_PA               0x770
 #define L2X0_INV_WAY                   0x77C
 #define L2X0_CLEAN_LINE_PA             0x7B0
index a101f10..e0d1c0c 100644 (file)
 #define SCPCELLID2             0xFF8
 #define SCPCELLID3             0xFFC
 
+#define SCCTRL_TIMEREN0SEL_REFCLK      (0 << 15)
+#define SCCTRL_TIMEREN0SEL_TIMCLK      (1 << 15)
+
+#define SCCTRL_TIMEREN1SEL_REFCLK      (0 << 17)
+#define SCCTRL_TIMEREN1SEL_TIMCLK      (1 << 17)
+
 static inline void sysctl_soft_reset(void __iomem *base)
 {
+       /* switch to slow mode */
+       writel(0x2, base + SCCTRL);
+
        /* writing any value to SCSYSSTAT reg will reset system */
        writel(0, base + SCSYSSTAT);
 }
index 20e0f7c..d66605d 100644 (file)
@@ -95,6 +95,15 @@ static inline void __iomem *__typesafe_io(unsigned long addr)
        return (void __iomem *)addr;
 }
 
+/* IO barriers */
+#ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE
+#define __iormb()              rmb()
+#define __iowmb()              wmb()
+#else
+#define __iormb()              do { } while (0)
+#define __iowmb()              do { } while (0)
+#endif
+
 /*
  * Now, pick up the machine-defined IO definitions
  */
@@ -125,17 +134,17 @@ static inline void __iomem *__typesafe_io(unsigned long addr)
  * The {in,out}[bwl] macros are for emulating x86-style PCI/ISA IO space.
  */
 #ifdef __io
-#define outb(v,p)              __raw_writeb(v,__io(p))
-#define outw(v,p)              __raw_writew((__force __u16) \
-                                       cpu_to_le16(v),__io(p))
-#define outl(v,p)              __raw_writel((__force __u32) \
-                                       cpu_to_le32(v),__io(p))
+#define outb(v,p)      ({ __iowmb(); __raw_writeb(v,__io(p)); })
+#define outw(v,p)      ({ __iowmb(); __raw_writew((__force __u16) \
+                                       cpu_to_le16(v),__io(p)); })
+#define outl(v,p)      ({ __iowmb(); __raw_writel((__force __u32) \
+                                       cpu_to_le32(v),__io(p)); })
 
-#define inb(p) ({ __u8 __v = __raw_readb(__io(p)); __v; })
+#define inb(p) ({ __u8 __v = __raw_readb(__io(p)); __iormb(); __v; })
 #define inw(p) ({ __u16 __v = le16_to_cpu((__force __le16) \
-                       __raw_readw(__io(p))); __v; })
+                       __raw_readw(__io(p))); __iormb(); __v; })
 #define inl(p) ({ __u32 __v = le32_to_cpu((__force __le32) \
-                       __raw_readl(__io(p))); __v; })
+                       __raw_readl(__io(p))); __iormb(); __v; })
 
 #define outsb(p,d,l)           __raw_writesb(__io(p),d,l)
 #define outsw(p,d,l)           __raw_writesw(__io(p),d,l)
@@ -192,14 +201,6 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
 #define writel_relaxed(v,c)    ((void)__raw_writel((__force u32) \
                                        cpu_to_le32(v),__mem_pci(c)))
 
-#ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE
-#define __iormb()              rmb()
-#define __iowmb()              wmb()
-#else
-#define __iormb()              do { } while (0)
-#define __iowmb()              do { } while (0)
-#endif
-
 #define readb(c)               ({ u8  __v = readb_relaxed(c); __iormb(); __v; })
 #define readw(c)               ({ u16 __v = readw_relaxed(c); __iormb(); __v; })
 #define readl(c)               ({ u32 __v = readl_relaxed(c); __iormb(); __v; })
index 3a0893a..bf13b81 100644 (file)
@@ -15,10 +15,6 @@ struct meminfo;
 struct sys_timer;
 
 struct machine_desc {
-       /*
-        * Note! The first two elements are used
-        * by assembler code in head.S, head-common.S
-        */
        unsigned int            nr;             /* architecture number  */
        const char              *name;          /* architecture name    */
        unsigned long           boot_params;    /* tagged list          */
index 23c2e8e..d0ee74b 100644 (file)
  * translation for translating DMA addresses.  Use the driver
  * DMA support - see dma-mapping.h.
  */
-static inline unsigned long virt_to_phys(void *x)
+static inline unsigned long virt_to_phys(const volatile void *x)
 {
        return __virt_to_phys((unsigned long)(x));
 }
index 9763be0..22de005 100644 (file)
@@ -10,6 +10,8 @@
 #ifndef _ASMARM_PGALLOC_H
 #define _ASMARM_PGALLOC_H
 
+#include <linux/pagemap.h>
+
 #include <asm/domain.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/processor.h>
index f41a6f5..82dfe5d 100644 (file)
 #define __ASMARM_TLB_H
 
 #include <asm/cacheflush.h>
-#include <asm/tlbflush.h>
 
 #ifndef CONFIG_MMU
 
 #include <linux/pagemap.h>
+
+#define tlb_flush(tlb) ((void) tlb)
+
 #include <asm-generic/tlb.h>
 
 #else /* !CONFIG_MMU */
 
+#include <linux/swap.h>
 #include <asm/pgalloc.h>
+#include <asm/tlbflush.h>
+
+/*
+ * We need to delay page freeing for SMP as other CPUs can access pages
+ * which have been removed but not yet had their TLB entries invalidated.
+ * Also, as ARMv7 speculative prefetch can drag new entries into the TLB,
+ * we need to apply this same delaying tactic to ensure correct operation.
+ */
+#if defined(CONFIG_SMP) || defined(CONFIG_CPU_32v7)
+#define tlb_fast_mode(tlb)     0
+#define FREE_PTE_NR            500
+#else
+#define tlb_fast_mode(tlb)     1
+#define FREE_PTE_NR            0
+#endif
 
 /*
  * TLB handling.  This allows us to remove pages from the page
 struct mmu_gather {
        struct mm_struct        *mm;
        unsigned int            fullmm;
+       struct vm_area_struct   *vma;
        unsigned long           range_start;
        unsigned long           range_end;
+       unsigned int            nr;
+       struct page             *pages[FREE_PTE_NR];
 };
 
 DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
 
+/*
+ * This is unnecessarily complex.  There's three ways the TLB shootdown
+ * code is used:
+ *  1. Unmapping a range of vmas.  See zap_page_range(), unmap_region().
+ *     tlb->fullmm = 0, and tlb_start_vma/tlb_end_vma will be called.
+ *     tlb->vma will be non-NULL.
+ *  2. Unmapping all vmas.  See exit_mmap().
+ *     tlb->fullmm = 1, and tlb_start_vma/tlb_end_vma will be called.
+ *     tlb->vma will be non-NULL.  Additionally, page tables will be freed.
+ *  3. Unmapping argument pages.  See shift_arg_pages().
+ *     tlb->fullmm = 0, but tlb_start_vma/tlb_end_vma will not be called.
+ *     tlb->vma will be NULL.
+ */
+static inline void tlb_flush(struct mmu_gather *tlb)
+{
+       if (tlb->fullmm || !tlb->vma)
+               flush_tlb_mm(tlb->mm);
+       else if (tlb->range_end > 0) {
+               flush_tlb_range(tlb->vma, tlb->range_start, tlb->range_end);
+               tlb->range_start = TASK_SIZE;
+               tlb->range_end = 0;
+       }
+}
+
+static inline void tlb_add_flush(struct mmu_gather *tlb, unsigned long addr)
+{
+       if (!tlb->fullmm) {
+               if (addr < tlb->range_start)
+                       tlb->range_start = addr;
+               if (addr + PAGE_SIZE > tlb->range_end)
+                       tlb->range_end = addr + PAGE_SIZE;
+       }
+}
+
+static inline void tlb_flush_mmu(struct mmu_gather *tlb)
+{
+       tlb_flush(tlb);
+       if (!tlb_fast_mode(tlb)) {
+               free_pages_and_swap_cache(tlb->pages, tlb->nr);
+               tlb->nr = 0;
+       }
+}
+
 static inline struct mmu_gather *
 tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
 {
@@ -49,6 +113,8 @@ tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
 
        tlb->mm = mm;
        tlb->fullmm = full_mm_flush;
+       tlb->vma = NULL;
+       tlb->nr = 0;
 
        return tlb;
 }
@@ -56,8 +122,7 @@ tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
 static inline void
 tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
 {
-       if (tlb->fullmm)
-               flush_tlb_mm(tlb->mm);
+       tlb_flush_mmu(tlb);
 
        /* keep the page table cache within bounds */
        check_pgt_cache();
@@ -71,12 +136,7 @@ tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
 static inline void
 tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, unsigned long addr)
 {
-       if (!tlb->fullmm) {
-               if (addr < tlb->range_start)
-                       tlb->range_start = addr;
-               if (addr + PAGE_SIZE > tlb->range_end)
-                       tlb->range_end = addr + PAGE_SIZE;
-       }
+       tlb_add_flush(tlb, addr);
 }
 
 /*
@@ -89,6 +149,7 @@ tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
 {
        if (!tlb->fullmm) {
                flush_cache_range(vma, vma->vm_start, vma->vm_end);
+               tlb->vma = vma;
                tlb->range_start = TASK_SIZE;
                tlb->range_end = 0;
        }
@@ -97,12 +158,30 @@ tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
 static inline void
 tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
 {
-       if (!tlb->fullmm && tlb->range_end > 0)
-               flush_tlb_range(vma, tlb->range_start, tlb->range_end);
+       if (!tlb->fullmm)
+               tlb_flush(tlb);
+}
+
+static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+       if (tlb_fast_mode(tlb)) {
+               free_page_and_swap_cache(page);
+       } else {
+               tlb->pages[tlb->nr++] = page;
+               if (tlb->nr >= FREE_PTE_NR)
+                       tlb_flush_mmu(tlb);
+       }
+}
+
+static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
+       unsigned long addr)
+{
+       pgtable_page_dtor(pte);
+       tlb_add_flush(tlb, addr);
+       tlb_remove_page(tlb, pte);
 }
 
-#define tlb_remove_page(tlb,page)      free_page_and_swap_cache(page)
-#define pte_free_tlb(tlb, ptep, addr)  pte_free((tlb)->mm, ptep)
+#define pte_free_tlb(tlb, ptep, addr)  __pte_free_tlb(tlb, ptep, addr)
 #define pmd_free_tlb(tlb, pmdp, addr)  pmd_free((tlb)->mm, pmdp)
 
 #define tlb_migrate_finish(mm)         do { } while (0)
index ce7378e..d2005de 100644 (file)
 #ifndef _ASMARM_TLBFLUSH_H
 #define _ASMARM_TLBFLUSH_H
 
-
-#ifndef CONFIG_MMU
-
-#define tlb_flush(tlb) ((void) tlb)
-
-#else /* CONFIG_MMU */
+#ifdef CONFIG_MMU
 
 #include <asm/glue.h>
 
index f17d9a0..f06ff9f 100644 (file)
@@ -391,25 +391,24 @@ ENDPROC(__turn_mmu_on)
 
 
 #ifdef CONFIG_SMP_ON_UP
+       __INIT
 __fixup_smp:
-       mov     r4, #0x00070000
-       orr     r3, r4, #0xff000000     @ mask 0xff070000
-       orr     r4, r4, #0x41000000     @ val 0x41070000
-       and     r0, r9, r3
-       teq     r0, r4                  @ ARM CPU and ARMv6/v7?
+       and     r3, r9, #0x000f0000     @ architecture version
+       teq     r3, #0x000f0000         @ CPU ID supported?
        bne     __fixup_smp_on_up       @ no, assume UP
 
-       orr     r3, r3, #0x0000ff00
-       orr     r3, r3, #0x000000f0     @ mask 0xff07fff0
+       bic     r3, r9, #0x00ff0000
+       bic     r3, r3, #0x0000000f     @ mask 0xff00fff0
+       mov     r4, #0x41000000
        orr     r4, r4, #0x0000b000
-       orr     r4, r4, #0x00000020     @ val 0x4107b020
-       and     r0, r9, r3
-       teq     r0, r4                  @ ARM 11MPCore?
+       orr     r4, r4, #0x00000020     @ val 0x4100b020
+       teq     r3, r4                  @ ARM 11MPCore?
        moveq   pc, lr                  @ yes, assume SMP
 
        mrc     p15, 0, r0, c0, c0, 5   @ read MPIDR
-       tst     r0, #1 << 31
-       movne   pc, lr                  @ bit 31 => SMP
+       and     r0, r0, #0xc0000000     @ multiprocessing extensions and
+       teq     r0, #0x80000000         @ not part of a uniprocessor system?
+       moveq   pc, lr                  @ yes, assume SMP
 
 __fixup_smp_on_up:
        adr     r0, 1f
@@ -417,18 +416,7 @@ __fixup_smp_on_up:
        sub     r3, r0, r3
        add     r4, r4, r3
        add     r5, r5, r3
-2:     cmp     r4, r5
-       movhs   pc, lr
-       ldmia   r4!, {r0, r6}
- ARM(  str     r6, [r0, r3]    )
- THUMB(        add     r0, r0, r3      )
-#ifdef __ARMEB__
- THUMB(        mov     r6, r6, ror #16 )       @ Convert word order for big-endian.
-#endif
- THUMB(        strh    r6, [r0], #2    )       @ For Thumb-2, store as two halfwords
- THUMB(        mov     r6, r6, lsr #16 )       @ to be robust against misaligned r3.
- THUMB(        strh    r6, [r0]        )
-       b       2b
+       b       __do_fixup_smp_on_up
 ENDPROC(__fixup_smp)
 
        .align
@@ -442,7 +430,31 @@ smp_on_up:
        ALT_SMP(.long   1)
        ALT_UP(.long    0)
        .popsection
+#endif
 
+       .text
+__do_fixup_smp_on_up:
+       cmp     r4, r5
+       movhs   pc, lr
+       ldmia   r4!, {r0, r6}
+ ARM(  str     r6, [r0, r3]    )
+ THUMB(        add     r0, r0, r3      )
+#ifdef __ARMEB__
+ THUMB(        mov     r6, r6, ror #16 )       @ Convert word order for big-endian.
 #endif
+ THUMB(        strh    r6, [r0], #2    )       @ For Thumb-2, store as two halfwords
+ THUMB(        mov     r6, r6, lsr #16 )       @ to be robust against misaligned r3.
+ THUMB(        strh    r6, [r0]        )
+       b       __do_fixup_smp_on_up
+ENDPROC(__do_fixup_smp_on_up)
+
+ENTRY(fixup_smp)
+       stmfd   sp!, {r4 - r6, lr}
+       mov     r4, r0
+       add     r5, r0, r1
+       mov     r3, #0
+       bl      __do_fixup_smp_on_up
+       ldmfd   sp!, {r4 - r6, pc}
+ENDPROC(fixup_smp)
 
 #include "head-common.S"
index c9f3f04..44b84fe 100644 (file)
@@ -137,11 +137,10 @@ static u8 get_debug_arch(void)
        u32 didr;
 
        /* Do we implement the extended CPUID interface? */
-       if (((read_cpuid_id() >> 16) & 0xf) != 0xf) {
-               pr_warning("CPUID feature registers not supported. "
-                               "Assuming v6 debug is present.\n");
+       if (WARN_ONCE((((read_cpuid_id() >> 16) & 0xf) != 0xf),
+           "CPUID feature registers not supported. "
+           "Assuming v6 debug is present.\n"))
                return ARM_DEBUG_ARCH_V6;
-       }
 
        ARM_DBG_READ(c0, 0, didr);
        return (didr >> 16) & 0xf;
@@ -152,6 +151,12 @@ u8 arch_get_debug_arch(void)
        return debug_arch;
 }
 
+static int debug_arch_supported(void)
+{
+       u8 arch = get_debug_arch();
+       return arch >= ARM_DEBUG_ARCH_V6 && arch <= ARM_DEBUG_ARCH_V7_ECP14;
+}
+
 /* Determine number of BRP register available. */
 static int get_num_brp_resources(void)
 {
@@ -268,6 +273,9 @@ out:
 
 int hw_breakpoint_slots(int type)
 {
+       if (!debug_arch_supported())
+               return 0;
+
        /*
         * We can be called early, so don't rely on
         * our static variables being initialised.
@@ -828,19 +836,32 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
 /*
  * One-time initialisation.
  */
-static void reset_ctrl_regs(void *unused)
+static void reset_ctrl_regs(void *info)
 {
-       int i;
+       int i, cpu = smp_processor_id();
+       u32 dbg_power;
+       cpumask_t *cpumask = info;
 
        /*
         * v7 debug contains save and restore registers so that debug state
-        * can be maintained across low-power modes without leaving
-        * the debug logic powered up. It is IMPLEMENTATION DEFINED whether
-        * we can write to the debug registers out of reset, so we must
-        * unlock the OS Lock Access Register to avoid taking undefined
-        * instruction exceptions later on.
+        * can be maintained across low-power modes without leaving the debug
+        * logic powered up. It is IMPLEMENTATION DEFINED whether we can access
+        * the debug registers out of reset, so we must unlock the OS Lock
+        * Access Register to avoid taking undefined instruction exceptions
+        * later on.
         */
        if (debug_arch >= ARM_DEBUG_ARCH_V7_ECP14) {
+               /*
+                * Ensure sticky power-down is clear (i.e. debug logic is
+                * powered up).
+                */
+               asm volatile("mrc p14, 0, %0, c1, c5, 4" : "=r" (dbg_power));
+               if ((dbg_power & 0x1) == 0) {
+                       pr_warning("CPU %d debug is powered down!\n", cpu);
+                       cpumask_or(cpumask, cpumask, cpumask_of(cpu));
+                       return;
+               }
+
                /*
                 * Unconditionally clear the lock by writing a value
                 * other than 0xC5ACCE55 to the access register.
@@ -879,10 +900,11 @@ static struct notifier_block __cpuinitdata dbg_reset_nb = {
 static int __init arch_hw_breakpoint_init(void)
 {
        u32 dscr;
+       cpumask_t cpumask = { CPU_BITS_NONE };
 
        debug_arch = get_debug_arch();
 
-       if (debug_arch > ARM_DEBUG_ARCH_V7_ECP14) {
+       if (!debug_arch_supported()) {
                pr_info("debug architecture 0x%x unsupported.\n", debug_arch);
                return 0;
        }
@@ -899,18 +921,24 @@ static int __init arch_hw_breakpoint_init(void)
                pr_info("%d breakpoint(s) reserved for watchpoint "
                                "single-step.\n", core_num_reserved_brps);
 
+       /*
+        * Reset the breakpoint resources. We assume that a halting
+        * debugger will leave the world in a nice state for us.
+        */
+       on_each_cpu(reset_ctrl_regs, &cpumask, 1);
+       if (!cpumask_empty(&cpumask)) {
+               core_num_brps = 0;
+               core_num_reserved_brps = 0;
+               core_num_wrps = 0;
+               return 0;
+       }
+
        ARM_DBG_READ(c1, 0, dscr);
        if (dscr & ARM_DSCR_HDBGEN) {
+               max_watchpoint_len = 4;
                pr_warning("halting debug mode enabled. Assuming maximum "
-                               "watchpoint size of 4 bytes.");
+                          "watchpoint size of %u bytes.", max_watchpoint_len);
        } else {
-               /*
-                * Reset the breakpoint resources. We assume that a halting
-                * debugger will leave the world in a nice state for us.
-                */
-               smp_call_function(reset_ctrl_regs, NULL, 1);
-               reset_ctrl_regs(NULL);
-
                /* Work out the maximum supported watchpoint length. */
                max_watchpoint_len = get_max_wp_len();
                pr_info("maximum watchpoint size is %u bytes.\n",
index 2c1f005..8f6ed43 100644 (file)
@@ -1437,7 +1437,7 @@ arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi)
 
                return space_cccc_1100_010x(insn, asi);
 
-       } else if ((insn & 0x0e000000) == 0x0c400000) {
+       } else if ((insn & 0x0e000000) == 0x0c000000) {
 
                return space_cccc_110x(insn, asi);
 
index 2cfe816..6d4105e 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <asm/pgtable.h>
 #include <asm/sections.h>
+#include <asm/smp_plat.h>
 #include <asm/unwind.h>
 
 #ifdef CONFIG_XIP_KERNEL
@@ -268,12 +269,28 @@ struct mod_unwind_map {
        const Elf_Shdr *txt_sec;
 };
 
+static const Elf_Shdr *find_mod_section(const Elf32_Ehdr *hdr,
+       const Elf_Shdr *sechdrs, const char *name)
+{
+       const Elf_Shdr *s, *se;
+       const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+       for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++)
+               if (strcmp(name, secstrs + s->sh_name) == 0)
+                       return s;
+
+       return NULL;
+}
+
+extern void fixup_smp(const void *, unsigned long);
+
 int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
                    struct module *mod)
 {
+       const Elf_Shdr * __maybe_unused s = NULL;
 #ifdef CONFIG_ARM_UNWIND
        const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
-       const Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum;
+       const Elf_Shdr *sechdrs_end = sechdrs + hdr->e_shnum;
        struct mod_unwind_map maps[ARM_SEC_MAX];
        int i;
 
@@ -315,6 +332,9 @@ int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
                                                 maps[i].txt_sec->sh_addr,
                                                 maps[i].txt_sec->sh_size);
 #endif
+       s = find_mod_section(hdr, sechdrs, ".alt.smp.init");
+       if (s && !is_smp())
+               fixup_smp((void *)s->sh_addr, s->sh_size);
        return 0;
 }
 
index 5efa264..d150ad1 100644 (file)
@@ -700,7 +700,7 @@ user_backtrace(struct frame_tail __user *tail,
         * Frame pointers should strictly progress back up the stack
         * (towards higher addresses).
         */
-       if (tail >= buftail.fp)
+       if (tail + 1 >= buftail.fp)
                return NULL;
 
        return buftail.fp - 1;
index b8af96e..2c79eec 100644 (file)
@@ -97,28 +97,34 @@ set_irq_affinity(int irq,
                           irq, cpu);
        return err;
 #else
-       return 0;
+       return -EINVAL;
 #endif
 }
 
 static int
 init_cpu_pmu(void)
 {
-       int i, err = 0;
+       int i, irqs, err = 0;
        struct platform_device *pdev = pmu_devices[ARM_PMU_DEVICE_CPU];
 
-       if (!pdev) {
-               err = -ENODEV;
-               goto out;
-       }
+       if (!pdev)
+               return -ENODEV;
+
+       irqs = pdev->num_resources;
+
+       /*
+        * If we have a single PMU interrupt that we can't shift, assume that
+        * we're running on a uniprocessor machine and continue.
+        */
+       if (irqs == 1 && !irq_can_set_affinity(platform_get_irq(pdev, 0)))
+               return 0;
 
-       for (i = 0; i < pdev->num_resources; ++i) {
+       for (i = 0; i < irqs; ++i) {
                err = set_irq_affinity(platform_get_irq(pdev, i), i);
                if (err)
                        break;
        }
 
-out:
        return err;
 }
 
index 19c6816..b13e70f 100644 (file)
@@ -996,10 +996,10 @@ static int ptrace_gethbpregs(struct task_struct *tsk, long num,
                while (!(arch_ctrl.len & 0x1))
                        arch_ctrl.len >>= 1;
 
-               if (idx & 0x1)
-                       reg = encode_ctrl_reg(arch_ctrl);
-               else
+               if (num & 0x1)
                        reg = bp->attr.bp_addr;
+               else
+                       reg = encode_ctrl_reg(arch_ctrl);
        }
 
 put:
index 420b8d6..5ea4fb7 100644 (file)
@@ -226,8 +226,8 @@ int cpu_architecture(void)
                 * Register 0 and check for VMSAv7 or PMSAv7 */
                asm("mrc        p15, 0, %0, c0, c1, 4"
                    : "=r" (mmfr0));
-               if ((mmfr0 & 0x0000000f) == 0x00000003 ||
-                   (mmfr0 & 0x000000f0) == 0x00000030)
+               if ((mmfr0 & 0x0000000f) >= 0x00000003 ||
+                   (mmfr0 & 0x000000f0) >= 0x00000030)
                        cpu_arch = CPU_ARCH_ARMv7;
                else if ((mmfr0 & 0x0000000f) == 0x00000002 ||
                         (mmfr0 & 0x000000f0) == 0x00000020)
index 907d5a6..abaf844 100644 (file)
@@ -474,7 +474,9 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka,
        unsigned long handler = (unsigned long)ka->sa.sa_handler;
        unsigned long retcode;
        int thumb = 0;
-       unsigned long cpsr = regs->ARM_cpsr & ~PSR_f;
+       unsigned long cpsr = regs->ARM_cpsr & ~(PSR_f | PSR_E_BIT);
+
+       cpsr |= PSR_ENDSTATE;
 
        /*
         * Maybe we need to deliver a 32-bit signal to a 26-bit task.
index fd91566..60636f4 100644 (file)
@@ -36,6 +36,7 @@ static void twd_set_mode(enum clock_event_mode mode,
                /* timer load already set up */
                ctrl = TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE
                        | TWD_TIMER_CONTROL_PERIODIC;
+               __raw_writel(twd_timer_rate / HZ, twd_base + TWD_TIMER_LOAD);
                break;
        case CLOCK_EVT_MODE_ONESHOT:
                /* period set, and timer enabled in 'next_event' hook */
@@ -81,7 +82,7 @@ int twd_timer_ack(void)
 
 static void __cpuinit twd_calibrate_rate(void)
 {
-       unsigned long load, count;
+       unsigned long count;
        u64 waitjiffies;
 
        /*
@@ -116,10 +117,6 @@ static void __cpuinit twd_calibrate_rate(void)
                printk("%lu.%02luMHz.\n", twd_timer_rate / 1000000,
                        (twd_timer_rate / 1000000) % 100);
        }
-
-       load = twd_timer_rate / HZ;
-
-       __raw_writel(load, twd_base + TWD_TIMER_LOAD);
 }
 
 /*
index 3d76bf2..1ff46ca 100644 (file)
@@ -107,9 +107,7 @@ void timer_tick(void)
 {
        profile_tick(CPU_PROFILING);
        do_leds();
-       write_seqlock(&xtime_lock);
-       do_timer(1);
-       write_sequnlock(&xtime_lock);
+       xtime_update(1);
 #ifndef CONFIG_SMP
        update_process_times(user_mode(get_irq_regs()));
 #endif
index cf78a03..28fea9b 100644 (file)
 #define ARM_CPU_KEEP(x)
 #endif
 
+#if defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK)
+#define ARM_EXIT_KEEP(x)       x
+#else
+#define ARM_EXIT_KEEP(x)
+#endif
+
 OUTPUT_ARCH(arm)
 ENTRY(stext)
 
@@ -43,6 +49,7 @@ SECTIONS
                _sinittext = .;
                        HEAD_TEXT
                        INIT_TEXT
+                       ARM_EXIT_KEEP(EXIT_TEXT)
                _einittext = .;
                ARM_CPU_DISCARD(PROC_INFO)
                __arch_info_begin = .;
@@ -67,6 +74,7 @@ SECTIONS
 #ifndef CONFIG_XIP_KERNEL
                __init_begin = _stext;
                INIT_DATA
+               ARM_EXIT_KEEP(EXIT_DATA)
 #endif
        }
 
@@ -162,6 +170,7 @@ SECTIONS
                . = ALIGN(PAGE_SIZE);
                __init_begin = .;
                INIT_DATA
+               ARM_EXIT_KEEP(EXIT_DATA)
                . = ALIGN(PAGE_SIZE);
                __init_end = .;
 #endif
@@ -247,6 +256,8 @@ SECTIONS
        }
 #endif
 
+       NOTES
+
        BSS_SECTION(0, 0, 0)
        _end = .;
 
index 8fe283c..61fef91 100644 (file)
@@ -30,7 +30,7 @@ p720t_timer_interrupt(int irq, void *dev_id)
 {
        struct pt_regs *regs = get_irq_regs();
        do_leds();
-       do_timer(1);
+       xtime_update(1);
 #ifndef CONFIG_SMP
        update_process_times(user_mode(regs));
 #endif
index 343de73..4a68c2b 100644 (file)
@@ -132,7 +132,7 @@ out:
        return ret;
 }
 
-static int __init davinci_cpu_init(struct cpufreq_policy *policy)
+static int davinci_cpu_init(struct cpufreq_policy *policy)
 {
        int result = 0;
        struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data;
index 9eec630..beda8a4 100644 (file)
@@ -480,8 +480,15 @@ static struct platform_device da850_mcasp_device = {
        .resource       = da850_mcasp_resources,
 };
 
+struct platform_device davinci_pcm_device = {
+       .name   = "davinci-pcm-audio",
+       .id     = -1,
+};
+
 void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata)
 {
+       platform_device_register(&davinci_pcm_device);
+
        /* DA830/OMAP-L137 has 3 instances of McASP */
        if (cpu_is_davinci_da830() && id == 1) {
                da830_mcasp1_device.dev.platform_data = pdata;
index d102986..3fa3e28 100644 (file)
@@ -58,7 +58,7 @@ static int tnetv107x_gpio_request(struct gpio_chip *chip, unsigned offset)
 
        spin_lock_irqsave(&ctlr->lock, flags);
 
-       gpio_reg_set_bit(&regs->enable, gpio);
+       gpio_reg_set_bit(regs->enable, gpio);
 
        spin_unlock_irqrestore(&ctlr->lock, flags);
 
@@ -74,7 +74,7 @@ static void tnetv107x_gpio_free(struct gpio_chip *chip, unsigned offset)
 
        spin_lock_irqsave(&ctlr->lock, flags);
 
-       gpio_reg_clear_bit(&regs->enable, gpio);
+       gpio_reg_clear_bit(regs->enable, gpio);
 
        spin_unlock_irqrestore(&ctlr->lock, flags);
 }
@@ -88,7 +88,7 @@ static int tnetv107x_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
 
        spin_lock_irqsave(&ctlr->lock, flags);
 
-       gpio_reg_set_bit(&regs->direction, gpio);
+       gpio_reg_set_bit(regs->direction, gpio);
 
        spin_unlock_irqrestore(&ctlr->lock, flags);
 
@@ -106,11 +106,11 @@ static int tnetv107x_gpio_dir_out(struct gpio_chip *chip,
        spin_lock_irqsave(&ctlr->lock, flags);
 
        if (value)
-               gpio_reg_set_bit(&regs->data_out, gpio);
+               gpio_reg_set_bit(regs->data_out, gpio);
        else
-               gpio_reg_clear_bit(&regs->data_out, gpio);
+               gpio_reg_clear_bit(regs->data_out, gpio);
 
-       gpio_reg_clear_bit(&regs->direction, gpio);
+       gpio_reg_clear_bit(regs->direction, gpio);
 
        spin_unlock_irqrestore(&ctlr->lock, flags);
 
@@ -124,7 +124,7 @@ static int tnetv107x_gpio_get(struct gpio_chip *chip, unsigned offset)
        unsigned gpio = chip->base + offset;
        int ret;
 
-       ret = gpio_reg_get_bit(&regs->data_in, gpio);
+       ret = gpio_reg_get_bit(regs->data_in, gpio);
 
        return ret ? 1 : 0;
 }
@@ -140,9 +140,9 @@ static void tnetv107x_gpio_set(struct gpio_chip *chip,
        spin_lock_irqsave(&ctlr->lock, flags);
 
        if (value)
-               gpio_reg_set_bit(&regs->data_out, gpio);
+               gpio_reg_set_bit(regs->data_out, gpio);
        else
-               gpio_reg_clear_bit(&regs->data_out, gpio);
+               gpio_reg_clear_bit(regs->data_out, gpio);
 
        spin_unlock_irqrestore(&ctlr->lock, flags);
 }
index 730c49d..14a5048 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __MACH_CLKDEV_H
 #define __MACH_CLKDEV_H
 
+struct clk;
+
 static inline int __clk_get(struct clk *clk)
 {
        return 1;
index ffdf87b..8207954 100644 (file)
@@ -838,7 +838,7 @@ EXPORT_SYMBOL(ep93xx_i2s_release);
 static struct resource ep93xx_ac97_resources[] = {
        {
                .start  = EP93XX_AAC_PHYS_BASE,
-               .end    = EP93XX_AAC_PHYS_BASE + 0xb0 - 1,
+               .end    = EP93XX_AAC_PHYS_BASE + 0xac - 1,
                .flags  = IORESOURCE_MEM,
        },
        {
index f3dc76f..bec34b8 100644 (file)
@@ -427,6 +427,13 @@ void __init ep93xx_gpio_init(void)
 {
        int i;
 
+       /* Set Ports C, D, E, G, and H for GPIO use */
+       ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_KEYS |
+                                EP93XX_SYSCON_DEVCFG_GONK |
+                                EP93XX_SYSCON_DEVCFG_EONIDE |
+                                EP93XX_SYSCON_DEVCFG_GONIDE |
+                                EP93XX_SYSCON_DEVCFG_HONIDE);
+
        for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++)
                gpiochip_add(&ep93xx_gpio_banks[i].chip);
 }
index 3c9e0c4..30b971d 100644 (file)
@@ -17,8 +17,8 @@
        /* For NetWinder debugging */
                .macro  addruart, rp, rv
                mov     \rp, #0x000003f8
-               orr     \rv, \rp, #0x7c000000   @ physical
-               orr     \rp, \rp, #0xff000000   @ virtual
+               orr     \rv, \rp, #0xff000000   @ virtual
+               orr     \rp, \rp, #0x7c000000   @ physical
                .endm
 
 #define UART_SHIFT     0
index aa76cfd..8382e79 100644 (file)
@@ -180,7 +180,7 @@ static const uint32_t mx25pdk_keymap[] = {
        KEY(3, 3, KEY_POWER),
 };
 
-static const struct matrix_keymap_data mx25pdk_keymap_data __initdata = {
+static const struct matrix_keymap_data mx25pdk_keymap_data __initconst = {
        .keymap         = mx25pdk_keymap,
        .keymap_size    = ARRAY_SIZE(mx25pdk_keymap),
 };
index 4dc68d6..9fd8942 100644 (file)
@@ -432,7 +432,7 @@ static struct clocksource clocksource_ixp4xx = {
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-unsigned long ixp4xx_timer_freq = FREQ;
+unsigned long ixp4xx_timer_freq = IXP4XX_TIMER_FREQ;
 EXPORT_SYMBOL(ixp4xx_timer_freq);
 static void __init ixp4xx_clocksource_init(void)
 {
@@ -496,7 +496,7 @@ static struct clock_event_device clockevent_ixp4xx = {
 
 static void __init ixp4xx_clockevent_init(void)
 {
-       clockevent_ixp4xx.mult = div_sc(FREQ, NSEC_PER_SEC,
+       clockevent_ixp4xx.mult = div_sc(IXP4XX_TIMER_FREQ, NSEC_PER_SEC,
                                        clockevent_ixp4xx.shift);
        clockevent_ixp4xx.max_delta_ns =
                clockevent_delta2ns(0xfffffffe, &clockevent_ixp4xx);
index 2c3f93c..c9e930f 100644 (file)
@@ -10,6 +10,7 @@
  * 66.66... MHz. We do a convulted calculation of CLOCK_TICK_RATE b/c the
  * timer register ignores the bottom 2 bits of the LATCH value.
  */
-#define FREQ 66666000
-#define CLOCK_TICK_RATE (((FREQ / HZ & ~IXP4XX_OST_RELOAD_MASK) + 1) * HZ)
+#define IXP4XX_TIMER_FREQ 66666000
+#define CLOCK_TICK_RATE \
+       (((IXP4XX_TIMER_FREQ / HZ & ~IXP4XX_OST_RELOAD_MASK) + 1) * HZ)
 
index bfdbe4b..852f7c9 100644 (file)
@@ -265,6 +265,11 @@ void qmgr_release_queue(unsigned int queue)
               qmgr_queue_descs[queue], queue);
        qmgr_queue_descs[queue][0] = '\x0';
 #endif
+
+       while ((addr = qmgr_get_entry(queue)))
+               printk(KERN_ERR "qmgr: released queue %i not empty: 0x%08X\n",
+                      queue, addr);
+
        __raw_writel(0, &qmgr_regs->sram[queue]);
 
        used_sram_bitmap[0] &= ~mask[0];
@@ -275,10 +280,6 @@ void qmgr_release_queue(unsigned int queue)
        spin_unlock_irq(&qmgr_lock);
 
        module_put(THIS_MODULE);
-
-       while ((addr = qmgr_get_entry(queue)))
-               printk(KERN_ERR "qmgr: released queue %i not empty: 0x%08X\n",
-                      queue, addr);
 }
 
 static int qmgr_init(void)
index b1a362e..ca72a05 100644 (file)
@@ -304,7 +304,7 @@ static int name##_set_rate(struct clk *clk, unsigned long rate)             \
        reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr);         \
        reg &= ~BM_CLKCTRL_##dr##_DIV;                                  \
        reg |= div << BP_CLKCTRL_##dr##_DIV;                            \
-       if (reg | (1 << clk->enable_shift)) {                           \
+       if (reg & (1 << clk->enable_shift)) {                           \
                pr_err("%s: clock is gated\n", __func__);               \
                return -EINVAL;                                         \
        }                                                               \
@@ -347,7 +347,7 @@ static int name##_set_parent(struct clk *clk, struct clk *parent)   \
 {                                                                      \
        if (parent != clk->parent) {                                    \
                __raw_writel(BM_CLKCTRL_CLKSEQ_BYPASS_##bit,            \
-                        HW_CLKCTRL_CLKSEQ_TOG);                        \
+                        CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ_TOG);    \
                clk->parent = parent;                                   \
        }                                                               \
                                                                        \
index 56312c0..fd1c4c5 100644 (file)
@@ -355,12 +355,12 @@ static int name##_set_rate(struct clk *clk, unsigned long rate)           \
        } else {                                                        \
                reg &= ~BM_CLKCTRL_##dr##_DIV;                          \
                reg |= div << BP_CLKCTRL_##dr##_DIV;                    \
-               if (reg | (1 << clk->enable_shift)) {                   \
+               if (reg & (1 << clk->enable_shift)) {                   \
                        pr_err("%s: clock is gated\n", __func__);       \
                        return -EINVAL;                                 \
                }                                                       \
        }                                                               \
-       __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU);          \
+       __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr);         \
                                                                        \
        for (i = 10000; i; i--)                                         \
                if (!(__raw_readl(CLKCTRL_BASE_ADDR +                   \
@@ -483,7 +483,7 @@ static int name##_set_parent(struct clk *clk, struct clk *parent)   \
 {                                                                      \
        if (parent != clk->parent) {                                    \
                __raw_writel(BM_CLKCTRL_CLKSEQ_BYPASS_##bit,            \
-                        HW_CLKCTRL_CLKSEQ_TOG);                        \
+                        CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ_TOG);    \
                clk->parent = parent;                                   \
        }                                                               \
                                                                        \
@@ -609,7 +609,6 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("duart", NULL, uart_clk)
        _REGISTER_CLOCK("imx28-fec.0", NULL, fec_clk)
        _REGISTER_CLOCK("imx28-fec.1", NULL, fec_clk)
-       _REGISTER_CLOCK("fec.0", NULL, fec_clk)
        _REGISTER_CLOCK("rtc", NULL, rtc_clk)
        _REGISTER_CLOCK("pll2", NULL, pll2_clk)
        _REGISTER_CLOCK(NULL, "hclk", hbus_clk)
index e7d2269..a7093c8 100644 (file)
@@ -57,7 +57,6 @@ static void __clk_disable(struct clk *clk)
                if (clk->disable)
                        clk->disable(clk);
                __clk_disable(clk->parent);
-               __clk_disable(clk->secondary);
        }
 }
 
@@ -68,7 +67,6 @@ static int __clk_enable(struct clk *clk)
 
        if (clk->usecount++ == 0) {
                __clk_enable(clk->parent);
-               __clk_enable(clk->secondary);
 
                if (clk->enable)
                        clk->enable(clk);
index d7ad7a6..cb0c0e8 100644 (file)
@@ -139,6 +139,8 @@ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc)
        struct mxs_gpio_port *port = (struct mxs_gpio_port *)get_irq_data(irq);
        u32 gpio_irq_no_base = port->virtual_irq_start;
 
+       desc->irq_data.chip->irq_ack(&desc->irq_data);
+
        irq_stat = __raw_readl(port->base + PINCTRL_IRQSTAT(port->id)) &
                        __raw_readl(port->base + PINCTRL_IRQEN(port->id));
 
index 041e276..592c9ab 100644 (file)
@@ -29,8 +29,6 @@ struct clk {
        int id;
        /* Source clock this clk depends on */
        struct clk *parent;
-       /* Secondary clock to enable/disable with this clock */
-       struct clk *secondary;
        /* Reference count of clock enable/disable */
        __s8 usecount;
        /* Register bit position for clock's enable/disable control. */
index c9be6d4..bfb4fb1 100644 (file)
 #include <mach/irqs.h>
 #include <asm/hardware/gic.h>
 
-/*
- * We use __glue to avoid errors with multiple definitions of
- * .globl omap_irq_flags as it's included from entry-armv.S but not
- * from entry-common.S.
- */
-#ifdef __glue
-               .pushsection .data
-               .globl  omap_irq_flags
-omap_irq_flags:
-               .word   0
-               .popsection
-#endif
-
                .macro  disable_fiq
                .endm
 
index 4770158..731dd33 100644 (file)
@@ -57,6 +57,7 @@ struct omap_irq_bank {
        unsigned long wake_enable;
 };
 
+u32 omap_irq_flags;
 static unsigned int irq_bank_count;
 static struct omap_irq_bank *irq_banks;
 
@@ -176,7 +177,6 @@ static struct irq_chip omap_irq_chip = {
 
 void __init omap_init_irq(void)
 {
-       extern unsigned int omap_irq_flags;
        int i, j;
 
 #if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
index c9088d8..4538093 100644 (file)
@@ -37,7 +37,7 @@ int omap_lcd_dma_running(void)
         * On OMAP1510, internal LCD controller will start the transfer
         * when it gets enabled, so assume DMA running if LCD enabled.
         */
-       if (cpu_is_omap1510())
+       if (cpu_is_omap15xx())
                if (omap_readw(OMAP_LCDC_CONTROL) & OMAP_LCDC_CTRL_LCD_EN)
                        return 1;
 
@@ -95,7 +95,7 @@ EXPORT_SYMBOL(omap_set_lcd_dma_single_transfer);
 
 void omap_set_lcd_dma_b1_rotation(int rotate)
 {
-       if (cpu_is_omap1510()) {
+       if (cpu_is_omap15xx()) {
                printk(KERN_ERR "DMA rotation is not supported in 1510 mode\n");
                BUG();
                return;
@@ -106,7 +106,7 @@ EXPORT_SYMBOL(omap_set_lcd_dma_b1_rotation);
 
 void omap_set_lcd_dma_b1_mirror(int mirror)
 {
-       if (cpu_is_omap1510()) {
+       if (cpu_is_omap15xx()) {
                printk(KERN_ERR "DMA mirror is not supported in 1510 mode\n");
                BUG();
        }
@@ -116,7 +116,7 @@ EXPORT_SYMBOL(omap_set_lcd_dma_b1_mirror);
 
 void omap_set_lcd_dma_b1_vxres(unsigned long vxres)
 {
-       if (cpu_is_omap1510()) {
+       if (cpu_is_omap15xx()) {
                printk(KERN_ERR "DMA virtual resulotion is not supported "
                                "in 1510 mode\n");
                BUG();
@@ -127,7 +127,7 @@ EXPORT_SYMBOL(omap_set_lcd_dma_b1_vxres);
 
 void omap_set_lcd_dma_b1_scale(unsigned int xscale, unsigned int yscale)
 {
-       if (cpu_is_omap1510()) {
+       if (cpu_is_omap15xx()) {
                printk(KERN_ERR "DMA scale is not supported in 1510 mode\n");
                BUG();
        }
@@ -177,7 +177,7 @@ static void set_b1_regs(void)
                        bottom = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);
                        /* 1510 DMA requires the bottom address to be 2 more
                         * than the actual last memory access location. */
-                       if (cpu_is_omap1510() &&
+                       if (cpu_is_omap15xx() &&
                                lcd_dma.data_type == OMAP_DMA_DATA_TYPE_S32)
                                        bottom += 2;
                        ei = PIXSTEP(0, 0, 1, 0);
@@ -241,7 +241,7 @@ static void set_b1_regs(void)
                return; /* Suppress warning about uninitialized vars */
        }
 
-       if (cpu_is_omap1510()) {
+       if (cpu_is_omap15xx()) {
                omap_writew(top >> 16, OMAP1510_DMA_LCD_TOP_F1_U);
                omap_writew(top, OMAP1510_DMA_LCD_TOP_F1_L);
                omap_writew(bottom >> 16, OMAP1510_DMA_LCD_BOT_F1_U);
@@ -343,7 +343,7 @@ void omap_free_lcd_dma(void)
                BUG();
                return;
        }
-       if (!cpu_is_omap1510())
+       if (!cpu_is_omap15xx())
                omap_writew(omap_readw(OMAP1610_DMA_LCD_CCR) & ~1,
                            OMAP1610_DMA_LCD_CCR);
        lcd_dma.reserved = 0;
@@ -360,7 +360,7 @@ void omap_enable_lcd_dma(void)
         * connected. Otherwise the OMAP internal controller will
         * start the transfer when it gets enabled.
         */
-       if (cpu_is_omap1510() || !lcd_dma.ext_ctrl)
+       if (cpu_is_omap15xx() || !lcd_dma.ext_ctrl)
                return;
 
        w = omap_readw(OMAP1610_DMA_LCD_CTRL);
@@ -378,14 +378,14 @@ EXPORT_SYMBOL(omap_enable_lcd_dma);
 void omap_setup_lcd_dma(void)
 {
        BUG_ON(lcd_dma.active);
-       if (!cpu_is_omap1510()) {
+       if (!cpu_is_omap15xx()) {
                /* Set some reasonable defaults */
                omap_writew(0x5440, OMAP1610_DMA_LCD_CCR);
                omap_writew(0x9102, OMAP1610_DMA_LCD_CSDP);
                omap_writew(0x0004, OMAP1610_DMA_LCD_LCH_CTRL);
        }
        set_b1_regs();
-       if (!cpu_is_omap1510()) {
+       if (!cpu_is_omap15xx()) {
                u16 w;
 
                w = omap_readw(OMAP1610_DMA_LCD_CCR);
@@ -407,7 +407,7 @@ void omap_stop_lcd_dma(void)
        u16 w;
 
        lcd_dma.active = 0;
-       if (cpu_is_omap1510() || !lcd_dma.ext_ctrl)
+       if (cpu_is_omap15xx() || !lcd_dma.ext_ctrl)
                return;
 
        w = omap_readw(OMAP1610_DMA_LCD_CCR);
index f83fc33..6885d2f 100644 (file)
@@ -44,7 +44,6 @@
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
 #include <linux/io.h>
-#include <linux/sched.h>
 
 #include <asm/system.h>
 #include <mach/hardware.h>
index e906e05..9a2a31e 100644 (file)
@@ -115,9 +115,6 @@ static struct omap2_hsmmc_info mmc[] = {
 
 static int devkit8000_panel_enable_lcd(struct omap_dss_device *dssdev)
 {
-       twl_i2c_write_u8(TWL4030_MODULE_GPIO, 0x80, REG_GPIODATADIR1);
-       twl_i2c_write_u8(TWL4030_MODULE_LED, 0x0, 0x0);
-
        if (gpio_is_valid(dssdev->reset_gpio))
                gpio_set_value_cansleep(dssdev->reset_gpio, 1);
        return 0;
@@ -247,6 +244,8 @@ static struct gpio_led gpio_leds[];
 static int devkit8000_twl_gpio_setup(struct device *dev,
                unsigned gpio, unsigned ngpio)
 {
+       int ret;
+
        omap_mux_init_gpio(29, OMAP_PIN_INPUT);
        /* gpio + 0 is "mmc0_cd" (input/IRQ) */
        mmc[0].gpio_cd = gpio + 0;
@@ -255,17 +254,23 @@ static int devkit8000_twl_gpio_setup(struct device *dev,
        /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
        gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
 
-        /* gpio + 1 is "LCD_PWREN" (out, active high) */
-       devkit8000_lcd_device.reset_gpio = gpio + 1;
-       gpio_request(devkit8000_lcd_device.reset_gpio, "LCD_PWREN");
-       /* Disable until needed */
-       gpio_direction_output(devkit8000_lcd_device.reset_gpio, 0);
+       /* TWL4030_GPIO_MAX + 0 is "LCD_PWREN" (out, active high) */
+       devkit8000_lcd_device.reset_gpio = gpio + TWL4030_GPIO_MAX + 0;
+       ret = gpio_request_one(devkit8000_lcd_device.reset_gpio,
+                       GPIOF_DIR_OUT | GPIOF_INIT_LOW, "LCD_PWREN");
+       if (ret < 0) {
+               devkit8000_lcd_device.reset_gpio = -EINVAL;
+               printk(KERN_ERR "Failed to request GPIO for LCD_PWRN\n");
+       }
 
        /* gpio + 7 is "DVI_PD" (out, active low) */
        devkit8000_dvi_device.reset_gpio = gpio + 7;
-       gpio_request(devkit8000_dvi_device.reset_gpio, "DVI PowerDown");
-       /* Disable until needed */
-       gpio_direction_output(devkit8000_dvi_device.reset_gpio, 0);
+       ret = gpio_request_one(devkit8000_dvi_device.reset_gpio,
+                       GPIOF_DIR_OUT | GPIOF_INIT_LOW, "DVI PowerDown");
+       if (ret < 0) {
+               devkit8000_dvi_device.reset_gpio = -EINVAL;
+               printk(KERN_ERR "Failed to request GPIO for DVI PowerDown\n");
+       }
 
        return 0;
 }
index e001a04..e944025 100644 (file)
@@ -409,8 +409,6 @@ static void __init omap4_panda_init(void)
        platform_add_devices(panda_devices, ARRAY_SIZE(panda_devices));
        omap_serial_init();
        omap4_twl6030_hsmmc_init(mmc);
-       /* OMAP4 Panda uses internal transceiver so register nop transceiver */
-       usb_nop_xceiv_register();
        omap4_ehci_init();
        usb_musb_init(&musb_board_data);
 }
index cb77be7..39a71bb 100644 (file)
@@ -40,9 +40,6 @@ static struct regulator_consumer_supply rm680_vemmc_consumers[] = {
 static struct regulator_init_data rm680_vemmc = {
        .constraints =  {
                .name                   = "rm680_vemmc",
-               .min_uV                 = 2900000,
-               .max_uV                 = 2900000,
-               .apply_uV               = 1,
                .valid_modes_mask       = REGULATOR_MODE_NORMAL
                                        | REGULATOR_MODE_STANDBY,
                .valid_ops_mask         = REGULATOR_CHANGE_STATUS
index 337392c..acb7ae5 100644 (file)
@@ -77,7 +77,7 @@ static int _dpll_test_fint(struct clk *clk, u8 n)
        dd = clk->dpll_data;
 
        /* DPLL divider must result in a valid jitter correction val */
-       fint = clk->parent->rate / (n + 1);
+       fint = clk->parent->rate / n;
        if (fint < DPLL_FINT_BAND1_MIN) {
 
                pr_debug("rejecting n=%d due to Fint failure, "
index d2f15f5..34922b2 100644 (file)
@@ -264,7 +264,7 @@ static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused)
        if (IS_ERR(od)) {
                pr_err("%s: Cant build omap_device for %s:%s.\n",
                        __func__, name, oh->name);
-               return IS_ERR(od);
+               return PTR_ERR(od);
        }
 
        mem = platform_get_resource(&od->pdev, IORESOURCE_MEM, 0);
index befa321..81985a6 100644 (file)
  */
 
 #ifdef MULTI_OMAP2
-
-/*
- * We use __glue to avoid errors with multiple definitions of
- * .globl omap_irq_base as it's included from entry-armv.S but not
- * from entry-common.S.
- */
-#ifdef __glue
-               .pushsection .data
-               .globl  omap_irq_base
-omap_irq_base:
-               .word   0
-               .popsection
-#endif
-
                /*
                 * Configure the interrupt base on the first interrupt.
                 * See also omap_irq_base_init for setting omap_irq_base.
index e66687b..c203204 100644 (file)
@@ -314,14 +314,13 @@ static int _set_hwmod_postsetup_state(struct omap_hwmod *oh, void *data)
        return omap_hwmod_set_postsetup_state(oh, *(u8 *)data);
 }
 
+void __iomem *omap_irq_base;
+
 /*
  * Initialize asm_irq_base for entry-macro.S
  */
 static inline void omap_irq_base_init(void)
 {
-       extern void __iomem *omap_irq_base;
-
-#ifdef MULTI_OMAP2
        if (cpu_is_omap24xx())
                omap_irq_base = OMAP2_L4_IO_ADDRESS(OMAP24XX_IC_BASE);
        else if (cpu_is_omap34xx())
@@ -330,7 +329,6 @@ static inline void omap_irq_base_init(void)
                omap_irq_base = OMAP2_L4_IO_ADDRESS(OMAP44XX_GIC_CPU_BASE);
        else
                pr_err("Could not initialize omap_irq_base\n");
-#endif
 }
 
 void __init omap2_init_common_infrastructure(void)
index 394413d..24b8850 100644 (file)
@@ -193,10 +193,12 @@ static void omap2_mbox_disable_irq(struct omap_mbox *mbox,
                omap_mbox_type_t irq)
 {
        struct omap_mbox2_priv *p = mbox->priv;
-       u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
-       l = mbox_read_reg(p->irqdisable);
-       l &= ~bit;
-       mbox_write_reg(l, p->irqdisable);
+       u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
+
+       if (!cpu_is_omap44xx())
+               bit = mbox_read_reg(p->irqdisable) & ~bit;
+
+       mbox_write_reg(bit, p->irqdisable);
 }
 
 static void omap2_mbox_ack_irq(struct omap_mbox *mbox,
@@ -334,7 +336,7 @@ static struct omap_mbox mbox_iva_info = {
        .priv   = &omap2_mbox_iva_priv,
 };
 
-struct omap_mbox *omap2_mboxes[] = { &mbox_iva_info, &mbox_dsp_info, NULL };
+struct omap_mbox *omap2_mboxes[] = { &mbox_dsp_info, &mbox_iva_info, NULL };
 #endif
 
 #if defined(CONFIG_ARCH_OMAP4)
index df8d2f2..6c84659 100644 (file)
@@ -160,7 +160,7 @@ static int __init _omap_mux_get_by_name(struct omap_mux_partition *partition,
        struct omap_mux *mux = NULL;
        struct omap_mux_entry *e;
        const char *mode_name;
-       int found = 0, found_mode, mode0_len = 0;
+       int found = 0, found_mode = 0, mode0_len = 0;
        struct list_head *muxmodes = &partition->muxmodes;
 
        mode_name = strchr(muxname, '.');
@@ -605,7 +605,7 @@ static void __init omap_mux_dbg_create_entry(
        list_for_each_entry(e, &partition->muxmodes, node) {
                struct omap_mux *m = &e->mux;
 
-               (void)debugfs_create_file(m->muxnames[0], S_IWUGO, mux_dbg_dir,
+               (void)debugfs_create_file(m->muxnames[0], S_IWUSR, mux_dbg_dir,
                                          m, &omap_mux_dbg_signal_fops);
        }
 }
@@ -1000,6 +1000,7 @@ int __init omap_mux_init(const char *name, u32 flags,
        if (!partition->base) {
                pr_err("%s: Could not ioremap mux partition at 0x%08x\n",
                        __func__, partition->phys);
+               kfree(partition);
                return -ENODEV;
        }
 
index 125f565..a5a83b3 100644 (file)
@@ -637,14 +637,14 @@ static int __init pm_dbg_init(void)
 
                }
 
-       (void) debugfs_create_file("enable_off_mode", S_IRUGO | S_IWUGO, d,
+       (void) debugfs_create_file("enable_off_mode", S_IRUGO | S_IWUSR, d,
                                   &enable_off_mode, &pm_dbg_option_fops);
-       (void) debugfs_create_file("sleep_while_idle", S_IRUGO | S_IWUGO, d,
+       (void) debugfs_create_file("sleep_while_idle", S_IRUGO | S_IWUSR, d,
                                   &sleep_while_idle, &pm_dbg_option_fops);
-       (void) debugfs_create_file("wakeup_timer_seconds", S_IRUGO | S_IWUGO, d,
+       (void) debugfs_create_file("wakeup_timer_seconds", S_IRUGO | S_IWUSR, d,
                                   &wakeup_timer_seconds, &pm_dbg_option_fops);
        (void) debugfs_create_file("wakeup_timer_milliseconds",
-                       S_IRUGO | S_IWUGO, d, &wakeup_timer_milliseconds,
+                       S_IRUGO | S_IWUSR, d, &wakeup_timer_milliseconds,
                        &pm_dbg_option_fops);
        pm_dbg_init_done = 1;
 
index 9e5dc8e..97feb3a 100644 (file)
@@ -134,7 +134,7 @@ static void omap2_enter_full_retention(void)
 
        /* Block console output in case it is on one of the OMAP UARTs */
        if (!is_suspending())
-               if (try_acquire_console_sem())
+               if (!console_trylock())
                        goto no_sleep;
 
        omap_uart_prepare_idle(0);
@@ -151,7 +151,7 @@ static void omap2_enter_full_retention(void)
        omap_uart_resume_idle(0);
 
        if (!is_suspending())
-               release_console_sem();
+               console_unlock();
 
 no_sleep:
        if (omap2_pm_debug) {
index 8cbbead..2f864e4 100644 (file)
@@ -168,9 +168,10 @@ static void omap3_core_restore_context(void)
  * once during boot sequence, but this works as we are not using secure
  * services.
  */
-static void omap3_save_secure_ram_context(u32 target_mpu_state)
+static void omap3_save_secure_ram_context(void)
 {
        u32 ret;
+       int mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
 
        if (omap_type() != OMAP2_DEVICE_TYPE_GP) {
                /*
@@ -181,7 +182,7 @@ static void omap3_save_secure_ram_context(u32 target_mpu_state)
                pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
                ret = _omap_save_secure_sram((u32 *)
                                __pa(omap3_secure_ram_storage));
-               pwrdm_set_next_pwrst(mpu_pwrdm, target_mpu_state);
+               pwrdm_set_next_pwrst(mpu_pwrdm, mpu_next_state);
                /* Following is for error tracking, it should not happen */
                if (ret) {
                        printk(KERN_ERR "save_secure_sram() returns %08x\n",
@@ -398,7 +399,7 @@ void omap_sram_idle(void)
        if (!is_suspending())
                if (per_next_state < PWRDM_POWER_ON ||
                    core_next_state < PWRDM_POWER_ON)
-                       if (try_acquire_console_sem())
+                       if (!console_trylock())
                                goto console_still_active;
 
        /* PER */
@@ -481,7 +482,7 @@ void omap_sram_idle(void)
        }
 
        if (!is_suspending())
-               release_console_sem();
+               console_unlock();
 
 console_still_active:
        /* Disable IO-PAD and IO-CHAIN wakeup */
@@ -1094,7 +1095,7 @@ static int __init omap3_pm_init(void)
                local_fiq_disable();
 
                omap_dma_global_context_save();
-               omap3_save_secure_ram_context(PWRDM_POWER_ON);
+               omap3_save_secure_ram_context();
                omap_dma_global_context_restore();
 
                local_irq_enable();
index 729a644..3300ff6 100644 (file)
@@ -38,8 +38,8 @@
 #define OMAP4430_PRCM_MPU_CPU1_INST            0x0800
 
 /* PRCM_MPU clockdomain register offsets (from instance start) */
-#define OMAP4430_PRCM_MPU_CPU0_MPU_CDOFFS      0x0000
-#define OMAP4430_PRCM_MPU_CPU1_MPU_CDOFFS      0x0000
+#define OMAP4430_PRCM_MPU_CPU0_MPU_CDOFFS      0x0018
+#define OMAP4430_PRCM_MPU_CPU1_MPU_CDOFFS      0x0018
 
 
 /*
index 302da74..32e91a9 100644 (file)
@@ -812,7 +812,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
 
        oh->dev_attr = uart;
 
-       acquire_console_sem(); /* in case the earlycon is on the UART */
+       console_lock(); /* in case the earlycon is on the UART */
 
        /*
         * Because of early UART probing, UART did not get idled
@@ -838,7 +838,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
        omap_uart_block_sleep(uart);
        uart->timeout = DEFAULT_TIMEOUT;
 
-       release_console_sem();
+       console_unlock();
 
        if ((cpu_is_omap34xx() && uart->padconf) ||
            (uart->wk_en && uart->wk_mask)) {
index 77ecebf..1a777e3 100644 (file)
@@ -282,6 +282,7 @@ error:
                dev_err(&sr_info->pdev->dev, "%s: ERROR in registering"
                        "interrupt handler. Smartreflex will"
                        "not function as desired\n", __func__);
+               kfree(name);
                kfree(sr_info);
                return ret;
 }
@@ -780,8 +781,7 @@ static int omap_sr_autocomp_show(void *data, u64 *val)
        struct omap_sr *sr_info = (struct omap_sr *) data;
 
        if (!sr_info) {
-               pr_warning("%s: omap_sr struct for sr_%s not found\n",
-                       __func__, sr_info->voltdm->name);
+               pr_warning("%s: omap_sr struct not found\n", __func__);
                return -EINVAL;
        }
 
@@ -795,8 +795,7 @@ static int omap_sr_autocomp_store(void *data, u64 val)
        struct omap_sr *sr_info = (struct omap_sr *) data;
 
        if (!sr_info) {
-               pr_warning("%s: omap_sr struct for sr_%s not found\n",
-                       __func__, sr_info->voltdm->name);
+               pr_warning("%s: omap_sr struct not found\n", __func__);
                return -EINVAL;
        }
 
@@ -834,7 +833,8 @@ static int __init omap_sr_probe(struct platform_device *pdev)
 
        if (!pdata) {
                dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err_free_devinfo;
        }
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -880,7 +880,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
                ret = sr_late_init(sr_info);
                if (ret) {
                        pr_warning("%s: Error in SR late init\n", __func__);
-                       return ret;
+                       goto err_release_region;
                }
        }
 
@@ -891,17 +891,20 @@ static int __init omap_sr_probe(struct platform_device *pdev)
         * not try to create rest of the debugfs entries.
         */
        vdd_dbg_dir = omap_voltage_get_dbgdir(sr_info->voltdm);
-       if (!vdd_dbg_dir)
-               return -EINVAL;
+       if (!vdd_dbg_dir) {
+               ret = -EINVAL;
+               goto err_release_region;
+       }
 
        dbg_dir = debugfs_create_dir("smartreflex", vdd_dbg_dir);
        if (IS_ERR(dbg_dir)) {
                dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n",
                        __func__);
-               return PTR_ERR(dbg_dir);
+               ret = PTR_ERR(dbg_dir);
+               goto err_release_region;
        }
 
-       (void) debugfs_create_file("autocomp", S_IRUGO | S_IWUGO, dbg_dir,
+       (void) debugfs_create_file("autocomp", S_IRUGO | S_IWUSR, dbg_dir,
                                (void *)sr_info, &pm_sr_fops);
        (void) debugfs_create_x32("errweight", S_IRUGO, dbg_dir,
                        &sr_info->err_weight);
@@ -914,7 +917,8 @@ static int __init omap_sr_probe(struct platform_device *pdev)
        if (IS_ERR(nvalue_dir)) {
                dev_err(&pdev->dev, "%s: Unable to create debugfs directory"
                        "for n-values\n", __func__);
-               return PTR_ERR(nvalue_dir);
+               ret = PTR_ERR(nvalue_dir);
+               goto err_release_region;
        }
 
        omap_voltage_get_volttable(sr_info->voltdm, &volt_data);
@@ -923,24 +927,16 @@ static int __init omap_sr_probe(struct platform_device *pdev)
                        " corresponding vdd vdd_%s. Cannot create debugfs"
                        "entries for n-values\n",
                        __func__, sr_info->voltdm->name);
-               return -ENODATA;
+               ret = -ENODATA;
+               goto err_release_region;
        }
 
        for (i = 0; i < sr_info->nvalue_count; i++) {
-               char *name;
-               char volt_name[32];
-
-               name = kzalloc(NVALUE_NAME_LEN + 1, GFP_KERNEL);
-               if (!name) {
-                       dev_err(&pdev->dev, "%s: Unable to allocate memory"
-                               " for n-value directory name\n",  __func__);
-                       return -ENOMEM;
-               }
+               char name[NVALUE_NAME_LEN + 1];
 
-               strcpy(name, "volt_");
-               sprintf(volt_name, "%d", volt_data[i].volt_nominal);
-               strcat(name, volt_name);
-               (void) debugfs_create_x32(name, S_IRUGO | S_IWUGO, nvalue_dir,
+               snprintf(name, sizeof(name), "volt_%d",
+                        volt_data[i].volt_nominal);
+               (void) debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir,
                                &(sr_info->nvalue_table[i].nvalue));
        }
 
@@ -966,7 +962,7 @@ static int __devexit omap_sr_remove(struct platform_device *pdev)
        }
 
        sr_info = _sr_lookup(pdata->voltdm);
-       if (!sr_info) {
+       if (IS_ERR(sr_info)) {
                dev_warn(&pdev->dev, "%s: omap_sr struct not found\n",
                        __func__);
                return -EINVAL;
index 7b7c268..0fc550e 100644 (file)
@@ -39,6 +39,7 @@
 #include <asm/mach/time.h>
 #include <plat/dmtimer.h>
 #include <asm/localtimer.h>
+#include <asm/sched_clock.h>
 
 #include "timer-gp.h"
 
@@ -190,6 +191,7 @@ static void __init omap2_gp_clocksource_init(void)
 /*
  * clocksource
  */
+static DEFINE_CLOCK_DATA(cd);
 static struct omap_dm_timer *gpt_clocksource;
 static cycle_t clocksource_read_cycles(struct clocksource *cs)
 {
@@ -204,6 +206,15 @@ static struct clocksource clocksource_gpt = {
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
+static void notrace dmtimer_update_sched_clock(void)
+{
+       u32 cyc;
+
+       cyc = omap_dm_timer_read_counter(gpt_clocksource);
+
+       update_sched_clock(&cd, cyc, (u32)~0);
+}
+
 /* Setup free-running counter for clocksource */
 static void __init omap2_gp_clocksource_init(void)
 {
@@ -224,6 +235,8 @@ static void __init omap2_gp_clocksource_init(void)
 
        omap_dm_timer_set_load_start(gpt, 1, 0);
 
+       init_sched_clock(&cd, dmtimer_update_sched_clock, 32, tick_rate);
+
        if (clocksource_register_hz(&clocksource_gpt, tick_rate))
                printk(err2, clocksource_gpt.name);
 }
index ed6079c..12be525 100644 (file)
@@ -471,6 +471,7 @@ static void __init vdd_debugfs_init(struct omap_vdd_info *vdd)
        strcat(name, vdd->voltdm.name);
 
        vdd->debug_dir = debugfs_create_dir(name, voltage_dir);
+       kfree(name);
        if (IS_ERR(vdd->debug_dir)) {
                pr_warning("%s: Unable to create debugfs directory for"
                        " vdd_%s\n", __func__, vdd->voltdm.name);
index 6b2c800..28f667e 100644 (file)
@@ -50,7 +50,7 @@ static void __init colibri_mmc_init(void)
                        GPIO0_COLIBRI_PXA270_SD_DETECT;
        if (machine_is_colibri300())    /* PXA300 Colibri */
                colibri_mci_platform_data.gpio_card_detect =
-                       GPIO39_COLIBRI_PXA300_SD_DETECT;
+                       GPIO13_COLIBRI_PXA300_SD_DETECT;
        else                            /* PXA320 Colibri */
                colibri_mci_platform_data.gpio_card_detect =
                        GPIO28_COLIBRI_PXA320_SD_DETECT;
index fddb16d..66dd81c 100644 (file)
@@ -41,7 +41,7 @@ static mfp_cfg_t colibri_pxa300_evalboard_pin_config[] __initdata = {
        GPIO4_MMC1_DAT1,
        GPIO5_MMC1_DAT2,
        GPIO6_MMC1_DAT3,
-       GPIO39_GPIO,    /* SD detect */
+       GPIO13_GPIO,    /* GPIO13_COLIBRI_PXA300_SD_DETECT */
 
        /* UHC */
        GPIO0_2_USBH_PEN,
index 388a96f..cb4236e 100644 (file)
@@ -60,7 +60,7 @@ static inline void colibri_pxa3xx_init_nand(void) {}
 #define GPIO113_COLIBRI_PXA270_TS_IRQ  113
 
 /* GPIO definitions for Colibri PXA300/310 */
-#define GPIO39_COLIBRI_PXA300_SD_DETECT        39
+#define GPIO13_COLIBRI_PXA300_SD_DETECT        13
 
 /* GPIO definitions for Colibri PXA320 */
 #define GPIO28_COLIBRI_PXA320_SD_DETECT        28
index 405b92a..35572c4 100644 (file)
@@ -323,7 +323,7 @@ static struct platform_pwm_backlight_data palm27x_backlight_data = {
        .pwm_id         = 0,
        .max_brightness = 0xfe,
        .dft_brightness = 0x7e,
-       .pwm_period_ns  = 3500,
+       .pwm_period_ns  = 3500 * 1024,
        .init           = palm27x_backlight_init,
        .notify         = palm27x_backlight_notify,
        .exit           = palm27x_backlight_exit,
index 978e1b2..1807c9a 100644 (file)
@@ -33,7 +33,7 @@ int pxa_pm_enter(suspend_state_t state)
 #endif
 
        /* skip registers saving for standby */
-       if (state != PM_SUSPEND_STANDBY) {
+       if (state != PM_SUSPEND_STANDBY && pxa_cpu_pm_fns->save) {
                pxa_cpu_pm_fns->save(sleep_save);
                /* before sleeping, calculate and save a checksum */
                for (i = 0; i < pxa_cpu_pm_fns->save_count - 1; i++)
@@ -44,7 +44,7 @@ int pxa_pm_enter(suspend_state_t state)
        pxa_cpu_pm_fns->enter(state);
        cpu_init();
 
-       if (state != PM_SUSPEND_STANDBY) {
+       if (state != PM_SUSPEND_STANDBY && pxa_cpu_pm_fns->restore) {
                /* after sleeping, validate the checksum */
                for (i = 0; i < pxa_cpu_pm_fns->save_count - 1; i++)
                        checksum += sleep_save[i];
index fbc5b77..b166b1d 100644 (file)
@@ -347,6 +347,7 @@ static struct platform_device *pxa25x_devices[] __initdata = {
        &pxa25x_device_assp,
        &pxa25x_device_pwm0,
        &pxa25x_device_pwm1,
+       &pxa_device_asoc_platform,
 };
 
 static struct sys_device pxa25x_sysdev[] = {
index c31e601..b9b1e5c 100644 (file)
@@ -81,8 +81,6 @@ static int tosa_bt_probe(struct platform_device *dev)
                goto err_rfk_alloc;
        }
 
-       rfkill_set_led_trigger_name(rfk, "tosa-bt");
-
        rc = rfkill_register(rfk);
        if (rc)
                goto err_rfkill;
index af152e7..f2582ec 100644 (file)
@@ -875,6 +875,11 @@ static struct platform_device sharpsl_rom_device = {
        .dev.platform_data = &sharpsl_rom_data,
 };
 
+static struct platform_device wm9712_device = {
+       .name   = "wm9712-codec",
+       .id     = -1,
+};
+
 static struct platform_device *devices[] __initdata = {
        &tosascoop_device,
        &tosascoop_jc_device,
@@ -885,6 +890,7 @@ static struct platform_device *devices[] __initdata = {
        &tosaled_device,
        &tosa_bt_device,
        &sharpsl_rom_device,
+       &wm9712_device,
 };
 
 static void tosa_poweroff(void)
index b4575ae..7ca138a 100644 (file)
@@ -2,52 +2,56 @@ menu "RealView platform type"
        depends on ARCH_REALVIEW
 
 config MACH_REALVIEW_EB
-       bool "Support RealView/EB platform"
+       bool "Support RealView(R) Emulation Baseboard"
        select ARM_GIC
        help
-         Include support for the ARM(R) RealView Emulation Baseboard platform.
+         Include support for the ARM(R) RealView(R) Emulation Baseboard
+         platform.
 
 config REALVIEW_EB_A9MP
-       bool "Support Multicore Cortex-A9"
+       bool "Support Multicore Cortex-A9 Tile"
        depends on MACH_REALVIEW_EB
        select CPU_V7
        help
-         Enable support for the Cortex-A9MPCore tile on the Realview platform.
+         Enable support for the Cortex-A9MPCore tile fitted to the
+         Realview(R) Emulation Baseboard platform.
 
 config REALVIEW_EB_ARM11MP
-       bool "Support ARM11MPCore tile"
+       bool "Support ARM11MPCore Tile"
        depends on MACH_REALVIEW_EB
        select CPU_V6
        select ARCH_HAS_BARRIERS if SMP
        help
-         Enable support for the ARM11MPCore tile on the Realview platform.
+         Enable support for the ARM11MPCore tile fitted to the Realview(R)
+         Emulation Baseboard platform.
 
 config REALVIEW_EB_ARM11MP_REVB
-       bool "Support ARM11MPCore RevB tile"
+       bool "Support ARM11MPCore RevB Tile"
        depends on REALVIEW_EB_ARM11MP
        help
-         Enable support for the ARM11MPCore RevB tile on the Realview
-         platform. Since there are device address differences, a
-         kernel built with this option enabled is not compatible with
-         other revisions of the ARM11MPCore tile.
+         Enable support for the ARM11MPCore Revision B tile on the
+         Realview(R) Emulation Baseboard platform. Since there are device
+         address differences, a kernel built with this option enabled is
+         not compatible with other revisions of the ARM11MPCore tile.
 
 config MACH_REALVIEW_PB11MP
-       bool "Support RealView/PB11MPCore platform"
+       bool "Support RealView(R) Platform Baseboard for ARM11MPCore"
        select CPU_V6
        select ARM_GIC
        select HAVE_PATA_PLATFORM
        select ARCH_HAS_BARRIERS if SMP
        help
-         Include support for the ARM(R) RealView MPCore Platform Baseboard.
-         PB11MPCore is a platform with an on-board ARM11MPCore and has
+         Include support for the ARM(R) RealView(R) Platform Baseboard for
+         the ARM11MPCore.  This platform has an on-board ARM11MPCore and has
          support for PCI-E and Compact Flash.
 
 config MACH_REALVIEW_PB1176
-       bool "Support RealView/PB1176 platform"
+       bool "Support RealView(R) Platform Baseboard for ARM1176JZF-S"
        select CPU_V6
        select ARM_GIC
        help
-         Include support for the ARM(R) RealView ARM1176 Platform Baseboard.
+         Include support for the ARM(R) RealView(R) Platform Baseboard for
+         ARM1176JZF-S.
 
 config REALVIEW_PB1176_SECURE_FLASH
        bool "Allow access to the secure flash memory block"
@@ -59,23 +63,24 @@ config REALVIEW_PB1176_SECURE_FLASH
          block (64MB @ 0x3c000000) is required.
 
 config MACH_REALVIEW_PBA8
-       bool "Support RealView/PB-A8 platform"
+       bool "Support RealView(R) Platform Baseboard for Cortex(tm)-A8 platform"
        select CPU_V7
        select ARM_GIC
        select HAVE_PATA_PLATFORM
        help
-         Include support for the ARM(R) RealView Cortex-A8 Platform Baseboard.
-         PB-A8 is a platform with an on-board Cortex-A8 and has support for
-         PCI-E and Compact Flash.
+         Include support for the ARM(R) RealView Platform Baseboard for
+         Cortex(tm)-A8.  This platform has an on-board Cortex-A8 and has
+         support for PCI-E and Compact Flash.
 
 config MACH_REALVIEW_PBX
-       bool "Support RealView/PBX platform"
+       bool "Support RealView(R) Platform Baseboard Explore"
        select ARM_GIC
        select HAVE_PATA_PLATFORM
        select ARCH_SPARSEMEM_ENABLE if CPU_V7 && !REALVIEW_HIGH_PHYS_OFFSET
        select ZONE_DMA if SPARSEMEM
        help
-         Include support for the ARM(R) RealView PBX platform.
+         Include support for the ARM(R) RealView(R) Platform Baseboard
+         Explore.
 
 config REALVIEW_HIGH_PHYS_OFFSET
        bool "High physical base address for the RealView platform"
index a22bf67..6959d13 100644 (file)
@@ -41,7 +41,7 @@ volatile int __cpuinitdata pen_release = -1;
  * observers, irrespective of whether they're taking part in coherency
  * or not.  This is necessary for the hotplug code to work reliably.
  */
-static void write_pen_release(int val)
+static void __cpuinit write_pen_release(int val)
 {
        pen_release = val;
        smp_wmb();
index a0cb258..50825a3 100644 (file)
@@ -99,6 +99,7 @@ config MACH_NEO1973_GTA02
        select POWER_SUPPLY
        select MACH_NEO1973
        select S3C2410_PWM
+       select S3C_DEV_USB_HOST
        help
           Say Y here if you are using the Openmoko GTA02 / Freerunner GSM Phone
 
index 953331d..3a56a22 100644 (file)
 #define GTA02v3_GPIO_nUSB_FLT  S3C2410_GPG(10) /* v3 + v4 only */
 #define GTA02v3_GPIO_nGSM_OC   S3C2410_GPG(11) /* v3 + v4 only */
 
-#define GTA02_GPIO_AMP_SHUT    S3C2440_GPJ1    /* v2 + v3 + v4 only */
-#define GTA02v1_GPIO_WLAN_GPIO10       S3C2440_GPJ2
-#define GTA02_GPIO_HP_IN       S3C2440_GPJ2    /* v2 + v3 + v4 only */
-#define GTA02_GPIO_INT0                S3C2440_GPJ3    /* v2 + v3 + v4 only */
-#define GTA02_GPIO_nGSM_EN     S3C2440_GPJ4
-#define GTA02_GPIO_3D_RESET    S3C2440_GPJ5
-#define GTA02_GPIO_nDL_GSM     S3C2440_GPJ6    /* v4 + v5 only */
-#define GTA02_GPIO_WLAN_GPIO0  S3C2440_GPJ7
-#define GTA02v1_GPIO_BAT_ID    S3C2440_GPJ8
-#define GTA02_GPIO_KEEPACT     S3C2440_GPJ8
-#define GTA02v1_GPIO_HP_IN     S3C2440_GPJ10
-#define GTA02_CHIP_PWD         S3C2440_GPJ11   /* v2 + v3 + v4 only */
-#define GTA02_GPIO_nWLAN_RESET S3C2440_GPJ12   /* v2 + v3 + v4 only */
+#define GTA02_GPIO_AMP_SHUT    S3C2410_GPJ(1)  /* v2 + v3 + v4 only */
+#define GTA02v1_GPIO_WLAN_GPIO10       S3C2410_GPJ(2)
+#define GTA02_GPIO_HP_IN       S3C2410_GPJ(2)  /* v2 + v3 + v4 only */
+#define GTA02_GPIO_INT0                S3C2410_GPJ(3)  /* v2 + v3 + v4 only */
+#define GTA02_GPIO_nGSM_EN     S3C2410_GPJ(4)
+#define GTA02_GPIO_3D_RESET    S3C2410_GPJ(5)
+#define GTA02_GPIO_nDL_GSM     S3C2410_GPJ(6)  /* v4 + v5 only */
+#define GTA02_GPIO_WLAN_GPIO0  S3C2410_GPJ(7)
+#define GTA02v1_GPIO_BAT_ID    S3C2410_GPJ(8)
+#define GTA02_GPIO_KEEPACT     S3C2410_GPJ(8)
+#define GTA02v1_GPIO_HP_IN     S3C2410_GPJ(10)
+#define GTA02_CHIP_PWD         S3C2410_GPJ(11) /* v2 + v3 + v4 only */
+#define GTA02_GPIO_nWLAN_RESET S3C2410_GPJ(12) /* v2 + v3 + v4 only */
 
 #define GTA02_IRQ_GSENSOR_1    IRQ_EINT0
 #define GTA02_IRQ_MODEM                IRQ_EINT1
index dd37820..fdfc4d5 100644 (file)
@@ -150,6 +150,12 @@ static struct clk init_clocks_off[] = {
                .parent         = &clk_p,
                .enable         = s3c64xx_pclk_ctrl,
                .ctrlbit        = S3C_CLKCON_PCLK_IIC,
+       }, {
+               .name           = "i2c",
+               .id             = 1,
+               .parent         = &clk_p,
+               .enable         = s3c64xx_pclk_ctrl,
+               .ctrlbit        = S3C6410_CLKCON_PCLK_I2C1,
        }, {
                .name           = "iis",
                .id             = 0,
index 135db1b..c35585c 100644 (file)
@@ -690,12 +690,12 @@ static int s3c64xx_dma_init1(int chno, enum dma_ch chbase,
 
        regptr = regs + PL080_Cx_BASE(0);
 
-       for (ch = 0; ch < 8; ch++, chno++, chptr++) {
-               printk(KERN_INFO "%s: registering DMA %d (%p)\n",
-                      __func__, chno, regptr);
+       for (ch = 0; ch < 8; ch++, chptr++) {
+               pr_debug("%s: registering DMA %d (%p)\n",
+                        __func__, chno + ch, regptr);
 
                chptr->bit = 1 << ch;
-               chptr->number = chno;
+               chptr->number = chno + ch;
                chptr->dmac = dmac;
                chptr->regs = regptr;
                regptr += PL080_Cx_STRIDE;
@@ -704,7 +704,8 @@ static int s3c64xx_dma_init1(int chno, enum dma_ch chbase,
        /* for the moment, permanently enable the controller */
        writel(PL080_CONFIG_ENABLE, regs + PL080_CONFIG);
 
-       printk(KERN_INFO "PL080: IRQ %d, at %p\n", irq, regs);
+       printk(KERN_INFO "PL080: IRQ %d, at %p, channels %d..%d\n",
+              irq, regs, chno, chno+8);
 
        return 0;
 
index fd99a82..92b0908 100644 (file)
@@ -72,7 +72,7 @@ static struct s3c_gpio_cfg gpio_4bit_cfg_eint0011 = {
        .get_pull       = s3c_gpio_getpull_updown,
 };
 
-int s3c64xx_gpio2int_gpm(struct gpio_chip *chip, unsigned pin)
+static int s3c64xx_gpio2int_gpm(struct gpio_chip *chip, unsigned pin)
 {
        return pin < 5 ? IRQ_EINT(23) + pin : -ENXIO;
 }
@@ -138,7 +138,7 @@ static struct s3c_gpio_chip gpio_4bit[] = {
        },
 };
 
-int s3c64xx_gpio2int_gpl(struct gpio_chip *chip, unsigned pin)
+static int s3c64xx_gpio2int_gpl(struct gpio_chip *chip, unsigned pin)
 {
        return pin >= 8 ? IRQ_EINT(16) + pin - 8 : -ENXIO;
 }
index e85192a..a80a316 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/delay.h>
 #include <linux/smsc911x.h>
 #include <linux/regulator/fixed.h>
+#include <linux/regulator/machine.h>
 
 #ifdef CONFIG_SMDK6410_WM1190_EV1
 #include <linux/mfd/wm8350/core.h>
@@ -351,7 +352,7 @@ static struct regulator_init_data smdk6410_vddpll = {
 /* VDD_UH_MMC, LDO5 on J5 */
 static struct regulator_init_data smdk6410_vdduh_mmc = {
        .constraints = {
-               .name = "PVDD_UH/PVDD_MMC",
+               .name = "PVDD_UH+PVDD_MMC",
                .always_on = 1,
        },
 };
@@ -417,7 +418,7 @@ static struct regulator_init_data smdk6410_vddaudio = {
 /* S3C64xx internal logic & PLL */
 static struct regulator_init_data wm8350_dcdc1_data = {
        .constraints = {
-               .name = "PVDD_INT/PVDD_PLL",
+               .name = "PVDD_INT+PVDD_PLL",
                .min_uV = 1200000,
                .max_uV = 1200000,
                .always_on = 1,
@@ -452,7 +453,7 @@ static struct regulator_consumer_supply wm8350_dcdc4_consumers[] = {
 
 static struct regulator_init_data wm8350_dcdc4_data = {
        .constraints = {
-               .name = "PVDD_HI/PVDD_EXT/PVDD_SYS/PVCCM2MTV",
+               .name = "PVDD_HI+PVDD_EXT+PVDD_SYS+PVCCM2MTV",
                .min_uV = 3000000,
                .max_uV = 3000000,
                .always_on = 1,
@@ -464,7 +465,7 @@ static struct regulator_init_data wm8350_dcdc4_data = {
 /* OTGi/1190-EV1 HPVDD & AVDD */
 static struct regulator_init_data wm8350_ldo4_data = {
        .constraints = {
-               .name = "PVDD_OTGI/HPVDD/AVDD",
+               .name = "PVDD_OTGI+HPVDD+AVDD",
                .min_uV = 1200000,
                .max_uV = 1200000,
                .apply_uV = 1,
@@ -552,7 +553,7 @@ static struct wm831x_backlight_pdata wm1192_backlight_pdata = {
 
 static struct regulator_init_data wm1192_dcdc3 = {
        .constraints = {
-               .name = "PVDD_MEM/PVDD_GPS",
+               .name = "PVDD_MEM+PVDD_GPS",
                .always_on = 1,
        },
 };
@@ -563,7 +564,7 @@ static struct regulator_consumer_supply wm1192_ldo1_consumers[] = {
 
 static struct regulator_init_data wm1192_ldo1 = {
        .constraints = {
-               .name = "PVDD_LCD/PVDD_EXT",
+               .name = "PVDD_LCD+PVDD_EXT",
                .always_on = 1,
        },
        .consumer_supplies = wm1192_ldo1_consumers,
index f8ed0d2..1d4d0ee 100644 (file)
@@ -17,7 +17,7 @@
 void samsung_keypad_cfg_gpio(unsigned int rows, unsigned int cols)
 {
        /* Set all the necessary GPK pins to special-function 3: KP_ROW[x] */
-       s3c_gpio_cfgrange_nopull(S3C64XX_GPK(8), 8 + rows, S3C_GPIO_SFN(3));
+       s3c_gpio_cfgrange_nopull(S3C64XX_GPK(8), rows, S3C_GPIO_SFN(3));
 
        /* Set all the necessary GPL pins to special-function 3: KP_COL[x] */
        s3c_gpio_cfgrange_nopull(S3C64XX_GPL(0), cols, S3C_GPIO_SFN(3));
index 1a94203..f344a22 100644 (file)
@@ -56,7 +56,7 @@ void s3c6400_setup_sdhci_cfg_card(struct platform_device *dev,
        else
                ctrl3 = (S3C_SDHCI_CTRL3_FCSEL1 | S3C_SDHCI_CTRL3_FCSEL0);
 
-       printk(KERN_INFO "%s: CTRL 2=%08x, 3=%08x\n", __func__, ctrl2, ctrl3);
+       pr_debug("%s: CTRL 2=%08x, 3=%08x\n", __func__, ctrl2, ctrl3);
        writel(ctrl2, r + S3C_SDHCI_CONTROL2);
        writel(ctrl3, r + S3C_SDHCI_CONTROL3);
 }
index 203dd5a..058dab4 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s5p6442/include/mach/map.h
  *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com/
  *
  * S5P6442 - Memory map definitions
 #include <plat/map-base.h>
 #include <plat/map-s5p.h>
 
-#define S5P6442_PA_CHIPID      (0xE0000000)
-#define S5P_PA_CHIPID          S5P6442_PA_CHIPID
+#define S5P6442_PA_SDRAM       0x20000000
 
-#define S5P6442_PA_SYSCON      (0xE0100000)
-#define S5P_PA_SYSCON          S5P6442_PA_SYSCON
+#define S5P6442_PA_I2S0                0xC0B00000
+#define S5P6442_PA_I2S1                0xF2200000
 
-#define S5P6442_PA_GPIO                (0xE0200000)
+#define S5P6442_PA_CHIPID      0xE0000000
 
-#define S5P6442_PA_VIC0                (0xE4000000)
-#define S5P6442_PA_VIC1                (0xE4100000)
-#define S5P6442_PA_VIC2                (0xE4200000)
+#define S5P6442_PA_SYSCON      0xE0100000
 
-#define S5P6442_PA_SROMC       (0xE7000000)
-#define S5P_PA_SROMC           S5P6442_PA_SROMC
+#define S5P6442_PA_GPIO                0xE0200000
 
-#define S5P6442_PA_MDMA                0xE8000000
-#define S5P6442_PA_PDMA                0xE9000000
+#define S5P6442_PA_VIC0                0xE4000000
+#define S5P6442_PA_VIC1                0xE4100000
+#define S5P6442_PA_VIC2                0xE4200000
 
-#define S5P6442_PA_TIMER       (0xEA000000)
-#define S5P_PA_TIMER           S5P6442_PA_TIMER
+#define S5P6442_PA_SROMC       0xE7000000
 
-#define S5P6442_PA_SYSTIMER    (0xEA100000)
+#define S5P6442_PA_MDMA                0xE8000000
+#define S5P6442_PA_PDMA                0xE9000000
 
-#define S5P6442_PA_WATCHDOG    (0xEA200000)
+#define S5P6442_PA_TIMER       0xEA000000
 
-#define S5P6442_PA_UART                (0xEC000000)
+#define S5P6442_PA_SYSTIMER    0xEA100000
 
-#define S5P_PA_UART0           (S5P6442_PA_UART + 0x0)
-#define S5P_PA_UART1           (S5P6442_PA_UART + 0x400)
-#define S5P_PA_UART2           (S5P6442_PA_UART + 0x800)
-#define S5P_SZ_UART            SZ_256
+#define S5P6442_PA_WATCHDOG    0xEA200000
 
-#define S5P6442_PA_IIC0                (0xEC100000)
+#define S5P6442_PA_UART                0xEC000000
 
-#define S5P6442_PA_SDRAM       (0x20000000)
-#define S5P_PA_SDRAM           S5P6442_PA_SDRAM
+#define S5P6442_PA_IIC0                0xEC100000
 
 #define S5P6442_PA_SPI         0xEC300000
 
-/* I2S */
-#define S5P6442_PA_I2S0                0xC0B00000
-#define S5P6442_PA_I2S1                0xF2200000
-
-/* PCM */
 #define S5P6442_PA_PCM0                0xF2400000
 #define S5P6442_PA_PCM1                0xF2500000
 
-/* compatibiltiy defines. */
+/* Compatibiltiy Defines */
+
+#define S3C_PA_IIC             S5P6442_PA_IIC0
 #define S3C_PA_WDT             S5P6442_PA_WATCHDOG
+
+#define S5P_PA_CHIPID          S5P6442_PA_CHIPID
+#define S5P_PA_SDRAM           S5P6442_PA_SDRAM
+#define S5P_PA_SROMC           S5P6442_PA_SROMC
+#define S5P_PA_SYSCON          S5P6442_PA_SYSCON
+#define S5P_PA_TIMER           S5P6442_PA_TIMER
+
+/* UART */
+
 #define S3C_PA_UART            S5P6442_PA_UART
-#define S3C_PA_IIC             S5P6442_PA_IIC0
+
+#define S5P_PA_UART(x)         (S3C_PA_UART + ((x) * S3C_UART_OFFSET))
+#define S5P_PA_UART0           S5P_PA_UART(0)
+#define S5P_PA_UART1           S5P_PA_UART(1)
+#define S5P_PA_UART2           S5P_PA_UART(2)
+
+#define S5P_SZ_UART            SZ_256
 
 #endif /* __ASM_ARCH_MAP_H */
index 5486c8f..adb5f29 100644 (file)
@@ -23,7 +23,7 @@
 #define S5P6440_GPIO_A_NR      (6)
 #define S5P6440_GPIO_B_NR      (7)
 #define S5P6440_GPIO_C_NR      (8)
-#define S5P6440_GPIO_F_NR      (2)
+#define S5P6440_GPIO_F_NR      (16)
 #define S5P6440_GPIO_G_NR      (7)
 #define S5P6440_GPIO_H_NR      (10)
 #define S5P6440_GPIO_I_NR      (16)
@@ -36,7 +36,7 @@
 #define S5P6450_GPIO_B_NR      (7)
 #define S5P6450_GPIO_C_NR      (8)
 #define S5P6450_GPIO_D_NR      (8)
-#define S5P6450_GPIO_F_NR      (2)
+#define S5P6450_GPIO_F_NR      (16)
 #define S5P6450_GPIO_G_NR      (14)
 #define S5P6450_GPIO_H_NR      (10)
 #define S5P6450_GPIO_I_NR      (16)
index a9365e5..95c9125 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s5p64x0/include/mach/map.h
  *
- * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2009-2011 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com
  *
  * S5P64X0 - Memory map definitions
 #include <plat/map-base.h>
 #include <plat/map-s5p.h>
 
-#define S5P64X0_PA_SDRAM       (0x20000000)
+#define S5P64X0_PA_SDRAM       0x20000000
 
-#define S5P64X0_PA_CHIPID      (0xE0000000)
-#define S5P_PA_CHIPID          S5P64X0_PA_CHIPID
-
-#define S5P64X0_PA_SYSCON      (0xE0100000)
-#define S5P_PA_SYSCON          S5P64X0_PA_SYSCON
-
-#define S5P64X0_PA_GPIO                (0xE0308000)
-
-#define S5P64X0_PA_VIC0                (0xE4000000)
-#define S5P64X0_PA_VIC1                (0xE4100000)
+#define S5P64X0_PA_CHIPID      0xE0000000
 
-#define S5P64X0_PA_SROMC       (0xE7000000)
-#define S5P_PA_SROMC           S5P64X0_PA_SROMC
-
-#define S5P64X0_PA_PDMA                (0xE9000000)
-
-#define S5P64X0_PA_TIMER       (0xEA000000)
-#define S5P_PA_TIMER           S5P64X0_PA_TIMER
+#define S5P64X0_PA_SYSCON      0xE0100000
 
-#define S5P64X0_PA_RTC         (0xEA100000)
+#define S5P64X0_PA_GPIO                0xE0308000
 
-#define S5P64X0_PA_WDT         (0xEA200000)
+#define S5P64X0_PA_VIC0                0xE4000000
+#define S5P64X0_PA_VIC1                0xE4100000
 
-#define S5P6440_PA_UART(x)     (0xEC000000 + ((x) * S3C_UART_OFFSET))
-#define S5P6450_PA_UART(x)     ((x < 5) ? (0xEC800000 + ((x) * S3C_UART_OFFSET)) : (0xEC000000))
+#define S5P64X0_PA_SROMC       0xE7000000
 
-#define S5P_PA_UART0           S5P6450_PA_UART(0)
-#define S5P_PA_UART1           S5P6450_PA_UART(1)
-#define S5P_PA_UART2           S5P6450_PA_UART(2)
-#define S5P_PA_UART3           S5P6450_PA_UART(3)
-#define S5P_PA_UART4           S5P6450_PA_UART(4)
-#define S5P_PA_UART5           S5P6450_PA_UART(5)
+#define S5P64X0_PA_PDMA                0xE9000000
 
-#define S5P_SZ_UART            SZ_256
+#define S5P64X0_PA_TIMER       0xEA000000
+#define S5P64X0_PA_RTC         0xEA100000
+#define S5P64X0_PA_WDT         0xEA200000
 
-#define S5P6440_PA_IIC0                (0xEC104000)
-#define S5P6440_PA_IIC1                (0xEC20F000)
-#define S5P6450_PA_IIC0                (0xEC100000)
-#define S5P6450_PA_IIC1                (0xEC200000)
+#define S5P6440_PA_IIC0                0xEC104000
+#define S5P6440_PA_IIC1                0xEC20F000
+#define S5P6450_PA_IIC0                0xEC100000
+#define S5P6450_PA_IIC1                0xEC200000
 
-#define S5P64X0_PA_SPI0                (0xEC400000)
-#define S5P64X0_PA_SPI1                (0xEC500000)
+#define S5P64X0_PA_SPI0                0xEC400000
+#define S5P64X0_PA_SPI1                0xEC500000
 
-#define S5P64X0_PA_HSOTG       (0xED100000)
+#define S5P64X0_PA_HSOTG       0xED100000
 
 #define S5P64X0_PA_HSMMC(x)    (0xED800000 + ((x) * 0x100000))
 
-#define S5P64X0_PA_I2S         (0xF2000000)
+#define S5P64X0_PA_I2S         0xF2000000
 #define S5P6450_PA_I2S1                0xF2800000
 #define S5P6450_PA_I2S2                0xF2900000
 
-#define S5P64X0_PA_PCM         (0xF2100000)
+#define S5P64X0_PA_PCM         0xF2100000
 
-#define S5P64X0_PA_ADC         (0xF3000000)
+#define S5P64X0_PA_ADC         0xF3000000
 
-/* compatibiltiy defines. */
+/* Compatibiltiy Defines */
 
 #define S3C_PA_HSMMC0          S5P64X0_PA_HSMMC(0)
 #define S3C_PA_HSMMC1          S5P64X0_PA_HSMMC(1)
 #define S3C_PA_RTC             S5P64X0_PA_RTC
 #define S3C_PA_WDT             S5P64X0_PA_WDT
 
+#define S5P_PA_CHIPID          S5P64X0_PA_CHIPID
+#define S5P_PA_SROMC           S5P64X0_PA_SROMC
+#define S5P_PA_SYSCON          S5P64X0_PA_SYSCON
+#define S5P_PA_TIMER           S5P64X0_PA_TIMER
+
 #define SAMSUNG_PA_ADC         S5P64X0_PA_ADC
 
+/* UART */
+
+#define S5P6440_PA_UART(x)     (0xEC000000 + ((x) * S3C_UART_OFFSET))
+#define S5P6450_PA_UART(x)     ((x < 5) ? (0xEC800000 + ((x) * S3C_UART_OFFSET)) : (0xEC000000))
+
+#define S5P_PA_UART0           S5P6450_PA_UART(0)
+#define S5P_PA_UART1           S5P6450_PA_UART(1)
+#define S5P_PA_UART2           S5P6450_PA_UART(2)
+#define S5P_PA_UART3           S5P6450_PA_UART(3)
+#define S5P_PA_UART4           S5P6450_PA_UART(4)
+#define S5P_PA_UART5           S5P6450_PA_UART(5)
+
+#define S5P_SZ_UART            SZ_256
+
 #endif /* __ASM_ARCH_MAP_H */
index 328467b..ccbe6b7 100644 (file)
@@ -1,4 +1,7 @@
 /* linux/arch/arm/mach-s5pc100/include/mach/map.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
  *
  * Copyright 2009 Samsung Electronics Co.
  *     Byungho Min <bhmin@samsung.com>
 #include <plat/map-base.h>
 #include <plat/map-s5p.h>
 
-/*
- * map-base.h has already defined virtual memory address
- * S3C_VA_IRQ          S3C_ADDR(0x00000000)    irq controller(s)
- * S3C_VA_SYS          S3C_ADDR(0x00100000)    system control
- * S3C_VA_MEM          S3C_ADDR(0x00200000)    system control (not used)
- * S3C_VA_TIMER                S3C_ADDR(0x00300000)    timer block
- * S3C_VA_WATCHDOG     S3C_ADDR(0x00400000)    watchdog
- * S3C_VA_UART         S3C_ADDR(0x01000000)    UART
- *
- * S5PC100 specific virtual memory address can be defined here
- * S5PC1XX_VA_GPIO     S3C_ADDR(0x00500000)    GPIO
- *
- */
+#define S5PC100_PA_SDRAM               0x20000000
+
+#define S5PC100_PA_ONENAND             0xE7100000
+#define S5PC100_PA_ONENAND_BUF         0xB0000000
+
+#define S5PC100_PA_CHIPID              0xE0000000
 
-#define S5PC100_PA_ONENAND_BUF (0xB0000000)
-#define S5PC100_SZ_ONENAND_BUF (SZ_256M - SZ_32M)
+#define S5PC100_PA_SYSCON              0xE0100000
 
-/* Chip ID */
+#define S5PC100_PA_OTHERS              0xE0200000
 
-#define S5PC100_PA_CHIPID      (0xE0000000)
-#define S5P_PA_CHIPID          S5PC100_PA_CHIPID
+#define S5PC100_PA_GPIO                        0xE0300000
 
-#define S5PC100_PA_SYSCON      (0xE0100000)
-#define S5P_PA_SYSCON          S5PC100_PA_SYSCON
+#define S5PC100_PA_VIC0                        0xE4000000
+#define S5PC100_PA_VIC1                        0xE4100000
+#define S5PC100_PA_VIC2                        0xE4200000
 
-#define S5PC100_PA_OTHERS      (0xE0200000)
-#define S5PC100_VA_OTHERS      (S3C_VA_SYS + 0x10000)
+#define S5PC100_PA_SROMC               0xE7000000
 
-#define S5PC100_PA_GPIO                (0xE0300000)
-#define S5PC1XX_VA_GPIO                S3C_ADDR(0x00500000)
+#define S5PC100_PA_CFCON               0xE7800000
 
-/* Interrupt */
-#define S5PC100_PA_VIC0                (0xE4000000)
-#define S5PC100_PA_VIC1                (0xE4100000)
-#define S5PC100_PA_VIC2                (0xE4200000)
-#define S5PC100_VA_VIC         S3C_VA_IRQ
-#define S5PC100_VA_VIC_OFFSET  0x10000
-#define S5PC1XX_VA_VIC(x)      (S5PC100_VA_VIC + ((x) * S5PC100_VA_VIC_OFFSET))
+#define S5PC100_PA_MDMA                        0xE8100000
+#define S5PC100_PA_PDMA0               0xE9000000
+#define S5PC100_PA_PDMA1               0xE9200000
 
-#define S5PC100_PA_SROMC       (0xE7000000)
-#define S5P_PA_SROMC           S5PC100_PA_SROMC
+#define S5PC100_PA_TIMER               0xEA000000
+#define S5PC100_PA_SYSTIMER            0xEA100000
+#define S5PC100_PA_WATCHDOG            0xEA200000
+#define S5PC100_PA_RTC                 0xEA300000
 
-#define S5PC100_PA_ONENAND     (0xE7100000)
+#define S5PC100_PA_UART                        0xEC000000
 
-#define S5PC100_PA_CFCON       (0xE7800000)
+#define S5PC100_PA_IIC0                        0xEC100000
+#define S5PC100_PA_IIC1                        0xEC200000
 
-/* DMA */
-#define S5PC100_PA_MDMA                (0xE8100000)
-#define S5PC100_PA_PDMA0       (0xE9000000)
-#define S5PC100_PA_PDMA1       (0xE9200000)
+#define S5PC100_PA_SPI0                        0xEC300000
+#define S5PC100_PA_SPI1                        0xEC400000
+#define S5PC100_PA_SPI2                        0xEC500000
 
-/* Timer */
-#define S5PC100_PA_TIMER       (0xEA000000)
-#define S5P_PA_TIMER           S5PC100_PA_TIMER
+#define S5PC100_PA_USB_HSOTG           0xED200000
+#define S5PC100_PA_USB_HSPHY           0xED300000
 
-#define S5PC100_PA_SYSTIMER    (0xEA100000)
+#define S5PC100_PA_HSMMC(x)            (0xED800000 + ((x) * 0x100000))
 
-#define S5PC100_PA_WATCHDOG    (0xEA200000)
-#define S5PC100_PA_RTC         (0xEA300000)
+#define S5PC100_PA_FB                  0xEE000000
 
-#define S5PC100_PA_UART                (0xEC000000)
+#define S5PC100_PA_FIMC0               0xEE200000
+#define S5PC100_PA_FIMC1               0xEE300000
+#define S5PC100_PA_FIMC2               0xEE400000
 
-#define S5P_PA_UART0           (S5PC100_PA_UART + 0x0)
-#define S5P_PA_UART1           (S5PC100_PA_UART + 0x400)
-#define S5P_PA_UART2           (S5PC100_PA_UART + 0x800)
-#define S5P_PA_UART3           (S5PC100_PA_UART + 0xC00)
-#define S5P_SZ_UART            SZ_256
+#define S5PC100_PA_I2S0                        0xF2000000
+#define S5PC100_PA_I2S1                        0xF2100000
+#define S5PC100_PA_I2S2                        0xF2200000
 
-#define S5PC100_PA_IIC0                (0xEC100000)
-#define S5PC100_PA_IIC1                (0xEC200000)
+#define S5PC100_PA_AC97                        0xF2300000
 
-/* SPI */
-#define S5PC100_PA_SPI0                0xEC300000
-#define S5PC100_PA_SPI1                0xEC400000
-#define S5PC100_PA_SPI2                0xEC500000
+#define S5PC100_PA_PCM0                        0xF2400000
+#define S5PC100_PA_PCM1                        0xF2500000
 
-/* USB HS OTG */
-#define S5PC100_PA_USB_HSOTG   (0xED200000)
-#define S5PC100_PA_USB_HSPHY   (0xED300000)
+#define S5PC100_PA_SPDIF               0xF2600000
 
-#define S5PC100_PA_FB          (0xEE000000)
+#define S5PC100_PA_TSADC               0xF3000000
 
-#define S5PC100_PA_FIMC0       (0xEE200000)
-#define S5PC100_PA_FIMC1       (0xEE300000)
-#define S5PC100_PA_FIMC2       (0xEE400000)
+#define S5PC100_PA_KEYPAD              0xF3100000
 
-#define S5PC100_PA_I2S0                (0xF2000000)
-#define S5PC100_PA_I2S1                (0xF2100000)
-#define S5PC100_PA_I2S2                (0xF2200000)
+/* Compatibiltiy Defines */
 
-#define S5PC100_PA_AC97                0xF2300000
+#define S3C_PA_FB                      S5PC100_PA_FB
+#define S3C_PA_HSMMC0                  S5PC100_PA_HSMMC(0)
+#define S3C_PA_HSMMC1                  S5PC100_PA_HSMMC(1)
+#define S3C_PA_HSMMC2                  S5PC100_PA_HSMMC(2)
+#define S3C_PA_IIC                     S5PC100_PA_IIC0
+#define S3C_PA_IIC1                    S5PC100_PA_IIC1
+#define S3C_PA_KEYPAD                  S5PC100_PA_KEYPAD
+#define S3C_PA_ONENAND                 S5PC100_PA_ONENAND
+#define S3C_PA_ONENAND_BUF             S5PC100_PA_ONENAND_BUF
+#define S3C_PA_RTC                     S5PC100_PA_RTC
+#define S3C_PA_TSADC                   S5PC100_PA_TSADC
+#define S3C_PA_USB_HSOTG               S5PC100_PA_USB_HSOTG
+#define S3C_PA_USB_HSPHY               S5PC100_PA_USB_HSPHY
+#define S3C_PA_WDT                     S5PC100_PA_WATCHDOG
 
-/* PCM */
-#define S5PC100_PA_PCM0                0xF2400000
-#define S5PC100_PA_PCM1                0xF2500000
+#define S5P_PA_CHIPID                  S5PC100_PA_CHIPID
+#define S5P_PA_FIMC0                   S5PC100_PA_FIMC0
+#define S5P_PA_FIMC1                   S5PC100_PA_FIMC1
+#define S5P_PA_FIMC2                   S5PC100_PA_FIMC2
+#define S5P_PA_SDRAM                   S5PC100_PA_SDRAM
+#define S5P_PA_SROMC                   S5PC100_PA_SROMC
+#define S5P_PA_SYSCON                  S5PC100_PA_SYSCON
+#define S5P_PA_TIMER                   S5PC100_PA_TIMER
 
-#define S5PC100_PA_SPDIF       0xF2600000
+#define SAMSUNG_PA_ADC                 S5PC100_PA_TSADC
+#define SAMSUNG_PA_CFCON               S5PC100_PA_CFCON
+#define SAMSUNG_PA_KEYPAD              S5PC100_PA_KEYPAD
 
-#define S5PC100_PA_TSADC       (0xF3000000)
+#define S5PC100_VA_OTHERS              (S3C_VA_SYS + 0x10000)
 
-/* KEYPAD */
-#define S5PC100_PA_KEYPAD      (0xF3100000)
+#define S3C_SZ_ONENAND_BUF             (SZ_256M - SZ_32M)
 
-#define S5PC100_PA_HSMMC(x)    (0xED800000 + ((x) * 0x100000))
+/* UART */
 
-#define S5PC100_PA_SDRAM       (0x20000000)
-#define S5P_PA_SDRAM           S5PC100_PA_SDRAM
+#define S3C_PA_UART                    S5PC100_PA_UART
 
-/* compatibiltiy defines. */
-#define S3C_PA_UART            S5PC100_PA_UART
-#define S3C_PA_IIC             S5PC100_PA_IIC0
-#define S3C_PA_IIC1            S5PC100_PA_IIC1
-#define S3C_PA_FB              S5PC100_PA_FB
-#define S3C_PA_G2D             S5PC100_PA_G2D
-#define S3C_PA_G3D             S5PC100_PA_G3D
-#define S3C_PA_JPEG            S5PC100_PA_JPEG
-#define S3C_PA_ROTATOR         S5PC100_PA_ROTATOR
-#define S5P_VA_VIC0            S5PC1XX_VA_VIC(0)
-#define S5P_VA_VIC1            S5PC1XX_VA_VIC(1)
-#define S5P_VA_VIC2            S5PC1XX_VA_VIC(2)
-#define S3C_PA_USB_HSOTG       S5PC100_PA_USB_HSOTG
-#define S3C_PA_USB_HSPHY       S5PC100_PA_USB_HSPHY
-#define S3C_PA_HSMMC0          S5PC100_PA_HSMMC(0)
-#define S3C_PA_HSMMC1          S5PC100_PA_HSMMC(1)
-#define S3C_PA_HSMMC2          S5PC100_PA_HSMMC(2)
-#define S3C_PA_KEYPAD          S5PC100_PA_KEYPAD
-#define S3C_PA_WDT             S5PC100_PA_WATCHDOG
-#define S3C_PA_TSADC           S5PC100_PA_TSADC
-#define S3C_PA_ONENAND         S5PC100_PA_ONENAND
-#define S3C_PA_ONENAND_BUF     S5PC100_PA_ONENAND_BUF
-#define S3C_SZ_ONENAND_BUF     S5PC100_SZ_ONENAND_BUF
-#define S3C_PA_RTC             S5PC100_PA_RTC
-
-#define SAMSUNG_PA_ADC         S5PC100_PA_TSADC
-#define SAMSUNG_PA_CFCON       S5PC100_PA_CFCON
-#define SAMSUNG_PA_KEYPAD      S5PC100_PA_KEYPAD
+#define S5P_PA_UART(x)                 (S3C_PA_UART + ((x) * S3C_UART_OFFSET))
+#define S5P_PA_UART0                   S5P_PA_UART(0)
+#define S5P_PA_UART1                   S5P_PA_UART(1)
+#define S5P_PA_UART2                   S5P_PA_UART(2)
+#define S5P_PA_UART3                   S5P_PA_UART(3)
 
-#define S5P_PA_FIMC0           S5PC100_PA_FIMC0
-#define S5P_PA_FIMC1           S5PC100_PA_FIMC1
-#define S5P_PA_FIMC2           S5PC100_PA_FIMC2
+#define S5P_SZ_UART                    SZ_256
 
-#endif /* __ASM_ARCH_C100_MAP_H */
+#endif /* __ASM_ARCH_MAP_H */
index 3611492..1dd5883 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s5pv210/include/mach/map.h
  *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com/
  *
  * S5PV210 - Memory map definitions
 #include <plat/map-base.h>
 #include <plat/map-s5p.h>
 
-#define S5PV210_PA_SROM_BANK5  (0xA8000000)
+#define S5PV210_PA_SDRAM               0x20000000
 
-#define S5PC110_PA_ONENAND     (0xB0000000)
-#define S5P_PA_ONENAND         S5PC110_PA_ONENAND
+#define S5PV210_PA_SROM_BANK5          0xA8000000
 
-#define S5PC110_PA_ONENAND_DMA (0xB0600000)
-#define S5P_PA_ONENAND_DMA     S5PC110_PA_ONENAND_DMA
+#define S5PC110_PA_ONENAND             0xB0000000
+#define S5PC110_PA_ONENAND_DMA         0xB0600000
 
-#define S5PV210_PA_CHIPID      (0xE0000000)
-#define S5P_PA_CHIPID          S5PV210_PA_CHIPID
+#define S5PV210_PA_CHIPID              0xE0000000
 
-#define S5PV210_PA_SYSCON      (0xE0100000)
-#define S5P_PA_SYSCON          S5PV210_PA_SYSCON
+#define S5PV210_PA_SYSCON              0xE0100000
 
-#define S5PV210_PA_GPIO                (0xE0200000)
+#define S5PV210_PA_GPIO                        0xE0200000
 
-/* SPI */
-#define S5PV210_PA_SPI0                0xE1300000
-#define S5PV210_PA_SPI1                0xE1400000
+#define S5PV210_PA_SPDIF               0xE1100000
 
-#define S5PV210_PA_KEYPAD      (0xE1600000)
+#define S5PV210_PA_SPI0                        0xE1300000
+#define S5PV210_PA_SPI1                        0xE1400000
 
-#define S5PV210_PA_IIC0                (0xE1800000)
-#define S5PV210_PA_IIC1                (0xFAB00000)
-#define S5PV210_PA_IIC2                (0xE1A00000)
+#define S5PV210_PA_KEYPAD              0xE1600000
 
-#define S5PV210_PA_TIMER       (0xE2500000)
-#define S5P_PA_TIMER           S5PV210_PA_TIMER
+#define S5PV210_PA_ADC                 0xE1700000
 
-#define S5PV210_PA_SYSTIMER    (0xE2600000)
+#define S5PV210_PA_IIC0                        0xE1800000
+#define S5PV210_PA_IIC1                        0xFAB00000
+#define S5PV210_PA_IIC2                        0xE1A00000
 
-#define S5PV210_PA_WATCHDOG    (0xE2700000)
+#define S5PV210_PA_AC97                        0xE2200000
 
-#define S5PV210_PA_RTC         (0xE2800000)
-#define S5PV210_PA_UART                (0xE2900000)
+#define S5PV210_PA_PCM0                        0xE2300000
+#define S5PV210_PA_PCM1                        0xE1200000
+#define S5PV210_PA_PCM2                        0xE2B00000
 
-#define S5P_PA_UART0           (S5PV210_PA_UART + 0x0)
-#define S5P_PA_UART1           (S5PV210_PA_UART + 0x400)
-#define S5P_PA_UART2           (S5PV210_PA_UART + 0x800)
-#define S5P_PA_UART3           (S5PV210_PA_UART + 0xC00)
+#define S5PV210_PA_TIMER               0xE2500000
+#define S5PV210_PA_SYSTIMER            0xE2600000
+#define S5PV210_PA_WATCHDOG            0xE2700000
+#define S5PV210_PA_RTC                 0xE2800000
 
-#define S5P_SZ_UART            SZ_256
+#define S5PV210_PA_UART                        0xE2900000
 
-#define S3C_VA_UARTx(x)                (S3C_VA_UART + ((x) * S3C_UART_OFFSET))
+#define S5PV210_PA_SROMC               0xE8000000
 
-#define S5PV210_PA_SROMC       (0xE8000000)
-#define S5P_PA_SROMC           S5PV210_PA_SROMC
+#define S5PV210_PA_CFCON               0xE8200000
 
-#define S5PV210_PA_CFCON       (0xE8200000)
+#define S5PV210_PA_HSMMC(x)            (0xEB000000 + ((x) * 0x100000))
 
-#define S5PV210_PA_MDMA                0xFA200000
-#define S5PV210_PA_PDMA0       0xE0900000
-#define S5PV210_PA_PDMA1       0xE0A00000
+#define S5PV210_PA_HSOTG               0xEC000000
+#define S5PV210_PA_HSPHY               0xEC100000
 
-#define S5PV210_PA_FB          (0xF8000000)
+#define S5PV210_PA_IIS0                        0xEEE30000
+#define S5PV210_PA_IIS1                        0xE2100000
+#define S5PV210_PA_IIS2                        0xE2A00000
 
-#define S5PV210_PA_FIMC0       (0xFB200000)
-#define S5PV210_PA_FIMC1       (0xFB300000)
-#define S5PV210_PA_FIMC2       (0xFB400000)
+#define S5PV210_PA_DMC0                        0xF0000000
+#define S5PV210_PA_DMC1                        0xF1400000
 
-#define S5PV210_PA_HSMMC(x)    (0xEB000000 + ((x) * 0x100000))
+#define S5PV210_PA_VIC0                        0xF2000000
+#define S5PV210_PA_VIC1                        0xF2100000
+#define S5PV210_PA_VIC2                        0xF2200000
+#define S5PV210_PA_VIC3                        0xF2300000
 
-#define S5PV210_PA_HSOTG       (0xEC000000)
-#define S5PV210_PA_HSPHY       (0xEC100000)
+#define S5PV210_PA_FB                  0xF8000000
 
-#define S5PV210_PA_VIC0                (0xF2000000)
-#define S5PV210_PA_VIC1                (0xF2100000)
-#define S5PV210_PA_VIC2                (0xF2200000)
-#define S5PV210_PA_VIC3                (0xF2300000)
+#define S5PV210_PA_MDMA                        0xFA200000
+#define S5PV210_PA_PDMA0               0xE0900000
+#define S5PV210_PA_PDMA1               0xE0A00000
 
-#define S5PV210_PA_SDRAM       (0x20000000)
-#define S5P_PA_SDRAM           S5PV210_PA_SDRAM
+#define S5PV210_PA_MIPI_CSIS           0xFA600000
 
-/* S/PDIF */
-#define S5PV210_PA_SPDIF       0xE1100000
+#define S5PV210_PA_FIMC0               0xFB200000
+#define S5PV210_PA_FIMC1               0xFB300000
+#define S5PV210_PA_FIMC2               0xFB400000
 
-/* I2S */
-#define S5PV210_PA_IIS0                0xEEE30000
-#define S5PV210_PA_IIS1                0xE2100000
-#define S5PV210_PA_IIS2                0xE2A00000
+/* Compatibiltiy Defines */
 
-/* PCM */
-#define S5PV210_PA_PCM0                0xE2300000
-#define S5PV210_PA_PCM1                0xE1200000
-#define S5PV210_PA_PCM2                0xE2B00000
+#define S3C_PA_FB                      S5PV210_PA_FB
+#define S3C_PA_HSMMC0                  S5PV210_PA_HSMMC(0)
+#define S3C_PA_HSMMC1                  S5PV210_PA_HSMMC(1)
+#define S3C_PA_HSMMC2                  S5PV210_PA_HSMMC(2)
+#define S3C_PA_HSMMC3                  S5PV210_PA_HSMMC(3)
+#define S3C_PA_IIC                     S5PV210_PA_IIC0
+#define S3C_PA_IIC1                    S5PV210_PA_IIC1
+#define S3C_PA_IIC2                    S5PV210_PA_IIC2
+#define S3C_PA_RTC                     S5PV210_PA_RTC
+#define S3C_PA_USB_HSOTG               S5PV210_PA_HSOTG
+#define S3C_PA_WDT                     S5PV210_PA_WATCHDOG
 
-/* AC97 */
-#define S5PV210_PA_AC97                0xE2200000
+#define S5P_PA_CHIPID                  S5PV210_PA_CHIPID
+#define S5P_PA_FIMC0                   S5PV210_PA_FIMC0
+#define S5P_PA_FIMC1                   S5PV210_PA_FIMC1
+#define S5P_PA_FIMC2                   S5PV210_PA_FIMC2
+#define S5P_PA_MIPI_CSIS0              S5PV210_PA_MIPI_CSIS
+#define S5P_PA_ONENAND                 S5PC110_PA_ONENAND
+#define S5P_PA_ONENAND_DMA             S5PC110_PA_ONENAND_DMA
+#define S5P_PA_SDRAM                   S5PV210_PA_SDRAM
+#define S5P_PA_SROMC                   S5PV210_PA_SROMC
+#define S5P_PA_SYSCON                  S5PV210_PA_SYSCON
+#define S5P_PA_TIMER                   S5PV210_PA_TIMER
 
-#define S5PV210_PA_ADC         (0xE1700000)
+#define SAMSUNG_PA_ADC                 S5PV210_PA_ADC
+#define SAMSUNG_PA_CFCON               S5PV210_PA_CFCON
+#define SAMSUNG_PA_KEYPAD              S5PV210_PA_KEYPAD
 
-#define S5PV210_PA_DMC0                (0xF0000000)
-#define S5PV210_PA_DMC1                (0xF1400000)
+/* UART */
 
-#define S5PV210_PA_MIPI_CSIS   0xFA600000
+#define S3C_VA_UARTx(x)                        (S3C_VA_UART + ((x) * S3C_UART_OFFSET))
 
-/* compatibiltiy defines. */
-#define S3C_PA_UART            S5PV210_PA_UART
-#define S3C_PA_HSMMC0          S5PV210_PA_HSMMC(0)
-#define S3C_PA_HSMMC1          S5PV210_PA_HSMMC(1)
-#define S3C_PA_HSMMC2          S5PV210_PA_HSMMC(2)
-#define S3C_PA_HSMMC3          S5PV210_PA_HSMMC(3)
-#define S3C_PA_IIC             S5PV210_PA_IIC0
-#define S3C_PA_IIC1            S5PV210_PA_IIC1
-#define S3C_PA_IIC2            S5PV210_PA_IIC2
-#define S3C_PA_FB              S5PV210_PA_FB
-#define S3C_PA_RTC             S5PV210_PA_RTC
-#define S3C_PA_WDT             S5PV210_PA_WATCHDOG
-#define S3C_PA_USB_HSOTG       S5PV210_PA_HSOTG
-#define S5P_PA_FIMC0           S5PV210_PA_FIMC0
-#define S5P_PA_FIMC1           S5PV210_PA_FIMC1
-#define S5P_PA_FIMC2           S5PV210_PA_FIMC2
-#define S5P_PA_MIPI_CSIS0      S5PV210_PA_MIPI_CSIS
+#define S3C_PA_UART                    S5PV210_PA_UART
 
-#define SAMSUNG_PA_ADC         S5PV210_PA_ADC
-#define SAMSUNG_PA_CFCON       S5PV210_PA_CFCON
-#define SAMSUNG_PA_KEYPAD      S5PV210_PA_KEYPAD
+#define S5P_PA_UART(x)                 (S3C_PA_UART + ((x) * S3C_UART_OFFSET))
+#define S5P_PA_UART0                   S5P_PA_UART(0)
+#define S5P_PA_UART1                   S5P_PA_UART(1)
+#define S5P_PA_UART2                   S5P_PA_UART(2)
+#define S5P_PA_UART3                   S5P_PA_UART(3)
+
+#define S5P_SZ_UART                    SZ_256
 
 #endif /* __ASM_ARCH_MAP_H */
index 461aa03..557add4 100644 (file)
@@ -149,7 +149,7 @@ static struct regulator_init_data aquila_ldo2_data = {
 
 static struct regulator_init_data aquila_ldo3_data = {
        .constraints    = {
-               .name           = "VUSB/MIPI_1.1V",
+               .name           = "VUSB+MIPI_1.1V",
                .min_uV         = 1100000,
                .max_uV         = 1100000,
                .apply_uV       = 1,
@@ -197,7 +197,7 @@ static struct regulator_init_data aquila_ldo7_data = {
 
 static struct regulator_init_data aquila_ldo8_data = {
        .constraints    = {
-               .name           = "VUSB/VADC_3.3V",
+               .name           = "VUSB+VADC_3.3V",
                .min_uV         = 3300000,
                .max_uV         = 3300000,
                .apply_uV       = 1,
@@ -207,7 +207,7 @@ static struct regulator_init_data aquila_ldo8_data = {
 
 static struct regulator_init_data aquila_ldo9_data = {
        .constraints    = {
-               .name           = "VCC/VCAM_2.8V",
+               .name           = "VCC+VCAM_2.8V",
                .min_uV         = 2800000,
                .max_uV         = 2800000,
                .apply_uV       = 1,
@@ -381,9 +381,12 @@ static struct max8998_platform_data aquila_max8998_pdata = {
        .buck1_set1     = S5PV210_GPH0(3),
        .buck1_set2     = S5PV210_GPH0(4),
        .buck2_set3     = S5PV210_GPH0(5),
-       .buck1_max_voltage1 = 1200000,
-       .buck1_max_voltage2 = 1200000,
-       .buck2_max_voltage = 1200000,
+       .buck1_voltage1 = 1200000,
+       .buck1_voltage2 = 1200000,
+       .buck1_voltage3 = 1200000,
+       .buck1_voltage4 = 1200000,
+       .buck2_voltage1 = 1200000,
+       .buck2_voltage2 = 1200000,
 };
 #endif
 
index e22d511..056f5c7 100644 (file)
@@ -288,7 +288,7 @@ static struct regulator_init_data goni_ldo2_data = {
 
 static struct regulator_init_data goni_ldo3_data = {
        .constraints    = {
-               .name           = "VUSB/MIPI_1.1V",
+               .name           = "VUSB+MIPI_1.1V",
                .min_uV         = 1100000,
                .max_uV         = 1100000,
                .apply_uV       = 1,
@@ -337,7 +337,7 @@ static struct regulator_init_data goni_ldo7_data = {
 
 static struct regulator_init_data goni_ldo8_data = {
        .constraints    = {
-               .name           = "VUSB/VADC_3.3V",
+               .name           = "VUSB+VADC_3.3V",
                .min_uV         = 3300000,
                .max_uV         = 3300000,
                .apply_uV       = 1,
@@ -347,7 +347,7 @@ static struct regulator_init_data goni_ldo8_data = {
 
 static struct regulator_init_data goni_ldo9_data = {
        .constraints    = {
-               .name           = "VCC/VCAM_2.8V",
+               .name           = "VCC+VCAM_2.8V",
                .min_uV         = 2800000,
                .max_uV         = 2800000,
                .apply_uV       = 1,
@@ -521,9 +521,12 @@ static struct max8998_platform_data goni_max8998_pdata = {
        .buck1_set1     = S5PV210_GPH0(3),
        .buck1_set2     = S5PV210_GPH0(4),
        .buck2_set3     = S5PV210_GPH0(5),
-       .buck1_max_voltage1 = 1200000,
-       .buck1_max_voltage2 = 1200000,
-       .buck2_max_voltage = 1200000,
+       .buck1_voltage1 = 1200000,
+       .buck1_voltage2 = 1200000,
+       .buck1_voltage3 = 1200000,
+       .buck1_voltage4 = 1200000,
+       .buck2_voltage1 = 1200000,
+       .buck2_voltage2 = 1200000,
 };
 #endif
 
index 09c4c21..b2a9acc 100644 (file)
@@ -122,6 +122,7 @@ config MACH_SMDKV310
        select S3C_DEV_HSMMC2
        select S3C_DEV_HSMMC3
        select S5PV310_DEV_PD
+       select S5PV310_DEV_SYSMMU
        select S5PV310_SETUP_I2C1
        select S5PV310_SETUP_SDHCI
        help
index 74d4006..901657f 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s5pv310/include/mach/map.h
  *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com/
  *
  * S5PV310 - Memory map definitions
 
 #include <plat/map-s5p.h>
 
-#define S5PV310_PA_SYSRAM              (0x02025000)
+#define S5PV310_PA_SYSRAM              0x02025000
 
-#define S5PV310_PA_SROM_BANK(x)                (0x04000000 + ((x) * 0x01000000))
-
-#define S5PC210_PA_ONENAND             (0x0C000000)
-#define S5P_PA_ONENAND                 S5PC210_PA_ONENAND
-
-#define S5PC210_PA_ONENAND_DMA         (0x0C600000)
-#define S5P_PA_ONENAND_DMA             S5PC210_PA_ONENAND_DMA
-
-#define S5PV310_PA_CHIPID              (0x10000000)
-#define S5P_PA_CHIPID                  S5PV310_PA_CHIPID
-
-#define S5PV310_PA_SYSCON              (0x10010000)
-#define S5P_PA_SYSCON                  S5PV310_PA_SYSCON
+#define S5PV310_PA_I2S0                        0x03830000
+#define S5PV310_PA_I2S1                        0xE3100000
+#define S5PV310_PA_I2S2                        0xE2A00000
 
-#define S5PV310_PA_PMU                 (0x10020000)
+#define S5PV310_PA_PCM0                        0x03840000
+#define S5PV310_PA_PCM1                        0x13980000
+#define S5PV310_PA_PCM2                        0x13990000
 
-#define S5PV310_PA_CMU                 (0x10030000)
-
-#define S5PV310_PA_WATCHDOG            (0x10060000)
-#define S5PV310_PA_RTC                 (0x10070000)
-
-#define S5PV310_PA_DMC0                        (0x10400000)
-
-#define S5PV310_PA_COMBINER            (0x10448000)
-
-#define S5PV310_PA_COREPERI            (0x10500000)
-#define S5PV310_PA_GIC_CPU             (0x10500100)
-#define S5PV310_PA_TWD                 (0x10500600)
-#define S5PV310_PA_GIC_DIST            (0x10501000)
-#define S5PV310_PA_L2CC                        (0x10502000)
-
-/* DMA */
-#define S5PV310_PA_MDMA                0x10810000
-#define S5PV310_PA_PDMA0       0x12680000
-#define S5PV310_PA_PDMA1       0x12690000
-
-#define S5PV310_PA_GPIO1               (0x11400000)
-#define S5PV310_PA_GPIO2               (0x11000000)
-#define S5PV310_PA_GPIO3               (0x03860000)
-
-#define S5PV310_PA_MIPI_CSIS0          0x11880000
-#define S5PV310_PA_MIPI_CSIS1          0x11890000
+#define S5PV310_PA_SROM_BANK(x)                (0x04000000 + ((x) * 0x01000000))
 
-#define S5PV310_PA_HSMMC(x)            (0x12510000 + ((x) * 0x10000))
+#define S5PC210_PA_ONENAND             0x0C000000
+#define S5PC210_PA_ONENAND_DMA         0x0C600000
 
-#define S5PV310_PA_SROMC               (0x12570000)
-#define S5P_PA_SROMC                   S5PV310_PA_SROMC
+#define S5PV310_PA_CHIPID              0x10000000
 
-/* S/PDIF */
-#define S5PV310_PA_SPDIF       0xE1100000
+#define S5PV310_PA_SYSCON              0x10010000
+#define S5PV310_PA_PMU                 0x10020000
+#define S5PV310_PA_CMU                 0x10030000
 
-/* I2S */
-#define S5PV310_PA_I2S0                0x03830000
-#define S5PV310_PA_I2S1                0xE3100000
-#define S5PV310_PA_I2S2                0xE2A00000
+#define S5PV310_PA_WATCHDOG            0x10060000
+#define S5PV310_PA_RTC                 0x10070000
 
-/* PCM */
-#define S5PV310_PA_PCM0                0x03840000
-#define S5PV310_PA_PCM1                0x13980000
-#define S5PV310_PA_PCM2                0x13990000
+#define S5PV310_PA_DMC0                        0x10400000
 
-/* AC97 */
-#define S5PV310_PA_AC97                0x139A0000
+#define S5PV310_PA_COMBINER            0x10448000
 
-#define S5PV310_PA_UART                        (0x13800000)
+#define S5PV310_PA_COREPERI            0x10500000
+#define S5PV310_PA_GIC_CPU             0x10500100
+#define S5PV310_PA_TWD                 0x10500600
+#define S5PV310_PA_GIC_DIST            0x10501000
+#define S5PV310_PA_L2CC                        0x10502000
 
-#define S5P_PA_UART(x)                 (S5PV310_PA_UART + ((x) * S3C_UART_OFFSET))
-#define S5P_PA_UART0                   S5P_PA_UART(0)
-#define S5P_PA_UART1                   S5P_PA_UART(1)
-#define S5P_PA_UART2                   S5P_PA_UART(2)
-#define S5P_PA_UART3                   S5P_PA_UART(3)
-#define S5P_PA_UART4                   S5P_PA_UART(4)
-
-#define S5P_SZ_UART                    SZ_256
-
-#define S5PV310_PA_IIC(x)              (0x13860000 + ((x) * 0x10000))
-
-#define S5PV310_PA_TIMER               (0x139D0000)
-#define S5P_PA_TIMER                   S5PV310_PA_TIMER
-
-#define S5PV310_PA_SDRAM               (0x40000000)
-#define S5P_PA_SDRAM                   S5PV310_PA_SDRAM
+#define S5PV310_PA_MDMA                        0x10810000
+#define S5PV310_PA_PDMA0               0x12680000
+#define S5PV310_PA_PDMA1               0x12690000
 
 #define S5PV310_PA_SYSMMU_MDMA         0x10A40000
 #define S5PV310_PA_SYSMMU_SSS          0x10A50000
 #define S5PV310_PA_SYSMMU_TV           0x12E20000
 #define S5PV310_PA_SYSMMU_MFC_L                0x13620000
 #define S5PV310_PA_SYSMMU_MFC_R                0x13630000
-#define S5PV310_SYSMMU_TOTAL_IPNUM     16
-#define S5P_SYSMMU_TOTAL_IPNUM         S5PV310_SYSMMU_TOTAL_IPNUM
 
-/* compatibiltiy defines. */
-#define S3C_PA_UART                    S5PV310_PA_UART
+#define S5PV310_PA_GPIO1               0x11400000
+#define S5PV310_PA_GPIO2               0x11000000
+#define S5PV310_PA_GPIO3               0x03860000
+
+#define S5PV310_PA_MIPI_CSIS0          0x11880000
+#define S5PV310_PA_MIPI_CSIS1          0x11890000
+
+#define S5PV310_PA_HSMMC(x)            (0x12510000 + ((x) * 0x10000))
+
+#define S5PV310_PA_SROMC               0x12570000
+
+#define S5PV310_PA_UART                        0x13800000
+
+#define S5PV310_PA_IIC(x)              (0x13860000 + ((x) * 0x10000))
+
+#define S5PV310_PA_AC97                        0x139A0000
+
+#define S5PV310_PA_TIMER               0x139D0000
+
+#define S5PV310_PA_SDRAM               0x40000000
+
+#define S5PV310_PA_SPDIF               0xE1100000
+
+/* Compatibiltiy Defines */
+
 #define S3C_PA_HSMMC0                  S5PV310_PA_HSMMC(0)
 #define S3C_PA_HSMMC1                  S5PV310_PA_HSMMC(1)
 #define S3C_PA_HSMMC2                  S5PV310_PA_HSMMC(2)
 #define S3C_PA_IIC7                    S5PV310_PA_IIC(7)
 #define S3C_PA_RTC                     S5PV310_PA_RTC
 #define S3C_PA_WDT                     S5PV310_PA_WATCHDOG
+
+#define S5P_PA_CHIPID                  S5PV310_PA_CHIPID
 #define S5P_PA_MIPI_CSIS0              S5PV310_PA_MIPI_CSIS0
 #define S5P_PA_MIPI_CSIS1              S5PV310_PA_MIPI_CSIS1
+#define S5P_PA_ONENAND                 S5PC210_PA_ONENAND
+#define S5P_PA_ONENAND_DMA             S5PC210_PA_ONENAND_DMA
+#define S5P_PA_SDRAM                   S5PV310_PA_SDRAM
+#define S5P_PA_SROMC                   S5PV310_PA_SROMC
+#define S5P_PA_SYSCON                  S5PV310_PA_SYSCON
+#define S5P_PA_TIMER                   S5PV310_PA_TIMER
+
+/* UART */
+
+#define S3C_PA_UART                    S5PV310_PA_UART
+
+#define S5P_PA_UART(x)                 (S3C_PA_UART + ((x) * S3C_UART_OFFSET))
+#define S5P_PA_UART0                   S5P_PA_UART(0)
+#define S5P_PA_UART1                   S5P_PA_UART(1)
+#define S5P_PA_UART2                   S5P_PA_UART(2)
+#define S5P_PA_UART3                   S5P_PA_UART(3)
+#define S5P_PA_UART4                   S5P_PA_UART(4)
+
+#define S5P_SZ_UART                    SZ_256
 
 #endif /* __ASM_ARCH_MAP_H */
index 662fe85..598fc5c 100644 (file)
@@ -13,6 +13,9 @@
 #ifndef __ASM_ARM_ARCH_SYSMMU_H
 #define __ASM_ARM_ARCH_SYSMMU_H __FILE__
 
+#define S5PV310_SYSMMU_TOTAL_IPNUM     16
+#define S5P_SYSMMU_TOTAL_IPNUM         S5PV310_SYSMMU_TOTAL_IPNUM
+
 enum s5pv310_sysmmu_ips {
        SYSMMU_MDMA,
        SYSMMU_SSS,
@@ -32,7 +35,7 @@ enum s5pv310_sysmmu_ips {
        SYSMMU_MFC_R,
 };
 
-static char *sysmmu_ips_name[S5P_SYSMMU_TOTAL_IPNUM] = {
+static char *sysmmu_ips_name[S5PV310_SYSMMU_TOTAL_IPNUM] = {
        "SYSMMU_MDMA"   ,
        "SYSMMU_SSS"    ,
        "SYSMMU_FIMC0"  ,
index d43c5ef..bd3e1bf 100644 (file)
@@ -241,6 +241,9 @@ static struct locomo_platform_data locomo_info = {
 struct platform_device collie_locomo_device = {
        .name           = "locomo",
        .id             = 0,
+       .dev            = {
+               .platform_data  = &locomo_info,
+       },
        .num_resources  = ARRAY_SIZE(locomo_resources),
        .resource       = locomo_resources,
 };
index 4d1b4c5..0c8f6cf 100644 (file)
@@ -60,6 +60,8 @@ endchoice
 
 config MACH_AG5EVM
        bool "AG5EVM board"
+       select ARCH_REQUIRE_GPIOLIB
+       select SH_LCD_MIPI_DSI
        depends on ARCH_SH73A0
 
 config MACH_MACKEREL
index c18a740..4303a86 100644 (file)
 #include <linux/input/sh_keysc.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/sh_mmcif.h>
-
+#include <linux/sh_clk.h>
+#include <video/sh_mobile_lcdc.h>
+#include <video/sh_mipi_dsi.h>
 #include <sound/sh_fsi.h>
-
 #include <mach/hardware.h>
 #include <mach/sh73a0.h>
 #include <mach/common.h>
@@ -183,11 +184,165 @@ static struct platform_device mmc_device = {
        .resource       = sh_mmcif_resources,
 };
 
+/* IrDA */
+static struct resource irda_resources[] = {
+       [0] = {
+               .start  = 0xE6D00000,
+               .end    = 0xE6D01FD4 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = gic_spi(95),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device irda_device = {
+       .name           = "sh_irda",
+       .id             = 0,
+       .resource       = irda_resources,
+       .num_resources  = ARRAY_SIZE(irda_resources),
+};
+
+static unsigned char lcd_backlight_seq[3][2] = {
+       { 0x04, 0x07 },
+       { 0x23, 0x80 },
+       { 0x03, 0x01 },
+};
+
+static void lcd_backlight_on(void)
+{
+       struct i2c_adapter *a;
+       struct i2c_msg msg;
+       int k;
+
+       a = i2c_get_adapter(1);
+       for (k = 0; a && k < 3; k++) {
+               msg.addr = 0x6d;
+               msg.buf = &lcd_backlight_seq[k][0];
+               msg.len = 2;
+               msg.flags = 0;
+               if (i2c_transfer(a, &msg, 1) != 1)
+                       break;
+       }
+}
+
+static void lcd_backlight_reset(void)
+{
+       gpio_set_value(GPIO_PORT235, 0);
+       mdelay(24);
+       gpio_set_value(GPIO_PORT235, 1);
+}
+
+static void lcd_on(void *board_data, struct fb_info *info)
+{
+       lcd_backlight_on();
+}
+
+static void lcd_off(void *board_data)
+{
+       lcd_backlight_reset();
+}
+
+/* LCDC0 */
+static const struct fb_videomode lcdc0_modes[] = {
+       {
+               .name           = "R63302(QHD)",
+               .xres           = 544,
+               .yres           = 961,
+               .left_margin    = 72,
+               .right_margin   = 600,
+               .hsync_len      = 16,
+               .upper_margin   = 8,
+               .lower_margin   = 8,
+               .vsync_len      = 2,
+               .sync           = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
+       },
+};
+
+static struct sh_mobile_lcdc_info lcdc0_info = {
+       .clock_source = LCDC_CLK_PERIPHERAL,
+       .ch[0] = {
+               .chan = LCDC_CHAN_MAINLCD,
+               .interface_type = RGB24,
+               .clock_divider = 1,
+               .flags = LCDC_FLAGS_DWPOL,
+               .lcd_size_cfg.width = 44,
+               .lcd_size_cfg.height = 79,
+               .bpp = 16,
+               .lcd_cfg = lcdc0_modes,
+               .num_cfg = ARRAY_SIZE(lcdc0_modes),
+               .board_cfg = {
+                       .display_on = lcd_on,
+                       .display_off = lcd_off,
+               },
+       }
+};
+
+static struct resource lcdc0_resources[] = {
+       [0] = {
+               .name   = "LCDC0",
+               .start  = 0xfe940000, /* P4-only space */
+               .end    = 0xfe943fff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = intcs_evt2irq(0x580),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device lcdc0_device = {
+       .name           = "sh_mobile_lcdc_fb",
+       .num_resources  = ARRAY_SIZE(lcdc0_resources),
+       .resource       = lcdc0_resources,
+       .id             = 0,
+       .dev    = {
+               .platform_data  = &lcdc0_info,
+               .coherent_dma_mask = ~0,
+       },
+};
+
+/* MIPI-DSI */
+static struct resource mipidsi0_resources[] = {
+       [0] = {
+               .start  = 0xfeab0000,
+               .end    = 0xfeab3fff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 0xfeab4000,
+               .end    = 0xfeab7fff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct sh_mipi_dsi_info mipidsi0_info = {
+       .data_format    = MIPI_RGB888,
+       .lcd_chan       = &lcdc0_info.ch[0],
+       .vsynw_offset   = 20,
+       .clksrc         = 1,
+       .flags          = SH_MIPI_DSI_HSABM,
+};
+
+static struct platform_device mipidsi0_device = {
+       .name           = "sh-mipi-dsi",
+       .num_resources  = ARRAY_SIZE(mipidsi0_resources),
+       .resource       = mipidsi0_resources,
+       .id             = 0,
+       .dev    = {
+               .platform_data  = &mipidsi0_info,
+       },
+};
+
 static struct platform_device *ag5evm_devices[] __initdata = {
        &eth_device,
        &keysc_device,
        &fsi_device,
        &mmc_device,
+       &irda_device,
+       &lcdc0_device,
+       &mipidsi0_device,
 };
 
 static struct map_desc ag5evm_io_desc[] __initdata = {
@@ -224,6 +379,8 @@ void __init ag5evm_init_irq(void)
        __raw_writew(__raw_readw(PINTCR0A) | (2<<10), PINTCR0A);
 }
 
+#define DSI0PHYCR      0xe615006c
+
 static void __init ag5evm_init(void)
 {
        sh73a0_pinmux_init();
@@ -287,6 +444,26 @@ static void __init ag5evm_init(void)
        gpio_request(GPIO_FN_FSIAISLD, NULL);
        gpio_request(GPIO_FN_FSIAOSLD, NULL);
 
+       /* IrDA */
+       gpio_request(GPIO_FN_PORT241_IRDA_OUT, NULL);
+       gpio_request(GPIO_FN_PORT242_IRDA_IN,  NULL);
+       gpio_request(GPIO_FN_PORT243_IRDA_FIRSEL, NULL);
+
+       /* LCD panel */
+       gpio_request(GPIO_PORT217, NULL); /* RESET */
+       gpio_direction_output(GPIO_PORT217, 0);
+       mdelay(1);
+       gpio_set_value(GPIO_PORT217, 1);
+       mdelay(100);
+
+       /* LCD backlight controller */
+       gpio_request(GPIO_PORT235, NULL); /* RESET */
+       gpio_direction_output(GPIO_PORT235, 0);
+       lcd_backlight_reset();
+
+       /* MIPI-DSI clock setup */
+       __raw_writel(0x2a809010, DSI0PHYCR);
+
 #ifdef CONFIG_CACHE_L2X0
        /* Shared attribute override enable, 64K*8way */
        l2x0_init(__io(0xf0100000), 0x00460000, 0xc2000fff);
index 3cf0951..81d6536 100644 (file)
@@ -1303,7 +1303,7 @@ static void __init ap4evb_init(void)
 
        lcdc_info.clock_source                  = LCDC_CLK_BUS;
        lcdc_info.ch[0].interface_type          = RGB18;
-       lcdc_info.ch[0].clock_divider           = 2;
+       lcdc_info.ch[0].clock_divider           = 3;
        lcdc_info.ch[0].flags                   = 0;
        lcdc_info.ch[0].lcd_size_cfg.width      = 152;
        lcdc_info.ch[0].lcd_size_cfg.height     = 91;
index 686b304..ef4613b 100644 (file)
@@ -347,7 +347,6 @@ static void __init g3evm_init(void)
        gpio_request(GPIO_FN_IRDA_OUT, NULL);
        gpio_request(GPIO_FN_IRDA_IN, NULL);
        gpio_request(GPIO_FN_IRDA_FIRSEL, NULL);
-       set_irq_type(evt2irq(0x480), IRQ_TYPE_LEVEL_LOW);
 
        sh7367_add_standard_devices();
 
index 7b15d21..1657eac 100644 (file)
  *     SW1     |       SW33
  *             | bit1 | bit2 | bit3 | bit4
  * -------------+------+------+------+-------
- * MMC0          OFF   |  OFF |  ON  |  ON  |  X
- * MMC1          ON    |  OFF |  ON  |  X   | ON
- * SDHI1  OFF  |  ON  |   X  |  OFF | ON
+ * MMC0   OFF  |  OFF |   X  |  ON  |  X       (Use MMCIF)
+ * SDHI1  OFF  |  ON  |   X  |  OFF |  X       (Use MFD_SH_MOBILE_SDHI)
  *
  */
 
@@ -304,7 +303,7 @@ static struct sh_mobile_lcdc_info lcdc_info = {
                .lcd_cfg = mackerel_lcdc_modes,
                .num_cfg = ARRAY_SIZE(mackerel_lcdc_modes),
                .interface_type         = RGB24,
-               .clock_divider          = 2,
+               .clock_divider          = 3,
                .flags                  = 0,
                .lcd_size_cfg.width     = 152,
                .lcd_size_cfg.height    = 91,
index 9aa8d68..e9731b5 100644 (file)
@@ -234,7 +234,9 @@ static int pllc2_set_rate(struct clk *clk, unsigned long rate)
 
        value = __raw_readl(PLLC2CR) & ~(0x3f << 24);
 
-       __raw_writel((value & ~0x80000000) | ((idx + 19) << 24), PLLC2CR);
+       __raw_writel(value | ((idx + 19) << 24), PLLC2CR);
+
+       clk->rate = clk->freq_table[idx].frequency;
 
        return 0;
 }
index 720a714..7e58904 100644 (file)
@@ -118,8 +118,16 @@ static unsigned long pll_recalc(struct clk *clk)
 {
        unsigned long mult = 1;
 
-       if (__raw_readl(PLLECR) & (1 << clk->enable_bit))
+       if (__raw_readl(PLLECR) & (1 << clk->enable_bit)) {
                mult = (((__raw_readl(clk->enable_reg) >> 24) & 0x3f) + 1);
+               /* handle CFG bit for PLL1 and PLL2 */
+               switch (clk->enable_bit) {
+               case 1:
+               case 2:
+                       if (__raw_readl(clk->enable_reg) & (1 << 20))
+                               mult *= 2;
+               }
+       }
 
        return clk->parent->rate * mult;
 }
@@ -212,7 +220,7 @@ enum { DIV4_I, DIV4_ZG, DIV4_M3, DIV4_B, DIV4_M1, DIV4_M2,
 static struct clk div4_clks[DIV4_NR] = {
        [DIV4_I] = DIV4(FRQCRA, 20, 0xfff, CLK_ENABLE_ON_INIT),
        [DIV4_ZG] = DIV4(FRQCRA, 16, 0xbff, CLK_ENABLE_ON_INIT),
-       [DIV4_M3] = DIV4(FRQCRA, 8, 0xfff, CLK_ENABLE_ON_INIT),
+       [DIV4_M3] = DIV4(FRQCRA, 12, 0xfff, CLK_ENABLE_ON_INIT),
        [DIV4_B] = DIV4(FRQCRA, 8, 0xfff, CLK_ENABLE_ON_INIT),
        [DIV4_M1] = DIV4(FRQCRA, 4, 0xfff, 0),
        [DIV4_M2] = DIV4(FRQCRA, 0, 0xfff, 0),
@@ -255,10 +263,10 @@ static struct clk div6_clks[DIV6_NR] = {
 };
 
 enum { MSTP001,
-       MSTP125, MSTP116,
+       MSTP129, MSTP128, MSTP127, MSTP126, MSTP125, MSTP118, MSTP116, MSTP100,
        MSTP219,
        MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
-       MSTP331, MSTP329, MSTP323, MSTP312,
+       MSTP331, MSTP329, MSTP325, MSTP323, MSTP312,
        MSTP411, MSTP410, MSTP403,
        MSTP_NR };
 
@@ -267,8 +275,14 @@ enum { MSTP001,
 
 static struct clk mstp_clks[MSTP_NR] = {
        [MSTP001] = MSTP(&div4_clks[DIV4_HP], SMSTPCR0, 1, 0), /* IIC2 */
+       [MSTP129] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 29, 0), /* CEU1 */
+       [MSTP128] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 28, 0), /* CSI2-RX1 */
+       [MSTP127] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 27, 0), /* CEU0 */
+       [MSTP126] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 26, 0), /* CSI2-RX0 */
        [MSTP125] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 25, 0), /* TMU0 */
+       [MSTP118] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 18, 0), /* DSITX0 */
        [MSTP116] = MSTP(&div4_clks[DIV4_HP], SMSTPCR1, 16, 0), /* IIC0 */
+       [MSTP100] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 0, 0), /* LCDC0 */
        [MSTP219] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 19, 0), /* SCIFA7 */
        [MSTP207] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 7, 0), /* SCIFA5 */
        [MSTP206] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 6, 0), /* SCIFB */
@@ -279,6 +293,7 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP200] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */
        [MSTP331] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 31, 0), /* SCIFA6 */
        [MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */
+       [MSTP325] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 25, 0), /* IrDA */
        [MSTP323] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 23, 0), /* IIC1 */
        [MSTP312] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 12, 0), /* MMCIF0 */
        [MSTP411] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 11, 0), /* IIC3 */
@@ -288,16 +303,32 @@ static struct clk mstp_clks[MSTP_NR] = {
 
 #define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
 #define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk }
+#define CLKDEV_ICK_ID(_cid, _did, _clk) { .con_id = _cid, .dev_id = _did, .clk = _clk }
 
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("r_clk", &r_clk),
 
+       /* DIV6 clocks */
+       CLKDEV_CON_ID("vck1_clk", &div6_clks[DIV6_VCK1]),
+       CLKDEV_CON_ID("vck2_clk", &div6_clks[DIV6_VCK2]),
+       CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]),
+       CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSIT]),
+       CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSIT]),
+       CLKDEV_ICK_ID("dsi0p_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]),
+       CLKDEV_ICK_ID("dsi1p_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSI1P]),
+
        /* MSTP32 clocks */
        CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* I2C2 */
+       CLKDEV_DEV_ID("sh_mobile_ceu.1", &mstp_clks[MSTP129]), /* CEU1 */
+       CLKDEV_DEV_ID("sh-mobile-csi2.1", &mstp_clks[MSTP128]), /* CSI2-RX1 */
+       CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[MSTP127]), /* CEU0 */
+       CLKDEV_DEV_ID("sh-mobile-csi2.0", &mstp_clks[MSTP126]), /* CSI2-RX0 */
        CLKDEV_DEV_ID("sh_tmu.0", &mstp_clks[MSTP125]), /* TMU00 */
        CLKDEV_DEV_ID("sh_tmu.1", &mstp_clks[MSTP125]), /* TMU01 */
+       CLKDEV_DEV_ID("sh-mipi-dsi.0", &mstp_clks[MSTP118]), /* DSITX */
        CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* I2C0 */
+       CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[MSTP100]), /* LCDC0 */
        CLKDEV_DEV_ID("sh-sci.7", &mstp_clks[MSTP219]), /* SCIFA7 */
        CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), /* SCIFA5 */
        CLKDEV_DEV_ID("sh-sci.8", &mstp_clks[MSTP206]), /* SCIFB */
@@ -308,6 +339,7 @@ static struct clk_lookup lookups[] = {
        CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */
        CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP331]), /* SCIFA6 */
        CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */
+       CLKDEV_DEV_ID("sh_irda.0", &mstp_clks[MSTP325]), /* IrDA */
        CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* I2C1 */
        CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMCIF0 */
        CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* I2C3 */
index efd3687..3029aba 100644 (file)
@@ -6,13 +6,10 @@ LIST "RWT Setting"
 EW 0xE6020004, 0xA500
 EW 0xE6030004, 0xA500
 
-DD 0x01001000, 0x01001000
-
 LIST "GPIO Setting"
 EB 0xE6051013, 0xA2
 
 LIST "CPG"
-ED 0xE6150080, 0x00000180
 ED 0xE61500C0, 0x00000002
 
 WAIT 1, 0xFE40009C
@@ -37,6 +34,9 @@ ED 0xE615002C, 0x93000040
 
 WAIT 1, 0xFE40009C
 
+LIST "SUB/USBClk"
+ED 0xE6150080, 0x00000180
+
 LIST "BSC"
 ED 0xFEC10000, 0x00E0001B
 
@@ -53,7 +53,7 @@ ED 0xFE400048, 0x20C18505
 ED 0xFE40004C, 0x00110209
 ED 0xFE400010, 0x00000087
 
-WAIT 10, 0xFE40009C
+WAIT 30, 0xFE40009C
 
 ED 0xFE400084, 0x0000003F
 EB 0xFE500000, 0x00
@@ -84,7 +84,7 @@ ED 0xE6150004, 0x80331050
 
 WAIT 1, 0xFE40009C
 
-ED 0xE6150354, 0x00000002
+ED 0xFE400354, 0x01AD8002
 
 LIST "SCIF0 - Serial port for earlyprintk"
 EB 0xE6053098, 0x11
index efd3687..3029aba 100644 (file)
@@ -6,13 +6,10 @@ LIST "RWT Setting"
 EW 0xE6020004, 0xA500
 EW 0xE6030004, 0xA500
 
-DD 0x01001000, 0x01001000
-
 LIST "GPIO Setting"
 EB 0xE6051013, 0xA2
 
 LIST "CPG"
-ED 0xE6150080, 0x00000180
 ED 0xE61500C0, 0x00000002
 
 WAIT 1, 0xFE40009C
@@ -37,6 +34,9 @@ ED 0xE615002C, 0x93000040
 
 WAIT 1, 0xFE40009C
 
+LIST "SUB/USBClk"
+ED 0xE6150080, 0x00000180
+
 LIST "BSC"
 ED 0xFEC10000, 0x00E0001B
 
@@ -53,7 +53,7 @@ ED 0xFE400048, 0x20C18505
 ED 0xFE40004C, 0x00110209
 ED 0xFE400010, 0x00000087
 
-WAIT 10, 0xFE40009C
+WAIT 30, 0xFE40009C
 
 ED 0xFE400084, 0x0000003F
 EB 0xFE500000, 0x00
@@ -84,7 +84,7 @@ ED 0xE6150004, 0x80331050
 
 WAIT 1, 0xFE40009C
 
-ED 0xE6150354, 0x00000002
+ED 0xFE400354, 0x01AD8002
 
 LIST "SCIF0 - Serial port for earlyprintk"
 EB 0xE6053098, 0x11
index f78a1ea..ca5f9d1 100644 (file)
@@ -365,6 +365,7 @@ static struct intc_desc intca_desc __initdata = {
 
 enum {
        UNUSED_INTCS = 0,
+       ENABLED_INTCS,
 
        INTCS,
 
@@ -413,7 +414,7 @@ enum {
        CMT4,
        DSITX1_DSITX1_0,
        DSITX1_DSITX1_1,
-       /* MFIS2 */
+       MFIS2_INTCS, /* Priority always enabled using ENABLED_INTCS */
        CPORTS2R,
        /* CEC */
        JPU6E,
@@ -477,7 +478,7 @@ static struct intc_vect intcs_vectors[] = {
        INTCS_VECT(CMT4, 0x1980),
        INTCS_VECT(DSITX1_DSITX1_0, 0x19a0),
        INTCS_VECT(DSITX1_DSITX1_1, 0x19c0),
-       /* MFIS2 */
+       INTCS_VECT(MFIS2_INTCS, 0x1a00),
        INTCS_VECT(CPORTS2R, 0x1a20),
        /* CEC */
        INTCS_VECT(JPU6E, 0x1a80),
@@ -543,7 +544,7 @@ static struct intc_mask_reg intcs_mask_registers[] = {
          { 0, TMU1_TUNI2, TMU1_TUNI1, TMU1_TUNI0,
            CMT4, DSITX1_DSITX1_0, DSITX1_DSITX1_1, 0 } },
        { 0xffd5019c, 0xffd501dc, 8, /* IMR7SA3 / IMCR7SA3 */
-         { 0, CPORTS2R, 0, 0,
+         { MFIS2_INTCS, CPORTS2R, 0, 0,
            JPU6E, 0, 0, 0 } },
        { 0xffd20104, 0, 16, /* INTAMASK */
          { 0, 0, 0, 0, 0, 0, 0, 0,
@@ -571,7 +572,8 @@ static struct intc_prio_reg intcs_prio_registers[] = {
        { 0xffd50030, 0, 16, 4, /* IPRMS3 */ { TMU1, 0, 0, 0 } },
        { 0xffd50034, 0, 16, 4, /* IPRNS3 */ { CMT4, DSITX1_DSITX1_0,
                                               DSITX1_DSITX1_1, 0 } },
-       { 0xffd50038, 0, 16, 4, /* IPROS3 */ { 0, CPORTS2R, 0, 0 } },
+       { 0xffd50038, 0, 16, 4, /* IPROS3 */ { ENABLED_INTCS, CPORTS2R,
+                                              0, 0 } },
        { 0xffd5003c, 0, 16, 4, /* IPRPS3 */ { JPU6E, 0, 0, 0 } },
 };
 
@@ -590,6 +592,7 @@ static struct resource intcs_resources[] __initdata = {
 
 static struct intc_desc intcs_desc __initdata = {
        .name = "sh7372-intcs",
+       .force_enable = ENABLED_INTCS,
        .resource = intcs_resources,
        .num_resources = ARRAY_SIZE(intcs_resources),
        .hw = INTC_HW_DESC(intcs_vectors, intcs_groups, intcs_mask_registers,
index 322d8d5..5d0e150 100644 (file)
@@ -252,10 +252,11 @@ static irqreturn_t sh73a0_intcs_demux(int irq, void *dev_id)
 
 void __init sh73a0_init_irq(void)
 {
-       void __iomem *gic_base = __io(0xf0001000);
+       void __iomem *gic_dist_base = __io(0xf0001000);
+       void __iomem *gic_cpu_base = __io(0xf0000100);
        void __iomem *intevtsa = ioremap_nocache(0xffd20100, PAGE_SIZE);
 
-       gic_init(0, 29, gic_base, gic_base);
+       gic_init(0, 29, gic_dist_base, gic_cpu_base);
 
        register_intc_controller(&intcs_desc);
 
index cacf17a..53677e4 100644 (file)
@@ -62,7 +62,7 @@
 #define SPEAR320_SMII1_BASE            0xAB000000
 #define SPEAR320_SMII1_SIZE            0x01000000
 
-#define SPEAR320_SOC_CONFIG_BASE       0xB4000000
+#define SPEAR320_SOC_CONFIG_BASE       0xB3000000
 #define SPEAR320_SOC_CONFIG_SIZE       0x00000070
 /* Interrupt registers offsets and masks */
 #define INT_STS_MASK_REG               0x04
index bd06620..ad80488 100644 (file)
@@ -207,9 +207,9 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
        spin_unlock_irqrestore(&bank->lvl_lock[port], flags);
 
        if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
-               __set_irq_handler_unlocked(irq, handle_level_irq);
+               __set_irq_handler_unlocked(d->irq, handle_level_irq);
        else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
-               __set_irq_handler_unlocked(irq, handle_edge_irq);
+               __set_irq_handler_unlocked(d->irq, handle_edge_irq);
 
        return 0;
 }
index d772395..a217f68 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef __MACH_CLK_H
 #define __MACH_CLK_H
 
+struct clk;
+
 void tegra_periph_reset_deassert(struct clk *c);
 void tegra_periph_reset_assert(struct clk *c);
 
index 412f5c6..66cd3f4 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef __MACH_CLKDEV_H
 #define __MACH_CLKDEV_H
 
+struct clk;
+
 static inline int __clk_get(struct clk *clk)
 {
        return 1;
diff --git a/arch/arm/mach-tegra/include/mach/kbc.h b/arch/arm/mach-tegra/include/mach/kbc.h
new file mode 100644 (file)
index 0000000..04c7798
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Platform definitions for tegra-kbc keyboard input driver
+ *
+ * Copyright (c) 2010-2011, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef ASMARM_ARCH_TEGRA_KBC_H
+#define ASMARM_ARCH_TEGRA_KBC_H
+
+#include <linux/types.h>
+#include <linux/input/matrix_keypad.h>
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+#define KBC_MAX_GPIO   24
+#define KBC_MAX_KPENT  8
+#else
+#define KBC_MAX_GPIO   20
+#define KBC_MAX_KPENT  7
+#endif
+
+#define KBC_MAX_ROW    16
+#define KBC_MAX_COL    8
+#define KBC_MAX_KEY    (KBC_MAX_ROW * KBC_MAX_COL)
+
+struct tegra_kbc_pin_cfg {
+       bool is_row;
+       unsigned char num;
+};
+
+struct tegra_kbc_wake_key {
+       u8 row:4;
+       u8 col:4;
+};
+
+struct tegra_kbc_platform_data {
+       unsigned int debounce_cnt;
+       unsigned int repeat_cnt;
+
+       unsigned int wake_cnt; /* 0:wake on any key >1:wake on wake_cfg */
+       const struct tegra_kbc_wake_key *wake_cfg;
+
+       struct tegra_kbc_pin_cfg pin_cfg[KBC_MAX_GPIO];
+       const struct matrix_keymap_data *keymap_data;
+
+       bool wakeup;
+       bool use_fn_map;
+};
+#endif
index de7dfad..17c74d2 100644 (file)
 #define ICTLR_COP_IER_CLR      0x38
 #define ICTLR_COP_IEP_CLASS    0x3c
 
-static void (*gic_mask_irq)(struct irq_data *d);
-static void (*gic_unmask_irq)(struct irq_data *d);
+static void (*tegra_gic_mask_irq)(struct irq_data *d);
+static void (*tegra_gic_unmask_irq)(struct irq_data *d);
 
-#define irq_to_ictlr(irq) (((irq)-32) >> 5)
+#define irq_to_ictlr(irq) (((irq) - 32) >> 5)
 static void __iomem *tegra_ictlr_base = IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE);
-#define ictlr_to_virt(ictlr) (tegra_ictlr_base + (ictlr)*0x100)
+#define ictlr_to_virt(ictlr) (tegra_ictlr_base + (ictlr) * 0x100)
 
 static void tegra_mask(struct irq_data *d)
 {
        void __iomem *addr = ictlr_to_virt(irq_to_ictlr(d->irq));
-       gic_mask_irq(d);
-       writel(1<<(d->irq&31), addr+ICTLR_CPU_IER_CLR);
+       tegra_gic_mask_irq(d);
+       writel(1 << (d->irq & 31), addr+ICTLR_CPU_IER_CLR);
 }
 
 static void tegra_unmask(struct irq_data *d)
 {
        void __iomem *addr = ictlr_to_virt(irq_to_ictlr(d->irq));
-       gic_unmask_irq(d);
+       tegra_gic_unmask_irq(d);
        writel(1<<(d->irq&31), addr+ICTLR_CPU_IER_SET);
 }
 
@@ -98,8 +98,8 @@ void __init tegra_init_irq(void)
                 IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100));
 
        gic = get_irq_chip(29);
-       gic_unmask_irq = gic->irq_unmask;
-       gic_mask_irq = gic->irq_mask;
+       tegra_gic_unmask_irq = gic->irq_unmask;
+       tegra_gic_mask_irq = gic->irq_mask;
        tegra_irq.irq_ack = gic->irq_ack;
 #ifdef CONFIG_SMP
        tegra_irq.irq_set_affinity = gic->irq_set_affinity;
index 3f7b5e9..9cdec5a 100644 (file)
@@ -2,17 +2,19 @@ menu "Versatile platform type"
        depends on ARCH_VERSATILE
 
 config ARCH_VERSATILE_PB
-       bool "Support Versatile/PB platform"
+       bool "Support Versatile Platform Baseboard for ARM926EJ-S"
        select CPU_ARM926T
        select MIGHT_HAVE_PCI
        default y
        help
-         Include support for the ARM(R) Versatile/PB platform.
+         Include support for the ARM(R) Versatile Platform Baseboard
+         for the ARM926EJ-S.
 
 config MACH_VERSATILE_AB
-       bool "Support Versatile/AB platform"
+       bool "Support Versatile Application Baseboard for ARM926EJ-S"
        select CPU_ARM926T
        help
-         Include support for the ARM(R) Versatile/AP platform.
+         Include support for the ARM(R) Versatile Application Baseboard
+         for the ARM926EJ-S.
 
 endmenu
index b1687b6..634bf1d 100644 (file)
@@ -39,7 +39,7 @@ volatile int __cpuinitdata pen_release = -1;
  * observers, irrespective of whether they're taking part in coherency
  * or not.  This is necessary for the hotplug code to work reliably.
  */
-static void write_pen_release(int val)
+static void __cpuinit write_pen_release(int val)
 {
        pen_release = val;
        smp_wmb();
index a9ed342..1edae65 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/mach/time.h>
 #include <asm/hardware/arm_timer.h>
 #include <asm/hardware/timer-sp.h>
+#include <asm/hardware/sp810.h>
 
 #include <mach/motherboard.h>
 
@@ -50,8 +51,16 @@ void __init v2m_map_io(struct map_desc *tile, size_t num)
 
 static void __init v2m_timer_init(void)
 {
+       u32 scctrl;
+
        versatile_sched_clock_init(MMIO_P2V(V2M_SYS_24MHZ), 24000000);
 
+       /* Select 1MHz TIMCLK as the reference clock for SP804 timers */
+       scctrl = readl(MMIO_P2V(V2M_SYSCTL + SCCTRL));
+       scctrl |= SCCTRL_TIMEREN0SEL_TIMCLK;
+       scctrl |= SCCTRL_TIMEREN1SEL_TIMCLK;
+       writel(scctrl, MMIO_P2V(V2M_SYSCTL + SCCTRL));
+
        writel(0, MMIO_P2V(V2M_TIMER0) + TIMER_CTRL);
        writel(0, MMIO_P2V(V2M_TIMER1) + TIMER_CTRL);
 
index 9d30c6f..e4509ba 100644 (file)
@@ -405,7 +405,7 @@ config CPU_V6
 config CPU_32v6K
        bool "Support ARM V6K processor extensions" if !SMP
        depends on CPU_V6 || CPU_V7
-       default y if SMP && !(ARCH_MX3 || ARCH_OMAP2)
+       default y if SMP
        help
          Say Y here if your ARMv6 processor supports the 'K' extension.
          This enables the kernel to use some instructions not present
@@ -416,7 +416,7 @@ config CPU_32v6K
 # ARMv7
 config CPU_V7
        bool "Support ARM V7 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX
-       select CPU_32v6K if !ARCH_OMAP2
+       select CPU_32v6K
        select CPU_32v7
        select CPU_ABRT_EV7
        select CPU_PABRT_V7
@@ -644,7 +644,7 @@ config ARM_THUMBEE
 
 config SWP_EMULATE
        bool "Emulate SWP/SWPB instructions"
-       depends on CPU_V7 && !CPU_V6
+       depends on !CPU_USE_DOMAINS && CPU_V7 && !CPU_V6
        select HAVE_PROC_CPU if PROC_FS
        default y if SMP
        help
index 170c9bb..f2ce38e 100644 (file)
@@ -49,7 +49,13 @@ static inline void cache_wait(void __iomem *reg, unsigned long mask)
 static inline void cache_sync(void)
 {
        void __iomem *base = l2x0_base;
+
+#ifdef CONFIG_ARM_ERRATA_753970
+       /* write to an unmmapped register */
+       writel_relaxed(0, base + L2X0_DUMMY_REG);
+#else
        writel_relaxed(0, base + L2X0_CACHE_SYNC);
+#endif
        cache_wait(base + L2X0_CACHE_SYNC, 1);
 }
 
index 5164069..cddd684 100644 (file)
@@ -297,6 +297,12 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
        memblock_reserve(__pa(_stext), _end - _stext);
 #endif
 #ifdef CONFIG_BLK_DEV_INITRD
+       if (phys_initrd_size &&
+           memblock_is_region_reserved(phys_initrd_start, phys_initrd_size)) {
+               pr_err("INITRD: 0x%08lx+0x%08lx overlaps in-use memory region - disabling initrd\n",
+                      phys_initrd_start, phys_initrd_size);
+               phys_initrd_start = phys_initrd_size = 0;
+       }
        if (phys_initrd_size) {
                memblock_reserve(phys_initrd_start, phys_initrd_size);
 
index 0c1172b..8e33562 100644 (file)
@@ -264,6 +264,12 @@ __v7_setup:
        orreq   r10, r10, #1 << 6               @ set bit #6
        mcreq   p15, 0, r10, c15, c0, 1         @ write diagnostic register
 #endif
+#ifdef CONFIG_ARM_ERRATA_751472
+       cmp     r6, #0x30                       @ present prior to r3p0
+       mrclt   p15, 0, r10, c15, c0, 1         @ read diagnostic register
+       orrlt   r10, r10, #1 << 11              @ set bit #11
+       mcrlt   p15, 0, r10, c15, c0, 1         @ write diagnostic register
+#endif
 
 3:     mov     r10, #0
 #ifdef HARVARD_CACHE
index 8aa9744..c074e66 100644 (file)
@@ -10,8 +10,6 @@
  */
 
 #include <linux/cpumask.h>
-#include <linux/err.h>
-#include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/mutex.h>
 #include <linux/oprofile.h>
@@ -46,6 +44,7 @@ char *op_name_from_perf_id(void)
                return NULL;
        }
 }
+#endif
 
 static int report_trace(struct stackframe *frame, void *d)
 {
@@ -85,7 +84,7 @@ static struct frame_tail* user_backtrace(struct frame_tail *tail)
 
        /* frame pointers should strictly progress back up the stack
         * (towards higher addresses) */
-       if (tail >= buftail[0].fp)
+       if (tail + 1 >= buftail[0].fp)
                return NULL;
 
        return buftail[0].fp-1;
@@ -111,6 +110,7 @@ static void arm_backtrace(struct pt_regs * const regs, unsigned int depth)
 
 int __init oprofile_arch_init(struct oprofile_operations *ops)
 {
+       /* provide backtrace support also in timer mode: */
        ops->backtrace          = arm_backtrace;
 
        return oprofile_perf_init(ops);
@@ -120,11 +120,3 @@ void __exit oprofile_arch_exit(void)
 {
        oprofile_perf_exit();
 }
-#else
-int __init oprofile_arch_init(struct oprofile_operations *ops)
-{
-       pr_info("oprofile: hardware counters not available\n");
-       return -ENODEV;
-}
-void __exit oprofile_arch_exit(void) {}
-#endif /* CONFIG_HW_PERF_EVENTS */
index 3a70ebf..ff469c4 100644 (file)
@@ -95,6 +95,7 @@ static __inline__ void __arch_decomp_setup(unsigned long arch_id)
        case MACH_TYPE_MX35_3DS:
        case MACH_TYPE_PCM043:
        case MACH_TYPE_LILLY1131:
+       case MACH_TYPE_VPR200:
                uart_base = MX3X_UART1_BASE_ADDR;
                break;
        case MACH_TYPE_MAGX_ZN5:
@@ -102,6 +103,7 @@ static __inline__ void __arch_decomp_setup(unsigned long arch_id)
                break;
        case MACH_TYPE_MX51_BABBAGE:
        case MACH_TYPE_EUKREA_CPUIMX51SD:
+       case MACH_TYPE_MX51_3DS:
                uart_base = MX51_UART1_BASE_ADDR;
                break;
        case MACH_TYPE_MX50_RDP:
index 459b319..69ddc9f 100644 (file)
@@ -32,7 +32,6 @@
 
 #include <plat/mailbox.h>
 
-static struct workqueue_struct *mboxd;
 static struct omap_mbox **mboxes;
 
 static int mbox_configured;
@@ -197,7 +196,7 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox)
        /* no more messages in the fifo. clear IRQ source. */
        ack_mbox_irq(mbox, IRQ_RX);
 nomem:
-       queue_work(mboxd, &mbox->rxq->work);
+       schedule_work(&mbox->rxq->work);
 }
 
 static irqreturn_t mbox_interrupt(int irq, void *p)
@@ -307,7 +306,7 @@ static void omap_mbox_fini(struct omap_mbox *mbox)
        if (!--mbox->use_count) {
                free_irq(mbox->irq, mbox);
                tasklet_kill(&mbox->txq->tasklet);
-               flush_work(&mbox->rxq->work);
+       flush_work_sync(&mbox->rxq->work);
                mbox_queue_free(mbox->txq);
                mbox_queue_free(mbox->rxq);
        }
@@ -322,15 +321,18 @@ static void omap_mbox_fini(struct omap_mbox *mbox)
 
 struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb)
 {
-       struct omap_mbox *mbox;
-       int ret;
+       struct omap_mbox *_mbox, *mbox = NULL;
+       int i, ret;
 
        if (!mboxes)
                return ERR_PTR(-EINVAL);
 
-       for (mbox = *mboxes; mbox; mbox++)
-               if (!strcmp(mbox->name, name))
+       for (i = 0; (_mbox = mboxes[i]); i++) {
+               if (!strcmp(_mbox->name, name)) {
+                       mbox = _mbox;
                        break;
+               }
+       }
 
        if (!mbox)
                return ERR_PTR(-ENOENT);
@@ -406,10 +408,6 @@ static int __init omap_mbox_init(void)
        if (err)
                return err;
 
-       mboxd = create_workqueue("mboxd");
-       if (!mboxd)
-               return -ENOMEM;
-
        /* kfifo size sanity check: alignment and minimal size */
        mbox_kfifo_size = ALIGN(mbox_kfifo_size, sizeof(mbox_msg_t));
        mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size,
@@ -421,7 +419,6 @@ subsys_initcall(omap_mbox_init);
 
 static void __exit omap_mbox_exit(void)
 {
-       destroy_workqueue(mboxd);
        class_unregister(&omap_mbox_class);
 }
 module_exit(omap_mbox_exit);
index b77e018..a9aa5ad 100644 (file)
@@ -139,10 +139,11 @@ static const unsigned long mfpr_edge[] = {
 #define mfp_configured(p)      ((p)->config != -1)
 
 /*
- * perform a read-back of any MFPR register to make sure the
+ * perform a read-back of any valid MFPR register to make sure the
  * previous writings are finished
  */
-#define mfpr_sync()    (void)__raw_readl(mfpr_mmio_base + 0)
+static unsigned long mfpr_off_readback;
+#define mfpr_sync()    (void)__raw_readl(mfpr_mmio_base + mfpr_off_readback)
 
 static inline void __mfp_config_run(struct mfp_pin *p)
 {
@@ -248,6 +249,9 @@ void __init mfp_init_addr(struct mfp_addr_map *map)
 
        spin_lock_irqsave(&mfp_spin_lock, flags);
 
+       /* mfp offset for readback */
+       mfpr_off_readback = map[0].offset;
+
        for (p = map; p->start != MFP_PIN_INVALID; p++) {
                offset = p->offset;
                i = p->start;
index deb3995..557f8c5 100644 (file)
@@ -37,6 +37,14 @@ config S5P_GPIO_INT
        help
          Common code for the GPIO interrupts (other than external interrupts.)
 
+comment "System MMU"
+
+config S5P_SYSTEM_MMU
+       bool "S5P SYSTEM MMU"
+       depends on ARCH_S5PV310
+       help
+         Say Y here if you want to enable System MMU
+
 config S5P_DEV_FIMC0
        bool
        help
@@ -66,19 +74,3 @@ config S5P_DEV_CSIS1
        bool
        help
          Compile in platform device definitions for MIPI-CSIS channel 1
-
-menuconfig S5P_SYSMMU
-       bool "SYSMMU support"
-       depends on ARCH_S5PV310
-       help
-         This is a System MMU driver for Samsung ARM based Soc.
-
-if S5P_SYSMMU
-
-config S5P_SYSMMU_DEBUG
-       bool "Enables debug messages"
-       depends on S5P_SYSMMU
-       help
-         This enables SYSMMU driver debug massages.
-
-endif
index 92efe1a..4bd5cf9 100644 (file)
@@ -19,6 +19,7 @@ obj-y                         += clock.o
 obj-y                          += irq.o
 obj-$(CONFIG_S5P_EXT_INT)      += irq-eint.o
 obj-$(CONFIG_S5P_GPIO_INT)     += irq-gpioint.o
+obj-$(CONFIG_S5P_SYSTEM_MMU)   += sysmmu.o
 obj-$(CONFIG_PM)               += pm.o
 obj-$(CONFIG_PM)               += irq-pm.o
 
@@ -30,4 +31,3 @@ obj-$(CONFIG_S5P_DEV_FIMC2)   += dev-fimc2.o
 obj-$(CONFIG_S5P_DEV_ONENAND)  += dev-onenand.o
 obj-$(CONFIG_S5P_DEV_CSIS0)    += dev-csis0.o
 obj-$(CONFIG_S5P_DEV_CSIS1)    += dev-csis1.o
-obj-$(CONFIG_S5P_SYSMMU)       += sysmmu.o
index 6a73428..afaf87f 100644 (file)
@@ -28,7 +28,7 @@
 static struct resource s5p_uart0_resource[] = {
        [0] = {
                .start  = S5P_PA_UART0,
-               .end    = S5P_PA_UART0 + S5P_SZ_UART,
+               .end    = S5P_PA_UART0 + S5P_SZ_UART - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -51,7 +51,7 @@ static struct resource s5p_uart0_resource[] = {
 static struct resource s5p_uart1_resource[] = {
        [0] = {
                .start  = S5P_PA_UART1,
-               .end    = S5P_PA_UART1 + S5P_SZ_UART,
+               .end    = S5P_PA_UART1 + S5P_SZ_UART - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -74,7 +74,7 @@ static struct resource s5p_uart1_resource[] = {
 static struct resource s5p_uart2_resource[] = {
        [0] = {
                .start  = S5P_PA_UART2,
-               .end    = S5P_PA_UART2 + S5P_SZ_UART,
+               .end    = S5P_PA_UART2 + S5P_SZ_UART - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -98,7 +98,7 @@ static struct resource s5p_uart3_resource[] = {
 #if CONFIG_SERIAL_SAMSUNG_UARTS > 3
        [0] = {
                .start  = S5P_PA_UART3,
-               .end    = S5P_PA_UART3 + S5P_SZ_UART,
+               .end    = S5P_PA_UART3 + S5P_SZ_UART - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -123,7 +123,7 @@ static struct resource s5p_uart4_resource[] = {
 #if CONFIG_SERIAL_SAMSUNG_UARTS > 4
        [0] = {
                .start  = S5P_PA_UART4,
-               .end    = S5P_PA_UART4 + S5P_SZ_UART,
+               .end    = S5P_PA_UART4 + S5P_SZ_UART - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -148,7 +148,7 @@ static struct resource s5p_uart5_resource[] = {
 #if CONFIG_SERIAL_SAMSUNG_UARTS > 5
        [0] = {
                .start  = S5P_PA_UART5,
-               .end    = S5P_PA_UART5 + S5P_SZ_UART,
+               .end    = S5P_PA_UART5 + S5P_SZ_UART - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
diff --git a/arch/arm/plat-s5p/include/plat/sysmmu.h b/arch/arm/plat-s5p/include/plat/sysmmu.h
deleted file mode 100644 (file)
index db298fc..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/* linux/arch/arm/plat-s5p/include/plat/sysmmu.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * Samsung sysmmu driver
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_PLAT_S5P_SYSMMU_H
-#define __ASM_PLAT_S5P_SYSMMU_H __FILE__
-
-/* debug macro */
-#ifdef CONFIG_S5P_SYSMMU_DEBUG
-#define sysmmu_debug(fmt, arg...)      printk(KERN_INFO "[%s] " fmt, __func__, ## arg)
-#else
-#define sysmmu_debug(fmt, arg...)      do { } while (0)
-#endif
-
-#endif /* __ASM_PLAT_S5P_SYSMMU_H */
index d804914..ffe8a48 100644 (file)
@@ -16,8 +16,6 @@
 #include <mach/regs-sysmmu.h>
 #include <mach/sysmmu.h>
 
-#include <plat/sysmmu.h>
-
 struct sysmmu_controller s5p_sysmmu_cntlrs[S5P_SYSMMU_TOTAL_IPNUM];
 
 void s5p_sysmmu_register(struct sysmmu_controller *sysmmuconp)
@@ -123,7 +121,7 @@ static int s5p_sysmmu_set_tablebase(sysmmu_ips ips)
                : "=r" (pg) : : "cc");          \
                pg &= ~0x3fff;
 
-       sysmmu_debug("CP15 TTBR0 : 0x%x\n", pg);
+       printk(KERN_INFO "%s: CP15 TTBR0 : 0x%x\n", __func__, pg);
 
        /* Set sysmmu page table base address */
        __raw_writel(pg, sysmmuconp->regs + S5P_PT_BASE_ADDR);
index 236ef84..3e4bd81 100644 (file)
@@ -58,4 +58,3 @@ void __init s3c24xx_ts_set_platdata(struct s3c2410_ts_mach_info *pd)
 
        s3c_device_ts.dev.platform_data = npd;
 }
-EXPORT_SYMBOL(s3c24xx_ts_set_platdata);
index 3776cd9..5928105 100644 (file)
@@ -15,6 +15,8 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 
+#include <plat/devs.h>
+
 /* uart devices */
 
 static struct platform_device s3c24xx_uart_device0 = {
index d9025e3..30518cc 100644 (file)
@@ -17,6 +17,8 @@
 
 #include <linux/irq.h>
 
+struct sys_device;
+
 #ifdef CONFIG_PM
 
 extern __init int s3c_pm_init(void);
index 99ba678..6dd455b 100644 (file)
@@ -24,10 +24,10 @@ static inline void putc(int c)
 {
        void __iomem *base = (void __iomem *)SPEAR_DBG_UART_BASE;
 
-       while (readl(base + UART01x_FR) & UART01x_FR_TXFF)
+       while (readl_relaxed(base + UART01x_FR) & UART01x_FR_TXFF)
                barrier();
 
-       writel(c, base + UART01x_DR);
+       writel_relaxed(c, base + UART01x_DR);
 }
 
 static inline void flush(void)
index 09e9372..8c8b24d 100644 (file)
@@ -14,6 +14,6 @@
 #ifndef __PLAT_VMALLOC_H
 #define __PLAT_VMALLOC_H
 
-#define VMALLOC_END            0xF0000000
+#define VMALLOC_END            0xF0000000UL
 
 #endif /* __PLAT_VMALLOC_H */
index 2fea897..9d6feaa 100644 (file)
@@ -12,7 +12,7 @@
 #
 #   http://www.arm.linux.org.uk/developer/machines/?action=new
 #
-# Last update: Sun Dec 12 23:24:27 2010
+# Last update: Mon Feb 7 08:59:27 2011
 #
 # machine_is_xxx       CONFIG_xxxx             MACH_TYPE_xxx           number
 #
@@ -2240,7 +2240,7 @@ arm_ultimator2            MACH_ARM_ULTIMATOR2     ARM_ULTIMATOR2          2250
 vs_v210                        MACH_VS_V210            VS_V210                 2252
 vs_v212                        MACH_VS_V212            VS_V212                 2253
 hmt                    MACH_HMT                HMT                     2254
-suen3                  MACH_SUEN3              SUEN3                   2255
+km_kirkwood            MACH_KM_KIRKWOOD        KM_KIRKWOOD             2255
 vesper                 MACH_VESPER             VESPER                  2256
 str9                   MACH_STR9               STR9                    2257
 omap3_wl_ff            MACH_OMAP3_WL_FF        OMAP3_WL_FF             2258
@@ -2987,7 +2987,7 @@ pxwnas_500_1000           MACH_PXWNAS_500_1000    PXWNAS_500_1000         3001
 ea20                   MACH_EA20               EA20                    3002
 awm2                   MACH_AWM2               AWM2                    3003
 ti8148evm              MACH_TI8148EVM          TI8148EVM               3004
-tegra_seaboard         MACH_TEGRA_SEABOARD     TEGRA_SEABOARD          3005
+seaboard               MACH_SEABOARD           SEABOARD                3005
 linkstation_chlv2      MACH_LINKSTATION_CHLV2  LINKSTATION_CHLV2       3006
 tera_pro2_rack         MACH_TERA_PRO2_RACK     TERA_PRO2_RACK          3007
 rubys                  MACH_RUBYS              RUBYS                   3008
@@ -3190,7 +3190,7 @@ synergy                   MACH_SYNERGY            SYNERGY                 3205
 ics_if_voip            MACH_ICS_IF_VOIP        ICS_IF_VOIP             3206
 wlf_cragg_6410         MACH_WLF_CRAGG_6410     WLF_CRAGG_6410          3207
 punica                 MACH_PUNICA             PUNICA                  3208
-sbc_nt250              MACH_SBC_NT250          SBC_NT250               3209
+trimslice              MACH_TRIMSLICE          TRIMSLICE               3209
 mx27_wmultra           MACH_MX27_WMULTRA       MX27_WMULTRA            3210
 mackerel               MACH_MACKEREL           MACKEREL                3211
 fa9x27                 MACH_FA9X27             FA9X27                  3213
@@ -3219,3 +3219,100 @@ pivicc                  MACH_PIVICC             PIVICC                  3235
 pcm048                 MACH_PCM048             PCM048                  3236
 dds                    MACH_DDS                DDS                     3237
 chalten_xa1            MACH_CHALTEN_XA1        CHALTEN_XA1             3238
+ts48xx                 MACH_TS48XX             TS48XX                  3239
+tonga2_tfttimer                MACH_TONGA2_TFTTIMER    TONGA2_TFTTIMER         3240
+whistler               MACH_WHISTLER           WHISTLER                3241
+asl_phoenix            MACH_ASL_PHOENIX        ASL_PHOENIX             3242
+at91sam9263otlite      MACH_AT91SAM9263OTLITE  AT91SAM9263OTLITE       3243
+ddplug                 MACH_DDPLUG             DDPLUG                  3244
+d2plug                 MACH_D2PLUG             D2PLUG                  3245
+kzm9d                  MACH_KZM9D              KZM9D                   3246
+verdi_lte              MACH_VERDI_LTE          VERDI_LTE               3247
+nanozoom               MACH_NANOZOOM           NANOZOOM                3248
+dm3730_som_lv          MACH_DM3730_SOM_LV      DM3730_SOM_LV           3249
+dm3730_torpedo         MACH_DM3730_TORPEDO     DM3730_TORPEDO          3250
+anchovy                        MACH_ANCHOVY            ANCHOVY                 3251
+re2rev20               MACH_RE2REV20           RE2REV20                3253
+re2rev21               MACH_RE2REV21           RE2REV21                3254
+cns21xx                        MACH_CNS21XX            CNS21XX                 3255
+rider                  MACH_RIDER              RIDER                   3257
+nsk330                 MACH_NSK330             NSK330                  3258
+cns2133evb             MACH_CNS2133EVB         CNS2133EVB              3259
+z3_816x_mod            MACH_Z3_816X_MOD        Z3_816X_MOD             3260
+z3_814x_mod            MACH_Z3_814X_MOD        Z3_814X_MOD             3261
+beect                  MACH_BEECT              BEECT                   3262
+dma_thunderbug         MACH_DMA_THUNDERBUG     DMA_THUNDERBUG          3263
+omn_at91sam9g20                MACH_OMN_AT91SAM9G20    OMN_AT91SAM9G20         3264
+mx25_e2s_uc            MACH_MX25_E2S_UC        MX25_E2S_UC             3265
+mione                  MACH_MIONE              MIONE                   3266
+top9000_tcu            MACH_TOP9000_TCU        TOP9000_TCU             3267
+top9000_bsl            MACH_TOP9000_BSL        TOP9000_BSL             3268
+kingdom                        MACH_KINGDOM            KINGDOM                 3269
+armadillo460           MACH_ARMADILLO460       ARMADILLO460            3270
+lq2                    MACH_LQ2                LQ2                     3271
+sweda_tms2             MACH_SWEDA_TMS2         SWEDA_TMS2              3272
+mx53_loco              MACH_MX53_LOCO          MX53_LOCO               3273
+acer_a8                        MACH_ACER_A8            ACER_A8                 3275
+acer_gauguin           MACH_ACER_GAUGUIN       ACER_GAUGUIN            3276
+guppy                  MACH_GUPPY              GUPPY                   3277
+mx61_ard               MACH_MX61_ARD           MX61_ARD                3278
+tx53                   MACH_TX53               TX53                    3279
+omapl138_case_a3       MACH_OMAPL138_CASE_A3   OMAPL138_CASE_A3        3280
+uemd                   MACH_UEMD               UEMD                    3281
+ccwmx51mut             MACH_CCWMX51MUT         CCWMX51MUT              3282
+rockhopper             MACH_ROCKHOPPER         ROCKHOPPER              3283
+nookcolor              MACH_NOOKCOLOR          NOOKCOLOR               3284
+hkdkc100               MACH_HKDKC100           HKDKC100                3285
+ts42xx                 MACH_TS42XX             TS42XX                  3286
+aebl                   MACH_AEBL               AEBL                    3287
+wario                  MACH_WARIO              WARIO                   3288
+gfs_spm                        MACH_GFS_SPM            GFS_SPM                 3289
+cm_t3730               MACH_CM_T3730           CM_T3730                3290
+isc3                   MACH_ISC3               ISC3                    3291
+rascal                 MACH_RASCAL             RASCAL                  3292
+hrefv60                        MACH_HREFV60            HREFV60                 3293
+tpt_2_0                        MACH_TPT_2_0            TPT_2_0                 3294
+pyramid_td             MACH_PYRAMID_TD         PYRAMID_TD              3295
+splendor               MACH_SPLENDOR           SPLENDOR                3296
+guf_planet             MACH_GUF_PLANET         GUF_PLANET              3297
+msm8x60_qt             MACH_MSM8X60_QT         MSM8X60_QT              3298
+htc_hd_mini            MACH_HTC_HD_MINI        HTC_HD_MINI             3299
+athene                 MACH_ATHENE             ATHENE                  3300
+deep_r_ek_1            MACH_DEEP_R_EK_1        DEEP_R_EK_1             3301
+vivow_ct               MACH_VIVOW_CT           VIVOW_CT                3302
+nery_1000              MACH_NERY_1000          NERY_1000               3303
+rfl109145_ssrv         MACH_RFL109145_SSRV     RFL109145_SSRV          3304
+nmh                    MACH_NMH                NMH                     3305
+wn802t                 MACH_WN802T             WN802T                  3306
+dragonet               MACH_DRAGONET           DRAGONET                3307
+geneva_b               MACH_GENEVA_B           GENEVA_B                3308
+at91sam9263desk16l     MACH_AT91SAM9263DESK16L AT91SAM9263DESK16L      3309
+bcmhana_sv             MACH_BCMHANA_SV         BCMHANA_SV              3310
+bcmhana_tablet         MACH_BCMHANA_TABLET     BCMHANA_TABLET          3311
+koi                    MACH_KOI                KOI                     3312
+ts4800                 MACH_TS4800             TS4800                  3313
+tqma9263               MACH_TQMA9263           TQMA9263                3314
+holiday                        MACH_HOLIDAY            HOLIDAY                 3315
+dma_6410               MACH_DMA6410            DMA6410                 3316
+pcats_overlay          MACH_PCATS_OVERLAY      PCATS_OVERLAY           3317
+hwgw6410               MACH_HWGW6410           HWGW6410                3318
+shenzhou               MACH_SHENZHOU           SHENZHOU                3319
+cwme9210               MACH_CWME9210           CWME9210                3320
+cwme9210js             MACH_CWME9210JS         CWME9210JS              3321
+pgs_v1                 MACH_PGS_SITARA         PGS_SITARA              3322
+colibri_tegra2         MACH_COLIBRI_TEGRA2     COLIBRI_TEGRA2          3323
+w21                    MACH_W21                W21                     3324
+polysat1               MACH_POLYSAT1           POLYSAT1                3325
+dataway                        MACH_DATAWAY            DATAWAY                 3326
+cobral138              MACH_COBRAL138          COBRAL138               3327
+roverpcs8              MACH_ROVERPCS8          ROVERPCS8               3328
+marvelc                        MACH_MARVELC            MARVELC                 3329
+navefihid              MACH_NAVEFIHID          NAVEFIHID               3330
+dm365_cv100            MACH_DM365_CV100        DM365_CV100             3331
+able                   MACH_ABLE               ABLE                    3332
+legacy                 MACH_LEGACY             LEGACY                  3333
+icong                  MACH_ICONG              ICONG                   3334
+rover_g8               MACH_ROVER_G8           ROVER_G8                3335
+t5388p                 MACH_T5388P             T5388P                  3336
+dingo                  MACH_DINGO              DINGO                   3337
+goflexhome             MACH_GOFLEXHOME         GOFLEXHOME              3338
index 92ecd84..bc7e8ae 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef __ASM_AVR32_PGALLOC_H
 #define __ASM_AVR32_PGALLOC_H
 
+#include <linux/mm.h>
 #include <linux/quicklist.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
index 1ff9f14..7dbc664 100644 (file)
@@ -10,6 +10,7 @@
 #define __BFIN_ASM_SERIAL_H__
 
 #include <linux/serial_core.h>
+#include <linux/spinlock.h>
 #include <mach/anomaly.h>
 #include <mach/bfin_serial.h>
 
@@ -41,6 +42,7 @@ struct bfin_serial_port {
        struct circ_buf rx_dma_buf;
        struct timer_list rx_dma_timer;
        int rx_dma_nrows;
+       spinlock_t rx_lock;
        unsigned int tx_dma_channel;
        unsigned int rx_dma_channel;
        struct work_struct tx_dma_workqueue;
index c911361..8d73724 100644 (file)
@@ -114,16 +114,14 @@ u32 arch_gettimeoffset(void)
 
 /*
  * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
+ * as well as call the "xtime_update()" routine every clocktick
  */
 #ifdef CONFIG_CORE_TIMER_IRQ_L1
 __attribute__((l1_text))
 #endif
 irqreturn_t timer_interrupt(int irq, void *dummy)
 {
-       write_seqlock(&xtime_lock);
-       do_timer(1);
-       write_sequnlock(&xtime_lock);
+       xtime_update(1);
 
 #ifdef CONFIG_IPIPE
        update_root_process_times(get_irq_regs());
index 250f4d4..06a5e67 100644 (file)
@@ -13,6 +13,8 @@
 .align 2
 
 ENTRY(_outsl)
+       CC = R2 == 0;
+       IF CC JUMP 1f;
        P0 = R0;        /* P0 = port */
        P1 = R1;        /* P1 = address */
        P2 = R2;        /* P2 = count */
@@ -20,10 +22,12 @@ ENTRY(_outsl)
        LSETUP( .Llong_loop_s, .Llong_loop_e) LC0 = P2;
 .Llong_loop_s: R0 = [P1++];
 .Llong_loop_e: [P0] = R0;
-       RTS;
+1:     RTS;
 ENDPROC(_outsl)
 
 ENTRY(_outsw)
+       CC = R2 == 0;
+       IF CC JUMP 1f;
        P0 = R0;        /* P0 = port */
        P1 = R1;        /* P1 = address */
        P2 = R2;        /* P2 = count */
@@ -31,10 +35,12 @@ ENTRY(_outsw)
        LSETUP( .Lword_loop_s, .Lword_loop_e) LC0 = P2;
 .Lword_loop_s: R0 = W[P1++];
 .Lword_loop_e: W[P0] = R0;
-       RTS;
+1:     RTS;
 ENDPROC(_outsw)
 
 ENTRY(_outsb)
+       CC = R2 == 0;
+       IF CC JUMP 1f;
        P0 = R0;        /* P0 = port */
        P1 = R1;        /* P1 = address */
        P2 = R2;        /* P2 = count */
@@ -42,10 +48,12 @@ ENTRY(_outsb)
        LSETUP( .Lbyte_loop_s, .Lbyte_loop_e) LC0 = P2;
 .Lbyte_loop_s: R0 = B[P1++];
 .Lbyte_loop_e: B[P0] = R0;
-       RTS;
+1:     RTS;
 ENDPROC(_outsb)
 
 ENTRY(_outsw_8)
+       CC = R2 == 0;
+       IF CC JUMP 1f;
        P0 = R0;        /* P0 = port */
        P1 = R1;        /* P1 = address */
        P2 = R2;        /* P2 = count */
@@ -56,5 +64,5 @@ ENTRY(_outsw_8)
                R0 = R0 << 8;
                R0 = R0 + R1;
 .Lword8_loop_e: W[P0] = R0;
-       RTS;
+1:     RTS;
 ENDPROC(_outsw_8)
index 790c767..ab4a925 100644 (file)
@@ -58,6 +58,8 @@
 1:
 .ifeqs "\flushins", BROK_FLUSH_INST
        \flushins [P0++];
+       nop;
+       nop;
 2:     nop;
 .else
 2:     \flushins [P0++];
index 00eb36f..20c85b5 100644 (file)
@@ -140,7 +140,7 @@ stop_watchdog(void)
 
 /*
  * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
+ * as well as call the "xtime_update()" routine every clocktick
  */
 
 //static unsigned short myjiff; /* used by our debug routine print_timestamp */
@@ -176,7 +176,7 @@ timer_interrupt(int irq, void *dev_id)
 
        /* call the real timer interrupt handler */
 
-       do_timer(1);
+       xtime_update(1);
        
         cris_do_profile(regs); /* Save profiling information */
         return IRQ_HANDLED;
index 84fed3b..4c9e3e1 100644 (file)
@@ -26,7 +26,9 @@
 #define FLUSH_ALL (void*)0xffffffff
 
 /* Vector of locks used for various atomic operations */
-spinlock_t cris_atomic_locks[] = { [0 ... LOCK_COUNT - 1] = SPIN_LOCK_UNLOCKED};
+spinlock_t cris_atomic_locks[] = {
+       [0 ... LOCK_COUNT - 1] = __SPIN_LOCK_UNLOCKED(cris_atomic_locks)
+};
 
 /* CPU masks */
 cpumask_t phys_cpu_present_map = CPU_MASK_NONE;
index a545211..bb978ed 100644 (file)
@@ -183,7 +183,7 @@ void handle_watchdog_bite(struct pt_regs *regs)
 
 /*
  * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick.
+ * as well as call the "xtime_update()" routine every clocktick.
  */
 extern void cris_do_profile(struct pt_regs *regs);
 
@@ -216,9 +216,7 @@ static inline irqreturn_t timer_interrupt(int irq, void *dev_id)
                return IRQ_HANDLED;
 
        /* Call the real timer interrupt handler */
-       write_seqlock(&xtime_lock);
-       do_timer(1);
-       write_sequnlock(&xtime_lock);
+       xtime_update(1);
         return IRQ_HANDLED;
 }
 
index c62e134..728bbd9 100644 (file)
@@ -72,11 +72,6 @@ SECTIONS
        INIT_TEXT_SECTION(PAGE_SIZE)
        .init.data : { INIT_DATA }
        .init.setup : { INIT_SETUP(16) }
-#ifdef CONFIG_ETRAX_ARCH_V32
-       __start___param = .;
-       __param : { *(__param) }
-       __stop___param = .;
-#endif
        .initcall.init : {
                INIT_CALLS
        }
index 08b3d1d..4bea27f 100644 (file)
@@ -7,10 +7,11 @@
 #include <asm/errno.h>
 #include <asm/uaccess.h>
 
-extern int futex_atomic_op_inuser(int encoded_op, int __user *uaddr);
+extern int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr);
 
 static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+                             u32 oldval, u32 newval)
 {
        return -ENOSYS;
 }
index 14f64b0..d155ca9 100644 (file)
@@ -18,7 +18,7 @@
  * the various futex operations; MMU fault checking is ignored under no-MMU
  * conditions
  */
-static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr, int *_oldval)
+static inline int atomic_futex_op_xchg_set(int oparg, u32 __user *uaddr, int *_oldval)
 {
        int oldval, ret;
 
@@ -50,7 +50,7 @@ static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr, int *_o
        return ret;
 }
 
-static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr, int *_oldval)
+static inline int atomic_futex_op_xchg_add(int oparg, u32 __user *uaddr, int *_oldval)
 {
        int oldval, ret;
 
@@ -83,7 +83,7 @@ static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr, int *_o
        return ret;
 }
 
-static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr, int *_oldval)
+static inline int atomic_futex_op_xchg_or(int oparg, u32 __user *uaddr, int *_oldval)
 {
        int oldval, ret;
 
@@ -116,7 +116,7 @@ static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr, int *_ol
        return ret;
 }
 
-static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr, int *_oldval)
+static inline int atomic_futex_op_xchg_and(int oparg, u32 __user *uaddr, int *_oldval)
 {
        int oldval, ret;
 
@@ -149,7 +149,7 @@ static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr, int *_o
        return ret;
 }
 
-static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr, int *_oldval)
+static inline int atomic_futex_op_xchg_xor(int oparg, u32 __user *uaddr, int *_oldval)
 {
        int oldval, ret;
 
@@ -186,7 +186,7 @@ static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr, int *_o
 /*
  * do the futex operations
  */
-int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
 {
        int op = (encoded_op >> 28) & 7;
        int cmp = (encoded_op >> 24) & 15;
@@ -197,7 +197,7 @@ int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
        if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
                oparg = 1 << oparg;
 
-       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
        pagefault_disable();
index 0ddbbae..b457de4 100644 (file)
@@ -50,21 +50,13 @@ static struct irqaction timer_irq  = {
 
 /*
  * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
+ * as well as call the "xtime_update()" routine every clocktick
  */
 static irqreturn_t timer_interrupt(int irq, void *dummy)
 {
        profile_tick(CPU_PROFILING);
-       /*
-        * Here we are in the timer irq handler. We just have irqs locally
-        * disabled but we don't know if the timer_bh is running on the other
-        * CPU. We need to avoid to SMP race with it. NOTE: we don't need
-        * the irq version of write_lock because as just said we have irq
-        * locally disabled. -arca
-        */
-       write_seqlock(&xtime_lock);
 
-       do_timer(1);
+       xtime_update(1);
 
 #ifdef CONFIG_HEARTBEAT
        static unsigned short n;
@@ -72,8 +64,6 @@ static irqreturn_t timer_interrupt(int irq, void *dummy)
        __set_LEDS(n);
 #endif /* CONFIG_HEARTBEAT */
 
-       write_sequnlock(&xtime_lock);
-
        update_process_times(user_mode(get_irq_regs()));
 
        return IRQ_HANDLED;
index 165005a..32263a1 100644 (file)
@@ -35,9 +35,7 @@ void h8300_timer_tick(void)
 {
        if (current->pid)
                profile_tick(CPU_PROFILING);
-       write_seqlock(&xtime_lock);
-       do_timer(1);
-       write_sequnlock(&xtime_lock);
+       xtime_update(1);
        update_process_times(user_mode(get_irq_regs()));
 }
 
index 3946c0f..7a1533f 100644 (file)
@@ -61,7 +61,7 @@
 
 /*
  * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
+ * as well as call the "xtime_update()" routine every clocktick
  */
 
 static irqreturn_t timer_interrupt(int irq, void *dev_id)
index c7f0f06..8428525 100644 (file)
@@ -46,7 +46,7 @@ do {                                                                  \
 } while (0)
 
 static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
 {
        int op = (encoded_op >> 28) & 7;
        int cmp = (encoded_op >> 24) & 15;
@@ -56,7 +56,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
        if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
                oparg = 1 << oparg;
 
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
        pagefault_disable();
@@ -100,23 +100,26 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
 }
 
 static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+                             u32 oldval, u32 newval)
 {
-       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
        {
-               register unsigned long r8 __asm ("r8");
+               register unsigned long r8 __asm ("r8") = 0;
+               unsigned long prev;
                __asm__ __volatile__(
                        "       mf;;                                    \n"
                        "       mov ar.ccv=%3;;                         \n"
                        "[1:]   cmpxchg4.acq %0=[%1],%2,ar.ccv          \n"
                        "       .xdata4 \"__ex_table\", 1b-., 2f-.      \n"
                        "[2:]"
-                       : "=r" (r8)
+                       : "=r" (prev)
                        : "r" (uaddr), "r" (newval),
                          "rO" ((long) (unsigned) oldval)
                        : "memory");
+               *uval = prev;
                return r8;
        }
 }
index 215d545..3027e75 100644 (file)
 #error "Please don't include <asm/rwsem.h> directly, use <linux/rwsem.h> instead."
 #endif
 
-#include <linux/list.h>
-#include <linux/spinlock.h>
-
 #include <asm/intrinsics.h>
 
-/*
- * the semaphore definition
- */
-struct rw_semaphore {
-       signed long             count;
-       spinlock_t              wait_lock;
-       struct list_head        wait_list;
-};
-
 #define RWSEM_UNLOCKED_VALUE           __IA64_UL_CONST(0x0000000000000000)
 #define RWSEM_ACTIVE_BIAS              (1L)
 #define RWSEM_ACTIVE_MASK              (0xffffffffL)
@@ -46,26 +34,6 @@ struct rw_semaphore {
 #define RWSEM_ACTIVE_READ_BIAS         RWSEM_ACTIVE_BIAS
 #define RWSEM_ACTIVE_WRITE_BIAS                (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
 
-#define __RWSEM_INITIALIZER(name) \
-       { RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait_lock), \
-         LIST_HEAD_INIT((name).wait_list) }
-
-#define DECLARE_RWSEM(name) \
-       struct rw_semaphore name = __RWSEM_INITIALIZER(name)
-
-extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
-extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
-extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem);
-extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
-
-static inline void
-init_rwsem (struct rw_semaphore *sem)
-{
-       sem->count = RWSEM_UNLOCKED_VALUE;
-       spin_lock_init(&sem->wait_lock);
-       INIT_LIST_HEAD(&sem->wait_list);
-}
-
 /*
  * lock for reading
  */
@@ -174,9 +142,4 @@ __downgrade_write (struct rw_semaphore *sem)
 #define rwsem_atomic_add(delta, sem)   atomic64_add(delta, (atomic64_t *)(&(sem)->count))
 #define rwsem_atomic_update(delta, sem)        atomic64_add_return(delta, (atomic64_t *)(&(sem)->count))
 
-static inline int rwsem_is_locked(struct rw_semaphore *sem)
-{
-       return (sem->count != 0);
-}
-
 #endif /* _ASM_IA64_RWSEM_H */
index 96fc623..ed28bcd 100644 (file)
@@ -107,7 +107,7 @@ extern unsigned long __hypercall(unsigned long a1, unsigned long a2,
 static inline int
 xencomm_arch_hypercall_sched_op(int cmd, struct xencomm_handle *arg)
 {
-       return _hypercall2(int, sched_op_new, cmd, arg);
+       return _hypercall2(int, sched_op, cmd, arg);
 }
 
 static inline long
index 9702fa9..156ad80 100644 (file)
@@ -190,19 +190,10 @@ timer_interrupt (int irq, void *dev_id)
 
                new_itm += local_cpu_data->itm_delta;
 
-               if (smp_processor_id() == time_keeper_id) {
-                       /*
-                        * Here we are in the timer irq handler. We have irqs locally
-                        * disabled, but we don't know if the timer_bh is running on
-                        * another CPU. We need to avoid to SMP race by acquiring the
-                        * xtime_lock.
-                        */
-                       write_seqlock(&xtime_lock);
-                       do_timer(1);
-                       local_cpu_data->itm_next = new_itm;
-                       write_sequnlock(&xtime_lock);
-               } else
-                       local_cpu_data->itm_next = new_itm;
+               if (smp_processor_id() == time_keeper_id)
+                       xtime_update(1);
+
+               local_cpu_data->itm_next = new_itm;
 
                if (time_after(new_itm, ia64_get_itc()))
                        break;
@@ -222,7 +213,7 @@ skip_process_time_accounting:
                 * comfort, we increase the safety margin by
                 * intentionally dropping the next tick(s).  We do NOT
                 * update itm.next because that would force us to call
-                * do_timer() which in turn would let our clock run
+                * xtime_update() which in turn would let our clock run
                 * too fast (with the potentially devastating effect
                 * of losing monotony of time).
                 */
index fd66b04..419c862 100644 (file)
@@ -37,19 +37,14 @@ xen_mm_unpin_all(void)
        /* nothing */
 }
 
-void xen_pre_device_suspend(void)
-{
-       /* nothing */
-}
-
 void
-xen_pre_suspend()
+xen_arch_pre_suspend()
 {
        /* nothing */
 }
 
 void
-xen_post_suspend(int suspend_cancelled)
+xen_arch_post_suspend(int suspend_cancelled)
 {
        if (suspend_cancelled)
                return;
index c1c5445..1f8244a 100644 (file)
@@ -139,14 +139,11 @@ consider_steal_time(unsigned long new_itm)
                run_posix_cpu_timers(p);
                delta_itm += local_cpu_data->itm_delta * (stolen + blocked);
 
-               if (cpu == time_keeper_id) {
-                       write_seqlock(&xtime_lock);
-                       do_timer(stolen + blocked);
-                       local_cpu_data->itm_next = delta_itm + new_itm;
-                       write_sequnlock(&xtime_lock);
-               } else {
-                       local_cpu_data->itm_next = delta_itm + new_itm;
-               }
+               if (cpu == time_keeper_id)
+                       xtime_update(stolen + blocked);
+
+               local_cpu_data->itm_next = delta_itm + new_itm;
+
                per_cpu(xen_stolen_time, cpu) += NS_PER_TICK * stolen;
                per_cpu(xen_blocked_time, cpu) += NS_PER_TICK * blocked;
        }
index f745c12..76eaf38 100644 (file)
@@ -80,7 +80,7 @@ asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs)
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
        /* FIXME M32R */
 #endif
-       __do_IRQ(irq);
+       generic_handle_irq(irq);
        irq_exit();
        set_irq_regs(old_regs);
 
index bda8682..84dd040 100644 (file)
@@ -107,15 +107,14 @@ u32 arch_gettimeoffset(void)
 
 /*
  * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
+ * as well as call the "xtime_update()" routine every clocktick
  */
 static irqreturn_t timer_interrupt(int irq, void *dev_id)
 {
 #ifndef CONFIG_SMP
        profile_tick(CPU_PROFILING);
 #endif
-       /* XXX FIXME. Uh, the xtime_lock should be held here, no? */
-       do_timer(1);
+       xtime_update(1);
 
 #ifndef CONFIG_SMP
        update_process_times(user_mode(get_irq_regs()));
index b1577f7..82a4bb5 100644 (file)
@@ -610,17 +610,17 @@ static void amiga_mem_console_write(struct console *co, const char *s,
 
 static int __init amiga_savekmsg_setup(char *arg)
 {
-       static struct resource debug_res = { .name = "Debug" };
-
        if (!MACH_IS_AMIGA || strcmp(arg, "mem"))
-               goto done;
+               return 0;
 
-       if (!AMIGAHW_PRESENT(CHIP_RAM)) {
-               printk("Warning: no chipram present for debugging\n");
-               goto done;
+       if (amiga_chip_size < SAVEKMSG_MAXMEM) {
+               pr_err("Not enough chipram for debugging\n");
+               return -ENOMEM;
        }
 
-       savekmsg = amiga_chip_alloc_res(SAVEKMSG_MAXMEM, &debug_res);
+       /* Just steal the block, the chipram allocator isn't functional yet */
+       amiga_chip_size -= SAVEKMSG_MAXMEM;
+       savekmsg = (void *)ZTWO_VADDR(CHIP_PHYSADDR + amiga_chip_size);
        savekmsg->magic1 = SAVEKMSG_MAGIC1;
        savekmsg->magic2 = SAVEKMSG_MAGIC2;
        savekmsg->magicptr = ZTWO_PADDR(savekmsg);
@@ -628,8 +628,6 @@ static int __init amiga_savekmsg_setup(char *arg)
 
        amiga_console_driver.write = amiga_mem_console_write;
        register_console(&amiga_console_driver);
-
-done:
        return 0;
 }
 
index 39478dd..26a804e 100644 (file)
@@ -388,9 +388,9 @@ void __init atari_init_IRQ(void)
        }
 
        if (ATARIHW_PRESENT(SCC) && !atari_SCC_reset_done) {
-               scc.cha_a_ctrl = 9;
+               atari_scc.cha_a_ctrl = 9;
                MFPDELAY();
-               scc.cha_a_ctrl = (char) 0xc0; /* hardware reset */
+               atari_scc.cha_a_ctrl = (char) 0xc0; /* hardware reset */
        }
 
        if (ATARIHW_PRESENT(SCU)) {
index ae2d96e..4203d10 100644 (file)
@@ -315,7 +315,7 @@ void __init config_atari(void)
                ATARIHW_SET(SCC_DMA);
                printk("SCC_DMA ");
        }
-       if (scc_test(&scc.cha_a_ctrl)) {
+       if (scc_test(&atari_scc.cha_a_ctrl)) {
                ATARIHW_SET(SCC);
                printk("SCC ");
        }
index 28efdc3..5a48424 100644 (file)
@@ -53,9 +53,9 @@ static inline void ata_scc_out(char c)
 {
        do {
                MFPDELAY();
-       } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
+       } while (!(atari_scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
        MFPDELAY();
-       scc.cha_b_data = c;
+       atari_scc.cha_b_data = c;
 }
 
 static void atari_scc_console_write(struct console *co, const char *str,
@@ -140,9 +140,9 @@ int atari_scc_console_wait_key(struct console *co)
 {
        do {
                MFPDELAY();
-       } while (!(scc.cha_b_ctrl & 0x01)); /* wait for rx buf filled */
+       } while (!(atari_scc.cha_b_ctrl & 0x01)); /* wait for rx buf filled */
        MFPDELAY();
-       return scc.cha_b_data;
+       return atari_scc.cha_b_data;
 }
 
 int atari_midi_console_wait_key(struct console *co)
@@ -185,9 +185,9 @@ static void __init atari_init_mfp_port(int cflag)
 
 #define SCC_WRITE(reg, val)                            \
        do {                                            \
-               scc.cha_b_ctrl = (reg);                 \
+               atari_scc.cha_b_ctrl = (reg);           \
                MFPDELAY();                             \
-               scc.cha_b_ctrl = (val);                 \
+               atari_scc.cha_b_ctrl = (val);           \
                MFPDELAY();                             \
        } while (0)
 
@@ -240,7 +240,7 @@ static void __init atari_init_scc_port(int cflag)
        reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40;
        reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */;
 
-       (void)scc.cha_b_ctrl;           /* reset reg pointer */
+       (void)atari_scc.cha_b_ctrl;     /* reset reg pointer */
        SCC_WRITE(9, 0xc0);             /* reset */
        LONG_DELAY();                   /* extra delay after WR9 access */
        SCC_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03)
index 9fe6fef..1edd950 100644 (file)
@@ -45,8 +45,8 @@ extern int bvme6000_set_clock_mmss (unsigned long);
 extern void bvme6000_reset (void);
 void bvme6000_set_vectors (void);
 
-/* Save tick handler routine pointer, will point to do_timer() in
- * kernel/sched.c, called via bvme6000_process_int() */
+/* Save tick handler routine pointer, will point to xtime_update() in
+ * kernel/timer/timekeeping.c, called via bvme6000_process_int() */
 
 static irq_handler_t tick_handler;
 
index a714e1a..f51f709 100644 (file)
@@ -449,7 +449,7 @@ struct SCC
   u_char char_dummy3;
   u_char cha_b_data;
  };
-# define scc ((*(volatile struct SCC*)SCC_BAS))
+# define atari_scc ((*(volatile struct SCC*)SCC_BAS))
 
 /* The ESCC (Z85230) in an Atari ST. The channels are reversed! */
 # define st_escc ((*(volatile struct SCC*)0xfffffa31))
index 2936dda..3219845 100644 (file)
@@ -81,18 +81,6 @@ static inline char *strncpy(char *dest, const char *src, size_t n)
        strcpy(__d + strlen(__d), (s));         \
 })
 
-#define __HAVE_ARCH_STRCHR
-static inline char *strchr(const char *s, int c)
-{
-       char sc, ch = c;
-
-       for (; (sc = *s++) != ch; ) {
-               if (!sc)
-                       return NULL;
-       }
-       return (char *)s - 1;
-}
-
 #ifndef CONFIG_COLDFIRE
 #define __HAVE_ARCH_STRCMP
 static inline int strcmp(const char *cs, const char *ct)
@@ -111,14 +99,12 @@ static inline int strcmp(const char *cs, const char *ct)
                : "+a" (cs), "+a" (ct), "=d" (res));
        return res;
 }
+#endif /* CONFIG_COLDFIRE */
 
 #define __HAVE_ARCH_MEMMOVE
 extern void *memmove(void *, const void *, __kernel_size_t);
 
-#define __HAVE_ARCH_MEMCMP
-extern int memcmp(const void *, const void *, __kernel_size_t);
 #define memcmp(d, s, n) __builtin_memcmp(d, s, n)
-#endif /* CONFIG_COLDFIRE */
 
 #define __HAVE_ARCH_MEMSET
 extern void *memset(void *, int, __kernel_size_t);
index 06438da..18b34ee 100644 (file)
@@ -37,11 +37,11 @@ static inline int set_rtc_mmss(unsigned long nowtime)
 
 /*
  * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
+ * as well as call the "xtime_update()" routine every clocktick
  */
 static irqreturn_t timer_interrupt(int irq, void *dummy)
 {
-       do_timer(1);
+       xtime_update(1);
        update_process_times(user_mode(get_irq_regs()));
        profile_tick(CPU_PROFILING);
 
index 4253f87..d399c5f 100644 (file)
@@ -243,14 +243,3 @@ void *memmove(void *dest, const void *src, size_t n)
        return xdest;
 }
 EXPORT_SYMBOL(memmove);
-
-int memcmp(const void *cs, const void *ct, size_t count)
-{
-       const unsigned char *su1, *su2;
-
-       for (su1 = cs, su2 = ct; count > 0; ++su1, ++su2, count--)
-               if (*su1 != *su2)
-                       return *su1 < *su2 ? -1 : +1;
-       return 0;
-}
-EXPORT_SYMBOL(memcmp);
index 100baaa..6cb9c3a 100644 (file)
@@ -46,8 +46,8 @@ extern void mvme147_reset (void);
 
 static int bcd2int (unsigned char b);
 
-/* Save tick handler routine pointer, will point to do_timer() in
- * kernel/sched.c, called via mvme147_process_int() */
+/* Save tick handler routine pointer, will point to xtime_update() in
+ * kernel/time/timekeeping.c, called via mvme147_process_int() */
 
 irq_handler_t tick_handler;
 
index 11edf61..0b28e26 100644 (file)
@@ -51,8 +51,8 @@ extern void mvme16x_reset (void);
 
 int bcd2int (unsigned char b);
 
-/* Save tick handler routine pointer, will point to do_timer() in
- * kernel/sched.c, called via mvme16x_process_int() */
+/* Save tick handler routine pointer, will point to xtime_update() in
+ * kernel/time/timekeeping.c, called via mvme16x_process_int() */
 
 static irq_handler_t tick_handler;
 
index 2d9e21b..6464ad3 100644 (file)
@@ -66,7 +66,7 @@ static irqreturn_t sun3_int5(int irq, void *dev_id)
 #ifdef CONFIG_SUN3
        intersil_clear();
 #endif
-        do_timer(1);
+       xtime_update(1);
        update_process_times(user_mode(get_irq_regs()));
         if (!(kstat_cpu(0).irqs[irq] % 20))
                 sun3_leds(led_pattern[(kstat_cpu(0).irqs[irq] % 160) / 20]);
index d6ac2a4..6623909 100644 (file)
@@ -36,7 +36,7 @@ static inline int set_rtc_mmss(unsigned long nowtime)
 #ifndef CONFIG_GENERIC_CLOCKEVENTS
 /*
  * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
+ * as well as call the "xtime_update()" routine every clocktick
  */
 irqreturn_t arch_timer_interrupt(int irq, void *dummy)
 {
@@ -44,11 +44,7 @@ irqreturn_t arch_timer_interrupt(int irq, void *dummy)
        if (current->pid)
                profile_tick(CPU_PROFILING);
 
-       write_seqlock(&xtime_lock);
-
-       do_timer(1);
-
-       write_sequnlock(&xtime_lock);
+       xtime_update(1);
 
        update_process_times(user_mode(get_irq_regs()));
 
index ef33213..47e15eb 100644 (file)
@@ -141,6 +141,12 @@ SECTIONS {
                *(__param)
                __stop___param = .;
 
+               /* Built-in module versions */
+               . = ALIGN(4) ;
+               __start___modver = .;
+               *(__modver)
+               __stop___modver = .;
+
                . = ALIGN(4) ;
                _etext = . ;
        } > TEXT
index d94d709..32d852e 100644 (file)
@@ -4,4 +4,4 @@
 
 lib-y  := ashldi3.o ashrdi3.o lshrdi3.o \
           muldi3.o mulsi3.o divsi3.o udivsi3.o modsi3.o umodsi3.o \
-          checksum.o memcpy.o memset.o delay.o
+          checksum.o memcpy.o memmove.o memset.o delay.o
diff --git a/arch/m68knommu/lib/memmove.c b/arch/m68knommu/lib/memmove.c
new file mode 100644 (file)
index 0000000..b3dcfe9
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+#define __IN_STRING_C
+
+#include <linux/module.h>
+#include <linux/string.h>
+
+void *memmove(void *dest, const void *src, size_t n)
+{
+       void *xdest = dest;
+       size_t temp;
+
+       if (!n)
+               return xdest;
+
+       if (dest < src) {
+               if ((long)dest & 1) {
+                       char *cdest = dest;
+                       const char *csrc = src;
+                       *cdest++ = *csrc++;
+                       dest = cdest;
+                       src = csrc;
+                       n--;
+               }
+               if (n > 2 && (long)dest & 2) {
+                       short *sdest = dest;
+                       const short *ssrc = src;
+                       *sdest++ = *ssrc++;
+                       dest = sdest;
+                       src = ssrc;
+                       n -= 2;
+               }
+               temp = n >> 2;
+               if (temp) {
+                       long *ldest = dest;
+                       const long *lsrc = src;
+                       temp--;
+                       do
+                               *ldest++ = *lsrc++;
+                       while (temp--);
+                       dest = ldest;
+                       src = lsrc;
+               }
+               if (n & 2) {
+                       short *sdest = dest;
+                       const short *ssrc = src;
+                       *sdest++ = *ssrc++;
+                       dest = sdest;
+                       src = ssrc;
+               }
+               if (n & 1) {
+                       char *cdest = dest;
+                       const char *csrc = src;
+                       *cdest = *csrc;
+               }
+       } else {
+               dest = (char *)dest + n;
+               src = (const char *)src + n;
+               if ((long)dest & 1) {
+                       char *cdest = dest;
+                       const char *csrc = src;
+                       *--cdest = *--csrc;
+                       dest = cdest;
+                       src = csrc;
+                       n--;
+               }
+               if (n > 2 && (long)dest & 2) {
+                       short *sdest = dest;
+                       const short *ssrc = src;
+                       *--sdest = *--ssrc;
+                       dest = sdest;
+                       src = ssrc;
+                       n -= 2;
+               }
+               temp = n >> 2;
+               if (temp) {
+                       long *ldest = dest;
+                       const long *lsrc = src;
+                       temp--;
+                       do
+                               *--ldest = *--lsrc;
+                       while (temp--);
+                       dest = ldest;
+                       src = lsrc;
+               }
+               if (n & 2) {
+                       short *sdest = dest;
+                       const short *ssrc = src;
+                       *--sdest = *--ssrc;
+                       dest = sdest;
+                       src = ssrc;
+               }
+               if (n & 1) {
+                       char *cdest = dest;
+                       const char *csrc = src;
+                       *--cdest = *--csrc;
+               }
+       }
+       return xdest;
+}
+EXPORT_SYMBOL(memmove);
index d09d9da..c5151f8 100644 (file)
@@ -50,8 +50,10 @@ static int __init mcf_intc2_init(void)
        int irq;
 
        /* GPIO interrupt sources */
-       for (irq = MCFINTC2_GPIOIRQ0; (irq <= MCFINTC2_GPIOIRQ7); irq++)
+       for (irq = MCFINTC2_GPIOIRQ0; (irq <= MCFINTC2_GPIOIRQ7); irq++) {
                irq_desc[irq].chip = &intc2_irq_gpio_chip;
+               set_irq_handler(irq, handle_edge_irq);
+       }
 
        return 0;
 }
index 240a7a6..676960c 100644 (file)
@@ -108,7 +108,6 @@ Luser_return:
        movel   %d1,%a2
 1:
        move    %a2@(TI_FLAGS),%d1      /* thread_info->flags */
-       andl    #_TIF_WORK_MASK,%d1
        jne     Lwork_to_do
        RESTORE_ALL
 
index f27e688..8e4e10c 100644 (file)
@@ -210,7 +210,7 @@ void
 cpm_install_handler(int vec, void (*handler)(), void *dev_id)
 {
 
-       request_irq(vec, handler, IRQ_FLG_LOCK, "timer", dev_id);
+       request_irq(vec, handler, 0, "timer", dev_id);
 
 /*     if (cpm_vecs[vec].handler != 0) */
 /*             printk(KERN_INFO "CPM interrupt %x replacing %x\n", */
index ac629fa..9dd5bca 100644 (file)
@@ -75,7 +75,7 @@ void hw_timer_init(void)
   /* Set compare register  32Khz / 32 / 10 = 100 */
   TCMP = 10;                                                              
 
-  request_irq(IRQ_MACHSPEC | 1, timer_routine, IRQ_FLG_LOCK, "timer", NULL);
+  request_irq(IRQ_MACHSPEC | 1, timer_routine, 0, "timer", NULL);
 #endif
 
   /* General purpose quicc timers: MC68360UM p7-20 */
index 8a28788..46c1b18 100644 (file)
@@ -104,7 +104,6 @@ Luser_return:
        movel   %d1,%a2
 1:
        move    %a2@(TI_FLAGS),%d1      /* thread_info->flags */
-       andl    #_TIF_WORK_MASK,%d1
        jne     Lwork_to_do
        RESTORE_ALL
 
index ad96ab1..a29041c 100644 (file)
@@ -132,8 +132,8 @@ void init_IRQ(void)
        pquicc->intr_cimr = 0x00000000;
 
        for (i = 0; (i < NR_IRQS); i++) {
-               set_irq_chip(irq, &intc_irq_chip);
-               set_irq_handler(irq, handle_level_irq);
+               set_irq_chip(i, &intc_irq_chip);
+               set_irq_handler(i, handle_level_irq);
        }
 }
 
index 4ddfc3d..5837cf0 100644 (file)
@@ -138,7 +138,6 @@ Luser_return:
        andl    #-THREAD_SIZE,%d1       /* at base of kernel stack */
        movel   %d1,%a0
        movel   %a0@(TI_FLAGS),%d1      /* get thread_info->flags */
-       andl    #0xefff,%d1
        jne     Lwork_to_do             /* still work to do */
 
 Lreturn:
index ad3fd61..b0526d2 100644 (file)
@@ -29,7 +29,7 @@
 })
 
 static inline int
-futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
 {
        int op = (encoded_op >> 28) & 7;
        int cmp = (encoded_op >> 24) & 15;
@@ -39,7 +39,7 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
        if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
                oparg = 1 << oparg;
 
-       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
        pagefault_disable();
@@ -94,31 +94,34 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
 }
 
 static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+                             u32 oldval, u32 newval)
 {
-       int prev, cmp;
+       int ret = 0, cmp;
+       u32 prev;
 
-       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
-       __asm__ __volatile__ ("1:       lwx     %0, %2, r0;             \
-                                       cmp     %1, %0, %3;             \
-                                       beqi    %1, 3f;                 \
-                               2:      swx     %4, %2, r0;             \
-                                       addic   %1, r0, 0;              \
-                                       bnei    %1, 1b;                 \
+       __asm__ __volatile__ ("1:       lwx     %1, %3, r0;             \
+                                       cmp     %2, %1, %4;             \
+                                       beqi    %2, 3f;                 \
+                               2:      swx     %5, %3, r0;             \
+                                       addic   %2, r0, 0;              \
+                                       bnei    %2, 1b;                 \
                                3:                                      \
                                .section .fixup,\"ax\";                 \
                                4:      brid    3b;                     \
-                                       addik   %0, r0, %5;             \
+                                       addik   %0, r0, %6;             \
                                .previous;                              \
                                .section __ex_table,\"a\";              \
                                .word   1b,4b,2b,4b;                    \
                                .previous;"                             \
-               : "=&r" (prev), "=&r"(cmp)                              \
+               : "+r" (ret), "=&r" (prev), "=&r"(cmp)  \
                : "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT));
 
-       return prev;
+       *uval = prev;
+       return ret;
 }
 
 #endif /* __KERNEL__ */
index 5fd3190..c4532f0 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/types.h>
 #include <asm/registers.h>
 
-#ifdef CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
+#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
 
 static inline unsigned long arch_local_irq_save(void)
 {
index 0c68764..1071766 100644 (file)
@@ -104,11 +104,22 @@ struct pci_controller {
        int global_number;      /* PCI domain number */
 };
 
+#ifdef CONFIG_PCI
 static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus)
 {
        return bus->sysdata;
 }
 
+static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
+{
+       struct pci_controller *host;
+
+       if (bus->self)
+               return pci_device_to_OF_node(bus->self);
+       host = pci_bus_to_host(bus);
+       return host ? host->dn : NULL;
+}
+
 static inline int isa_vaddr_is_ioport(void __iomem *address)
 {
        /* No specific ISA handling on ppc32 at this stage, it
@@ -116,6 +127,7 @@ static inline int isa_vaddr_is_ioport(void __iomem *address)
         */
        return 0;
 }
+#endif /* CONFIG_PCI */
 
 /* These are used for config access before all the PCI probing
    has been done. */
index b23f680..885574a 100644 (file)
@@ -411,20 +411,19 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 static inline unsigned long pte_update(pte_t *p, unsigned long clr,
                                unsigned long set)
 {
-       unsigned long old, tmp, msr;
-
-       __asm__ __volatile__("\
-       msrclr  %2, 0x2\n\
-       nop\n\
-       lw      %0, %4, r0\n\
-       andn    %1, %0, %5\n\
-       or      %1, %1, %6\n\
-       sw      %1, %4, r0\n\
-       mts     rmsr, %2\n\
-       nop"
-       : "=&r" (old), "=&r" (tmp), "=&r" (msr), "=m" (*p)
-       : "r" ((unsigned long)(p + 1) - 4), "r" (clr), "r" (set), "m" (*p)
-       : "cc");
+       unsigned long flags, old, tmp;
+
+       raw_local_irq_save(flags);
+
+       __asm__ __volatile__(   "lw     %0, %2, r0      \n"
+                               "andn   %1, %0, %3      \n"
+                               "or     %1, %1, %4      \n"
+                               "sw     %1, %2, r0      \n"
+                       : "=&r" (old), "=&r" (tmp)
+                       : "r" ((unsigned long)(p + 1) - 4), "r" (clr), "r" (set)
+                       : "cc");
+
+       raw_local_irq_restore(flags);
 
        return old;
 }
index 2e72af0..d0890d3 100644 (file)
@@ -64,21 +64,6 @@ extern void kdump_move_device_tree(void);
 /* CPU OF node matching */
 struct device_node *of_get_cpu_node(int cpu, unsigned int *thread);
 
-/**
- * of_irq_map_pci - Resolve the interrupt for a PCI device
- * @pdev:      the device whose interrupt is to be resolved
- * @out_irq:   structure of_irq filled by this function
- *
- * This function resolves the PCI interrupt for a given PCI device. If a
- * device-node exists for a given pci_dev, it will use normal OF tree
- * walking. If not, it will implement standard swizzling and walk up the
- * PCI tree until an device-node is found, at which point it will finish
- * resolving using the OF tree walking.
- */
-struct pci_dev;
-struct of_irq;
-extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq);
-
 #endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 
index e01afa6..488c1ed 100644 (file)
@@ -27,7 +27,7 @@
        register unsigned tmp __asm__("r3");                    \
        tmp = 0x0;      /* Prevent warning about unused */      \
        __asm__ __volatile__ (                                  \
-                       "mfs    %0, rpvr" #pvrid ";"    \
+                       "mfs    %0, rpvr" #pvrid ";"            \
                        : "=r" (tmp) : : "memory");             \
        val = tmp;                                              \
 }
@@ -54,7 +54,7 @@ int cpu_has_pvr(void)
        if (!(flags & PVR_MSR_BIT))
                return 0;
 
-       get_single_pvr(0x00, pvr0);
+       get_single_pvr(0, pvr0);
        pr_debug("%s: pvr0 is 0x%08x\n", __func__, pvr0);
 
        if (pvr0 & PVR0_PVR_FULL_MASK)
index 4243400..778a5ce 100644 (file)
@@ -62,23 +62,32 @@ real_start:
        andi    r1, r1, ~2
        mts     rmsr, r1
 /*
- * Here is checking mechanism which check if Microblaze has msr instructions
- * We load msr and compare it with previous r1 value - if is the same,
- * msr instructions works if not - cpu don't have them.
+ * According to Xilinx, msrclr instruction behaves like 'mfs rX,rpc'
+ * if the msrclr instruction is not enabled. We use this to detect
+ * if the opcode is available, by issuing msrclr and then testing the result.
+ * r8 == 0 - msr instructions are implemented
+ * r8 != 0 - msr instructions are not implemented
  */
-       /* r8=0 - I have msr instr, 1 - I don't have them */
-       rsubi   r0, r0, 1       /* set the carry bit */
-       msrclr  r0, 0x4         /* try to clear it */
-       /* read the carry bit, r8 will be '0' if msrclr exists */
-       addik   r8, r0, 0
+       msrclr  r8, 0 /* clear nothing - just read msr for test */
+       cmpu    r8, r8, r1 /* r1 must contain msr reg content */
 
 /* r7 may point to an FDT, or there may be one linked in.
    if it's in r7, we've got to save it away ASAP.
    We ensure r7 points to a valid FDT, just in case the bootloader
    is broken or non-existent */
        beqi    r7, no_fdt_arg                  /* NULL pointer?  don't copy */
-       lw      r11, r0, r7                     /* Does r7 point to a */
-       rsubi   r11, r11, OF_DT_HEADER          /* valid FDT? */
+/* Does r7 point to a valid FDT? Load HEADER magic number */
+       /* Run time Big/Little endian platform */
+       /* Save 1 as word and load byte - 0 - BIG, 1 - LITTLE */
+       addik   r11, r0, 0x1 /* BIG/LITTLE checking value */
+       /* __bss_start will be zeroed later - it is just temp location */
+       swi     r11, r0, TOPHYS(__bss_start)
+       lbui    r11, r0, TOPHYS(__bss_start)
+       beqid   r11, big_endian /* DO NOT break delay stop dependency */
+       lw      r11, r0, r7 /* Big endian load in delay slot */
+       lwr     r11, r0, r7 /* Little endian load */
+big_endian:
+       rsubi   r11, r11, OF_DT_HEADER  /* Check FDT header */
        beqi    r11, _prepare_copy_fdt
        or      r7, r0, r0              /* clear R7 when not valid DTB */
        bnei    r11, no_fdt_arg                 /* No - get out of here */
index 25f6e07..782680d 100644 (file)
        #if CONFIG_XILINX_MICROBLAZE0_USE_BARREL > 0
        #define BSRLI(rD, rA, imm)      \
                bsrli rD, rA, imm
-       #elif CONFIG_XILINX_MICROBLAZE0_USE_DIV > 0
-       #define BSRLI(rD, rA, imm)      \
-               ori rD, r0, (1 << imm); \
-               idivu rD, rD, rA
        #else
        #define BSRLI(rD, rA, imm) BSRLI ## imm (rD, rA)
        /* Only the used shift constants defined here - add more if needed */
index 9ae24f4..47187cc 100644 (file)
@@ -2,88 +2,11 @@
 
 #include <linux/kernel.h>
 #include <linux/string.h>
-#include <linux/pci_regs.h>
 #include <linux/module.h>
 #include <linux/ioport.h>
 #include <linux/etherdevice.h>
 #include <linux/of_address.h>
 #include <asm/prom.h>
-#include <asm/pci-bridge.h>
-
-#ifdef CONFIG_PCI
-int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
-{
-       struct device_node *dn, *ppnode;
-       struct pci_dev *ppdev;
-       u32 lspec;
-       u32 laddr[3];
-       u8 pin;
-       int rc;
-
-       /* Check if we have a device node, if yes, fallback to standard OF
-        * parsing
-        */
-       dn = pci_device_to_OF_node(pdev);
-       if (dn)
-               return of_irq_map_one(dn, 0, out_irq);
-
-       /* Ok, we don't, time to have fun. Let's start by building up an
-        * interrupt spec.  we assume #interrupt-cells is 1, which is standard
-        * for PCI. If you do different, then don't use that routine.
-        */
-       rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin);
-       if (rc != 0)
-               return rc;
-       /* No pin, exit */
-       if (pin == 0)
-               return -ENODEV;
-
-       /* Now we walk up the PCI tree */
-       lspec = pin;
-       for (;;) {
-               /* Get the pci_dev of our parent */
-               ppdev = pdev->bus->self;
-
-               /* Ouch, it's a host bridge... */
-               if (ppdev == NULL) {
-                       struct pci_controller *host;
-                       host = pci_bus_to_host(pdev->bus);
-                       ppnode = host ? host->dn : NULL;
-                       /* No node for host bridge ? give up */
-                       if (ppnode == NULL)
-                               return -EINVAL;
-               } else
-                       /* We found a P2P bridge, check if it has a node */
-                       ppnode = pci_device_to_OF_node(ppdev);
-
-               /* Ok, we have found a parent with a device-node, hand over to
-                * the OF parsing code.
-                * We build a unit address from the linux device to be used for
-                * resolution. Note that we use the linux bus number which may
-                * not match your firmware bus numbering.
-                * Fortunately, in most cases, interrupt-map-mask doesn't
-                * include the bus number as part of the matching.
-                * You should still be careful about that though if you intend
-                * to rely on this function (you ship  a firmware that doesn't
-                * create device nodes for all PCI devices).
-                */
-               if (ppnode)
-                       break;
-
-               /* We can only get here if we hit a P2P bridge with no node,
-                * let's do standard swizzling and try again
-                */
-               lspec = pci_swizzle_interrupt_pin(pdev, lspec);
-               pdev = ppdev;
-       }
-
-       laddr[0] = (pdev->bus->number << 16)
-               | (pdev->devfn << 8);
-       laddr[1]  = laddr[2] = 0;
-       return of_irq_map_raw(ppnode, &lspec, 1, laddr, out_irq);
-}
-EXPORT_SYMBOL_GPL(of_irq_map_pci);
-#endif /* CONFIG_PCI */
 
 void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
                unsigned long *busno, unsigned long *phys, unsigned long *size)
index bb1558e..9312fbb 100644 (file)
@@ -161,11 +161,11 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
 #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
        if (msr)
                eprintk("!!!Your kernel has setup MSR instruction but "
-                               "CPU don't have it %d\n", msr);
+                               "CPU don't have it %x\n", msr);
 #else
        if (!msr)
                eprintk("!!!Your kernel not setup MSR instruction but "
-                               "CPU have it %d\n", msr);
+                               "CPU have it %x\n", msr);
 #endif
 
        for (src = __ivt_start; src < __ivt_end; src++, dst++)
index fdc48bb..62021d7 100644 (file)
  *     between mem locations with size of xfer spec'd in bytes
  */
 
+#ifdef __MICROBLAZEEL__
+#error Microblaze LE not support ASM optimized lib func. Disable OPT_LIB_ASM.
+#endif
+
 #include <linux/linkage.h>
        .text
        .globl  memcpy
index e363615..1e01a12 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/of_pci.h>
 
 #include <asm/processor.h>
 #include <asm/io.h>
index f5ecc05..d889835 100644 (file)
@@ -4,6 +4,7 @@ config MIPS
        select HAVE_GENERIC_DMA_COHERENT
        select HAVE_IDE
        select HAVE_OPROFILE
+       select HAVE_IRQ_WORK
        select HAVE_PERF_EVENTS
        select PERF_USE_VMALLOC
        select HAVE_ARCH_KGDB
@@ -208,6 +209,7 @@ config MACH_JZ4740
        select ARCH_REQUIRE_GPIOLIB
        select SYS_HAS_EARLY_PRINTK
        select HAVE_PWM
+       select HAVE_CLK
 
 config LASAT
        bool "LASAT Networks platforms"
@@ -333,6 +335,8 @@ config PNX8550_STB810
 config PMC_MSP
        bool "PMC-Sierra MSP chipsets"
        depends on EXPERIMENTAL
+       select CEVT_R4K
+       select CSRC_R4K
        select DMA_NONCOHERENT
        select SWAP_IO_SPACE
        select NO_EXCEPT_FILL
index 6398fa9..40b84b9 100644 (file)
@@ -54,8 +54,8 @@ int mtx1_pci_idsel(unsigned int devsel, int assert);
 
 static void mtx1_reset(char *c)
 {
-       /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */
-       au_writel(0x00000000, 0xAE00001C);
+       /* Jump to the reset vector */
+       __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
 }
 
 static void mtx1_power_off(void)
index e30e42a..956f946 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/mtd/physmap.h>
 #include <mtd/mtd-abi.h>
 
+#include <asm/mach-au1x00/au1xxx_eth.h>
+
 static struct gpio_keys_button mtx1_gpio_button[] = {
        {
                .gpio = 207,
@@ -140,10 +142,17 @@ static struct __initdata platform_device * mtx1_devs[] = {
        &mtx1_mtd,
 };
 
+static struct au1000_eth_platform_data mtx1_au1000_eth0_pdata = {
+       .phy_search_highest_addr        = 1,
+       .phy1_search_mac0               = 1,
+};
+
 static int __init mtx1_register_devices(void)
 {
        int rc;
 
+       au1xxx_override_eth_cfg(0, &mtx1_au1000_eth0_pdata);
+
        rc = gpio_request(mtx1_gpio_button[0].gpio,
                                        mtx1_gpio_button[0].desc);
        if (rc < 0) {
index b43c918..80c521e 100644 (file)
@@ -36,8 +36,8 @@
 
 static void xxs1500_reset(char *c)
 {
-       /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */
-       au_writel(0x00000000, 0xAE00001C);
+       /* Jump to the reset vector */
+       __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
 }
 
 static void xxs1500_power_off(void)
index b9cce90..6ebf173 100644 (file)
@@ -75,7 +75,7 @@
 }
 
 static inline int
-futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
 {
        int op = (encoded_op >> 28) & 7;
        int cmp = (encoded_op >> 24) & 15;
@@ -85,7 +85,7 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
        if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
                oparg = 1 << oparg;
 
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
        pagefault_disable();
@@ -132,11 +132,13 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
 }
 
 static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+                             u32 oldval, u32 newval)
 {
-       int retval;
+       int ret = 0;
+       u32 val;
 
-       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
        if (cpu_has_llsc && R10000_LLSC_WAR) {
@@ -145,25 +147,25 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
                "       .set    push                                    \n"
                "       .set    noat                                    \n"
                "       .set    mips3                                   \n"
-               "1:     ll      %0, %2                                  \n"
-               "       bne     %0, %z3, 3f                             \n"
+               "1:     ll      %1, %3                                  \n"
+               "       bne     %1, %z4, 3f                             \n"
                "       .set    mips0                                   \n"
-               "       move    $1, %z4                                 \n"
+               "       move    $1, %z5                                 \n"
                "       .set    mips3                                   \n"
-               "2:     sc      $1, %1                                  \n"
+               "2:     sc      $1, %2                                  \n"
                "       beqzl   $1, 1b                                  \n"
                __WEAK_LLSC_MB
                "3:                                                     \n"
                "       .set    pop                                     \n"
                "       .section .fixup,\"ax\"                          \n"
-               "4:     li      %0, %5                                  \n"
+               "4:     li      %0, %6                                  \n"
                "       j       3b                                      \n"
                "       .previous                                       \n"
                "       .section __ex_table,\"a\"                       \n"
                "       "__UA_ADDR "\t1b, 4b                            \n"
                "       "__UA_ADDR "\t2b, 4b                            \n"
                "       .previous                                       \n"
-               : "=&r" (retval), "=R" (*uaddr)
+               : "+r" (ret), "=&r" (val), "=R" (*uaddr)
                : "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT)
                : "memory");
        } else if (cpu_has_llsc) {
@@ -172,31 +174,32 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
                "       .set    push                                    \n"
                "       .set    noat                                    \n"
                "       .set    mips3                                   \n"
-               "1:     ll      %0, %2                                  \n"
-               "       bne     %0, %z3, 3f                             \n"
+               "1:     ll      %1, %3                                  \n"
+               "       bne     %1, %z4, 3f                             \n"
                "       .set    mips0                                   \n"
-               "       move    $1, %z4                                 \n"
+               "       move    $1, %z5                                 \n"
                "       .set    mips3                                   \n"
-               "2:     sc      $1, %1                                  \n"
+               "2:     sc      $1, %2                                  \n"
                "       beqz    $1, 1b                                  \n"
                __WEAK_LLSC_MB
                "3:                                                     \n"
                "       .set    pop                                     \n"
                "       .section .fixup,\"ax\"                          \n"
-               "4:     li      %0, %5                                  \n"
+               "4:     li      %0, %6                                  \n"
                "       j       3b                                      \n"
                "       .previous                                       \n"
                "       .section __ex_table,\"a\"                       \n"
                "       "__UA_ADDR "\t1b, 4b                            \n"
                "       "__UA_ADDR "\t2b, 4b                            \n"
                "       .previous                                       \n"
-               : "=&r" (retval), "=R" (*uaddr)
+               : "+r" (ret), "=&r" (val), "=R" (*uaddr)
                : "R" (*uaddr), "Jr" (oldval), "Jr" (newval), "i" (-EFAULT)
                : "memory");
        } else
                return -ENOSYS;
 
-       return retval;
+       *uval = val;
+       return ret;
 }
 
 #endif
index e00007c..d0c7749 100644 (file)
 
 #ifndef __MIPS_PERF_EVENT_H__
 #define __MIPS_PERF_EVENT_H__
-
-/*
- * MIPS performance counters do not raise NMI upon overflow, a regular
- * interrupt will be signaled. Hence we can do the pending perf event
- * work at the tail of the irq handler.
- */
-static inline void
-set_perf_event_pending(void)
-{
-}
-
+/* Leave it empty here. The file is required by linux/perf_event.h */
 #endif /* __MIPS_PERF_EVENT_H__ */
index 5a84a1f..94ca2b0 100644 (file)
 #include <asm/cacheflush.h>
 #include <asm/uasm.h>
 
-/*
- * If the Instruction Pointer is in module space (0xc0000000), return true;
- * otherwise, it is in kernel space (0x80000000), return false.
- *
- * FIXME: This will not work when the kernel space and module space are the
- * same. If they are the same, we need to modify scripts/recordmcount.pl,
- * ftrace_make_nop/call() and the other related parts to ensure the
- * enabling/disabling of the calling site to _mcount is right for both kernel
- * and module.
- */
-
-static inline int in_module(unsigned long ip)
-{
-       return ip & 0x40000000;
-}
+#include <asm-generic/sections.h>
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 
 #define JAL 0x0c000000         /* jump & link: ip --> ra, jump to target */
 #define ADDR_MASK 0x03ffffff   /*  op_code|addr : 31...26|25 ....0 */
 
-#define INSN_B_1F_4 0x10000004 /* b 1f; offset = 4 */
-#define INSN_B_1F_5 0x10000005 /* b 1f; offset = 5 */
 #define INSN_NOP 0x00000000    /* nop */
 #define INSN_JAL(addr) \
        ((unsigned int)(JAL | (((addr) >> 2) & ADDR_MASK)))
@@ -69,6 +53,20 @@ static inline void ftrace_dyn_arch_init_insns(void)
 #endif
 }
 
+/*
+ * Check if the address is in kernel space
+ *
+ * Clone core_kernel_text() from kernel/extable.c, but doesn't call
+ * init_kernel_text() for Ftrace doesn't trace functions in init sections.
+ */
+static inline int in_kernel_space(unsigned long ip)
+{
+       if (ip >= (unsigned long)_stext &&
+           ip <= (unsigned long)_etext)
+               return 1;
+       return 0;
+}
+
 static int ftrace_modify_code(unsigned long ip, unsigned int new_code)
 {
        int faulted;
@@ -84,6 +82,42 @@ static int ftrace_modify_code(unsigned long ip, unsigned int new_code)
        return 0;
 }
 
+/*
+ * The details about the calling site of mcount on MIPS
+ *
+ * 1. For kernel:
+ *
+ * move at, ra
+ * jal _mcount         --> nop
+ *
+ * 2. For modules:
+ *
+ * 2.1 For KBUILD_MCOUNT_RA_ADDRESS and CONFIG_32BIT
+ *
+ * lui v1, hi_16bit_of_mcount        --> b 1f (0x10000005)
+ * addiu v1, v1, low_16bit_of_mcount
+ * move at, ra
+ * move $12, ra_address
+ * jalr v1
+ *  sub sp, sp, 8
+ *                                  1: offset = 5 instructions
+ * 2.2 For the Other situations
+ *
+ * lui v1, hi_16bit_of_mcount        --> b 1f (0x10000004)
+ * addiu v1, v1, low_16bit_of_mcount
+ * move at, ra
+ * jalr v1
+ *  nop | move $12, ra_address | sub sp, sp, 8
+ *                                  1: offset = 4 instructions
+ */
+
+#if defined(KBUILD_MCOUNT_RA_ADDRESS) && defined(CONFIG_32BIT)
+#define MCOUNT_OFFSET_INSNS 5
+#else
+#define MCOUNT_OFFSET_INSNS 4
+#endif
+#define INSN_B_1F (0x10000000 | MCOUNT_OFFSET_INSNS)
+
 int ftrace_make_nop(struct module *mod,
                    struct dyn_ftrace *rec, unsigned long addr)
 {
@@ -91,39 +125,11 @@ int ftrace_make_nop(struct module *mod,
        unsigned long ip = rec->ip;
 
        /*
-        * We have compiled module with -mlong-calls, but compiled the kernel
-        * without it, we need to cope with them respectively.
+        * If ip is in kernel space, no long call, otherwise, long call is
+        * needed.
         */
-       if (in_module(ip)) {
-#if defined(KBUILD_MCOUNT_RA_ADDRESS) && defined(CONFIG_32BIT)
-               /*
-                * lui v1, hi_16bit_of_mcount        --> b 1f (0x10000005)
-                * addiu v1, v1, low_16bit_of_mcount
-                * move at, ra
-                * move $12, ra_address
-                * jalr v1
-                *  sub sp, sp, 8
-                *                                  1: offset = 5 instructions
-                */
-               new = INSN_B_1F_5;
-#else
-               /*
-                * lui v1, hi_16bit_of_mcount        --> b 1f (0x10000004)
-                * addiu v1, v1, low_16bit_of_mcount
-                * move at, ra
-                * jalr v1
-                *  nop | move $12, ra_address | sub sp, sp, 8
-                *                                  1: offset = 4 instructions
-                */
-               new = INSN_B_1F_4;
-#endif
-       } else {
-               /*
-                * move at, ra
-                * jal _mcount          --> nop
-                */
-               new = INSN_NOP;
-       }
+       new = in_kernel_space(ip) ? INSN_NOP : INSN_B_1F;
+
        return ftrace_modify_code(ip, new);
 }
 
@@ -132,8 +138,8 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
        unsigned int new;
        unsigned long ip = rec->ip;
 
-       /* ip, module: 0xc0000000, kernel: 0x80000000 */
-       new = in_module(ip) ? insn_lui_v1_hi16_mcount : insn_jal_ftrace_caller;
+       new = in_kernel_space(ip) ? insn_jal_ftrace_caller :
+               insn_lui_v1_hi16_mcount;
 
        return ftrace_modify_code(ip, new);
 }
@@ -190,29 +196,25 @@ int ftrace_disable_ftrace_graph_caller(void)
 #define S_R_SP (0xafb0 << 16)  /* s{d,w} R, offset(sp) */
 #define OFFSET_MASK    0xffff  /* stack offset range: 0 ~ PT_SIZE */
 
-unsigned long ftrace_get_parent_addr(unsigned long self_addr,
-                                    unsigned long parent,
-                                    unsigned long parent_addr,
-                                    unsigned long fp)
+unsigned long ftrace_get_parent_ra_addr(unsigned long self_ra, unsigned long
+               old_parent_ra, unsigned long parent_ra_addr, unsigned long fp)
 {
-       unsigned long sp, ip, ra;
+       unsigned long sp, ip, tmp;
        unsigned int code;
        int faulted;
 
        /*
-        * For module, move the ip from calling site of mcount to the
-        * instruction "lui v1, hi_16bit_of_mcount"(offset is 20), but for
-        * kernel, move to the instruction "move ra, at"(offset is 12)
+        * For module, move the ip from the return address after the
+        * instruction "lui v1, hi_16bit_of_mcount"(offset is 24), but for
+        * kernel, move after the instruction "move ra, at"(offset is 16)
         */
-       ip = self_addr - (in_module(self_addr) ? 20 : 12);
+       ip = self_ra - (in_kernel_space(self_ra) ? 16 : 24);
 
        /*
         * search the text until finding the non-store instruction or "s{d,w}
         * ra, offset(sp)" instruction
         */
        do {
-               ip -= 4;
-
                /* get the code at "ip": code = *(unsigned int *)ip; */
                safe_load_code(code, ip, faulted);
 
@@ -224,18 +226,20 @@ unsigned long ftrace_get_parent_addr(unsigned long self_addr,
                 * store the ra on the stack
                 */
                if ((code & S_R_SP) != S_R_SP)
-                       return parent_addr;
+                       return parent_ra_addr;
 
-       } while (((code & S_RA_SP) != S_RA_SP));
+               /* Move to the next instruction */
+               ip -= 4;
+       } while ((code & S_RA_SP) != S_RA_SP);
 
        sp = fp + (code & OFFSET_MASK);
 
-       /* ra = *(unsigned long *)sp; */
-       safe_load_stack(ra, sp, faulted);
+       /* tmp = *(unsigned long *)sp; */
+       safe_load_stack(tmp, sp, faulted);
        if (unlikely(faulted))
                return 0;
 
-       if (ra == parent)
+       if (tmp == old_parent_ra)
                return sp;
        return 0;
 }
@@ -246,21 +250,21 @@ unsigned long ftrace_get_parent_addr(unsigned long self_addr,
  * Hook the return address and push it in the stack of return addrs
  * in current thread info.
  */
-void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
+void prepare_ftrace_return(unsigned long *parent_ra_addr, unsigned long self_ra,
                           unsigned long fp)
 {
-       unsigned long old;
+       unsigned long old_parent_ra;
        struct ftrace_graph_ent trace;
        unsigned long return_hooker = (unsigned long)
            &return_to_handler;
-       int faulted;
+       int faulted, insns;
 
        if (unlikely(atomic_read(&current->tracing_graph_pause)))
                return;
 
        /*
-        * "parent" is the stack address saved the return address of the caller
-        * of _mcount.
+        * "parent_ra_addr" is the stack address saved the return address of
+        * the caller of _mcount.
         *
         * if the gcc < 4.5, a leaf function does not save the return address
         * in the stack address, so, we "emulate" one in _mcount's stack space,
@@ -275,37 +279,44 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
         * do it in ftrace_graph_caller of mcount.S.
         */
 
-       /* old = *parent; */
-       safe_load_stack(old, parent, faulted);
+       /* old_parent_ra = *parent_ra_addr; */
+       safe_load_stack(old_parent_ra, parent_ra_addr, faulted);
        if (unlikely(faulted))
                goto out;
 #ifndef KBUILD_MCOUNT_RA_ADDRESS
-       parent = (unsigned long *)ftrace_get_parent_addr(self_addr, old,
-                       (unsigned long)parent, fp);
+       parent_ra_addr = (unsigned long *)ftrace_get_parent_ra_addr(self_ra,
+                       old_parent_ra, (unsigned long)parent_ra_addr, fp);
        /*
         * If fails when getting the stack address of the non-leaf function's
         * ra, stop function graph tracer and return
         */
-       if (parent == 0)
+       if (parent_ra_addr == 0)
                goto out;
 #endif
-       /* *parent = return_hooker; */
-       safe_store_stack(return_hooker, parent, faulted);
+       /* *parent_ra_addr = return_hooker; */
+       safe_store_stack(return_hooker, parent_ra_addr, faulted);
        if (unlikely(faulted))
                goto out;
 
-       if (ftrace_push_return_trace(old, self_addr, &trace.depth, fp) ==
-           -EBUSY) {
-               *parent = old;
+       if (ftrace_push_return_trace(old_parent_ra, self_ra, &trace.depth, fp)
+           == -EBUSY) {
+               *parent_ra_addr = old_parent_ra;
                return;
        }
 
-       trace.func = self_addr;
+       /*
+        * Get the recorded ip of the current mcount calling site in the
+        * __mcount_loc section, which will be used to filter the function
+        * entries configured through the tracing/set_graph_function interface.
+        */
+
+       insns = in_kernel_space(self_ra) ? 2 : MCOUNT_OFFSET_INSNS + 1;
+       trace.func = self_ra - (MCOUNT_INSN_SIZE * insns);
 
        /* Only trace if the calling function expects to */
        if (!ftrace_graph_entry(&trace)) {
                current->curr_ret_stack--;
-               *parent = old;
+               *parent_ra_addr = old_parent_ra;
        }
        return;
 out:
index 2b7f3f7..a824485 100644 (file)
@@ -161,41 +161,6 @@ mipspmu_event_set_period(struct perf_event *event,
        return ret;
 }
 
-static int mipspmu_enable(struct perf_event *event)
-{
-       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
-       struct hw_perf_event *hwc = &event->hw;
-       int idx;
-       int err = 0;
-
-       /* To look for a free counter for this event. */
-       idx = mipspmu->alloc_counter(cpuc, hwc);
-       if (idx < 0) {
-               err = idx;
-               goto out;
-       }
-
-       /*
-        * If there is an event in the counter we are going to use then
-        * make sure it is disabled.
-        */
-       event->hw.idx = idx;
-       mipspmu->disable_event(idx);
-       cpuc->events[idx] = event;
-
-       /* Set the period for the event. */
-       mipspmu_event_set_period(event, hwc, idx);
-
-       /* Enable the event. */
-       mipspmu->enable_event(hwc, idx);
-
-       /* Propagate our changes to the userspace mapping. */
-       perf_event_update_userpage(event);
-
-out:
-       return err;
-}
-
 static void mipspmu_event_update(struct perf_event *event,
                        struct hw_perf_event *hwc,
                        int idx)
@@ -204,7 +169,7 @@ static void mipspmu_event_update(struct perf_event *event,
        unsigned long flags;
        int shift = 64 - TOTAL_BITS;
        s64 prev_raw_count, new_raw_count;
-       s64 delta;
+       u64 delta;
 
 again:
        prev_raw_count = local64_read(&hwc->prev_count);
@@ -231,32 +196,90 @@ again:
        return;
 }
 
-static void mipspmu_disable(struct perf_event *event)
+static void mipspmu_start(struct perf_event *event, int flags)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (!mipspmu)
+               return;
+
+       if (flags & PERF_EF_RELOAD)
+               WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
+
+       hwc->state = 0;
+
+       /* Set the period for the event. */
+       mipspmu_event_set_period(event, hwc, hwc->idx);
+
+       /* Enable the event. */
+       mipspmu->enable_event(hwc, hwc->idx);
+}
+
+static void mipspmu_stop(struct perf_event *event, int flags)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (!mipspmu)
+               return;
+
+       if (!(hwc->state & PERF_HES_STOPPED)) {
+               /* We are working on a local event. */
+               mipspmu->disable_event(hwc->idx);
+               barrier();
+               mipspmu_event_update(event, hwc, hwc->idx);
+               hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
+       }
+}
+
+static int mipspmu_add(struct perf_event *event, int flags)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        struct hw_perf_event *hwc = &event->hw;
-       int idx = hwc->idx;
+       int idx;
+       int err = 0;
 
+       perf_pmu_disable(event->pmu);
 
-       WARN_ON(idx < 0 || idx >= mipspmu->num_counters);
+       /* To look for a free counter for this event. */
+       idx = mipspmu->alloc_counter(cpuc, hwc);
+       if (idx < 0) {
+               err = idx;
+               goto out;
+       }
 
-       /* We are working on a local event. */
+       /*
+        * If there is an event in the counter we are going to use then
+        * make sure it is disabled.
+        */
+       event->hw.idx = idx;
        mipspmu->disable_event(idx);
+       cpuc->events[idx] = event;
 
-       barrier();
-
-       mipspmu_event_update(event, hwc, idx);
-       cpuc->events[idx] = NULL;
-       clear_bit(idx, cpuc->used_mask);
+       hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
+       if (flags & PERF_EF_START)
+               mipspmu_start(event, PERF_EF_RELOAD);
 
+       /* Propagate our changes to the userspace mapping. */
        perf_event_update_userpage(event);
+
+out:
+       perf_pmu_enable(event->pmu);
+       return err;
 }
 
-static void mipspmu_unthrottle(struct perf_event *event)
+static void mipspmu_del(struct perf_event *event, int flags)
 {
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        struct hw_perf_event *hwc = &event->hw;
+       int idx = hwc->idx;
 
-       mipspmu->enable_event(hwc, hwc->idx);
+       WARN_ON(idx < 0 || idx >= mipspmu->num_counters);
+
+       mipspmu_stop(event, PERF_EF_UPDATE);
+       cpuc->events[idx] = NULL;
+       clear_bit(idx, cpuc->used_mask);
+
+       perf_event_update_userpage(event);
 }
 
 static void mipspmu_read(struct perf_event *event)
@@ -270,12 +293,17 @@ static void mipspmu_read(struct perf_event *event)
        mipspmu_event_update(event, hwc, hwc->idx);
 }
 
-static struct pmu pmu = {
-       .enable         = mipspmu_enable,
-       .disable        = mipspmu_disable,
-       .unthrottle     = mipspmu_unthrottle,
-       .read           = mipspmu_read,
-};
+static void mipspmu_enable(struct pmu *pmu)
+{
+       if (mipspmu)
+               mipspmu->start();
+}
+
+static void mipspmu_disable(struct pmu *pmu)
+{
+       if (mipspmu)
+               mipspmu->stop();
+}
 
 static atomic_t active_events = ATOMIC_INIT(0);
 static DEFINE_MUTEX(pmu_reserve_mutex);
@@ -318,6 +346,82 @@ static void mipspmu_free_irq(void)
                perf_irq = save_perf_irq;
 }
 
+/*
+ * mipsxx/rm9000/loongson2 have different performance counters, they have
+ * specific low-level init routines.
+ */
+static void reset_counters(void *arg);
+static int __hw_perf_event_init(struct perf_event *event);
+
+static void hw_perf_event_destroy(struct perf_event *event)
+{
+       if (atomic_dec_and_mutex_lock(&active_events,
+                               &pmu_reserve_mutex)) {
+               /*
+                * We must not call the destroy function with interrupts
+                * disabled.
+                */
+               on_each_cpu(reset_counters,
+                       (void *)(long)mipspmu->num_counters, 1);
+               mipspmu_free_irq();
+               mutex_unlock(&pmu_reserve_mutex);
+       }
+}
+
+static int mipspmu_event_init(struct perf_event *event)
+{
+       int err = 0;
+
+       switch (event->attr.type) {
+       case PERF_TYPE_RAW:
+       case PERF_TYPE_HARDWARE:
+       case PERF_TYPE_HW_CACHE:
+               break;
+
+       default:
+               return -ENOENT;
+       }
+
+       if (!mipspmu || event->cpu >= nr_cpumask_bits ||
+               (event->cpu >= 0 && !cpu_online(event->cpu)))
+               return -ENODEV;
+
+       if (!atomic_inc_not_zero(&active_events)) {
+               if (atomic_read(&active_events) > MIPS_MAX_HWEVENTS) {
+                       atomic_dec(&active_events);
+                       return -ENOSPC;
+               }
+
+               mutex_lock(&pmu_reserve_mutex);
+               if (atomic_read(&active_events) == 0)
+                       err = mipspmu_get_irq();
+
+               if (!err)
+                       atomic_inc(&active_events);
+               mutex_unlock(&pmu_reserve_mutex);
+       }
+
+       if (err)
+               return err;
+
+       err = __hw_perf_event_init(event);
+       if (err)
+               hw_perf_event_destroy(event);
+
+       return err;
+}
+
+static struct pmu pmu = {
+       .pmu_enable     = mipspmu_enable,
+       .pmu_disable    = mipspmu_disable,
+       .event_init     = mipspmu_event_init,
+       .add            = mipspmu_add,
+       .del            = mipspmu_del,
+       .start          = mipspmu_start,
+       .stop           = mipspmu_stop,
+       .read           = mipspmu_read,
+};
+
 static inline unsigned int
 mipspmu_perf_event_encode(const struct mips_perf_event *pev)
 {
@@ -382,8 +486,9 @@ static int validate_event(struct cpu_hw_events *cpuc,
 {
        struct hw_perf_event fake_hwc = event->hw;
 
-       if (event->pmu && event->pmu != &pmu)
-               return 0;
+       /* Allow mixed event group. So return 1 to pass validation. */
+       if (event->pmu != &pmu || event->state <= PERF_EVENT_STATE_OFF)
+               return 1;
 
        return mipspmu->alloc_counter(cpuc, &fake_hwc) >= 0;
 }
@@ -409,73 +514,6 @@ static int validate_group(struct perf_event *event)
        return 0;
 }
 
-/*
- * mipsxx/rm9000/loongson2 have different performance counters, they have
- * specific low-level init routines.
- */
-static void reset_counters(void *arg);
-static int __hw_perf_event_init(struct perf_event *event);
-
-static void hw_perf_event_destroy(struct perf_event *event)
-{
-       if (atomic_dec_and_mutex_lock(&active_events,
-                               &pmu_reserve_mutex)) {
-               /*
-                * We must not call the destroy function with interrupts
-                * disabled.
-                */
-               on_each_cpu(reset_counters,
-                       (void *)(long)mipspmu->num_counters, 1);
-               mipspmu_free_irq();
-               mutex_unlock(&pmu_reserve_mutex);
-       }
-}
-
-const struct pmu *hw_perf_event_init(struct perf_event *event)
-{
-       int err = 0;
-
-       if (!mipspmu || event->cpu >= nr_cpumask_bits ||
-               (event->cpu >= 0 && !cpu_online(event->cpu)))
-               return ERR_PTR(-ENODEV);
-
-       if (!atomic_inc_not_zero(&active_events)) {
-               if (atomic_read(&active_events) > MIPS_MAX_HWEVENTS) {
-                       atomic_dec(&active_events);
-                       return ERR_PTR(-ENOSPC);
-               }
-
-               mutex_lock(&pmu_reserve_mutex);
-               if (atomic_read(&active_events) == 0)
-                       err = mipspmu_get_irq();
-
-               if (!err)
-                       atomic_inc(&active_events);
-               mutex_unlock(&pmu_reserve_mutex);
-       }
-
-       if (err)
-               return ERR_PTR(err);
-
-       err = __hw_perf_event_init(event);
-       if (err)
-               hw_perf_event_destroy(event);
-
-       return err ? ERR_PTR(err) : &pmu;
-}
-
-void hw_perf_enable(void)
-{
-       if (mipspmu)
-               mipspmu->start();
-}
-
-void hw_perf_disable(void)
-{
-       if (mipspmu)
-               mipspmu->stop();
-}
-
 /* This is needed by specific irq handlers in perf_event_*.c */
 static void
 handle_associated_event(struct cpu_hw_events *cpuc,
@@ -496,21 +534,13 @@ handle_associated_event(struct cpu_hw_events *cpuc,
 #include "perf_event_mipsxx.c"
 
 /* Callchain handling code. */
-static inline void
-callchain_store(struct perf_callchain_entry *entry,
-               u64 ip)
-{
-       if (entry->nr < PERF_MAX_STACK_DEPTH)
-               entry->ip[entry->nr++] = ip;
-}
 
 /*
  * Leave userspace callchain empty for now. When we find a way to trace
  * the user stack callchains, we add here.
  */
-static void
-perf_callchain_user(struct pt_regs *regs,
-                   struct perf_callchain_entry *entry)
+void perf_callchain_user(struct perf_callchain_entry *entry,
+                   struct pt_regs *regs)
 {
 }
 
@@ -523,23 +553,21 @@ static void save_raw_perf_callchain(struct perf_callchain_entry *entry,
        while (!kstack_end(sp)) {
                addr = *sp++;
                if (__kernel_text_address(addr)) {
-                       callchain_store(entry, addr);
+                       perf_callchain_store(entry, addr);
                        if (entry->nr >= PERF_MAX_STACK_DEPTH)
                                break;
                }
        }
 }
 
-static void
-perf_callchain_kernel(struct pt_regs *regs,
-                     struct perf_callchain_entry *entry)
+void perf_callchain_kernel(struct perf_callchain_entry *entry,
+                     struct pt_regs *regs)
 {
        unsigned long sp = regs->regs[29];
 #ifdef CONFIG_KALLSYMS
        unsigned long ra = regs->regs[31];
        unsigned long pc = regs->cp0_epc;
 
-       callchain_store(entry, PERF_CONTEXT_KERNEL);
        if (raw_show_trace || !__kernel_text_address(pc)) {
                unsigned long stack_page =
                        (unsigned long)task_stack_page(current);
@@ -549,53 +577,12 @@ perf_callchain_kernel(struct pt_regs *regs,
                return;
        }
        do {
-               callchain_store(entry, pc);
+               perf_callchain_store(entry, pc);
                if (entry->nr >= PERF_MAX_STACK_DEPTH)
                        break;
                pc = unwind_stack(current, &sp, pc, &ra);
        } while (pc);
 #else
-       callchain_store(entry, PERF_CONTEXT_KERNEL);
        save_raw_perf_callchain(entry, sp);
 #endif
 }
-
-static void
-perf_do_callchain(struct pt_regs *regs,
-                 struct perf_callchain_entry *entry)
-{
-       int is_user;
-
-       if (!regs)
-               return;
-
-       is_user = user_mode(regs);
-
-       if (!current || !current->pid)
-               return;
-
-       if (is_user && current->state != TASK_RUNNING)
-               return;
-
-       if (!is_user) {
-               perf_callchain_kernel(regs, entry);
-               if (current->mm)
-                       regs = task_pt_regs(current);
-               else
-                       regs = NULL;
-       }
-       if (regs)
-               perf_callchain_user(regs, entry);
-}
-
-static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_irq_entry);
-
-struct perf_callchain_entry *
-perf_callchain(struct pt_regs *regs)
-{
-       struct perf_callchain_entry *entry = &__get_cpu_var(pmc_irq_entry);
-
-       entry->nr = 0;
-       perf_do_callchain(regs, entry);
-       return entry;
-}
index 183e0d2..d9a7db7 100644 (file)
@@ -696,7 +696,7 @@ static int mipsxx_pmu_handle_shared_irq(void)
         * interrupt, not NMI.
         */
        if (handled == IRQ_HANDLED)
-               perf_event_do_pending();
+               irq_work_run();
 
 #ifdef CONFIG_MIPS_MT_SMP
        read_unlock(&pmuint_rwlock);
@@ -1045,6 +1045,8 @@ init_hw_perf_events(void)
                        "CPU, irq %d%s\n", mipspmu->name, counters, irq,
                        irq < 0 ? " (share with timer interrupt)" : "");
 
+       perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
+
        return 0;
 }
 early_initcall(init_hw_perf_events);
index 5922342..dbbe0ce 100644 (file)
@@ -84,7 +84,7 @@ static int protected_save_fp_context(struct sigcontext __user *sc)
 
 static int protected_restore_fp_context(struct sigcontext __user *sc)
 {
-       int err, tmp;
+       int err, tmp __maybe_unused;
        while (1) {
                lock_fpu_owner();
                own_fpu_inatomic(0);
index a0ed0e0..aae9866 100644 (file)
@@ -115,7 +115,7 @@ static int protected_save_fp_context32(struct sigcontext32 __user *sc)
 
 static int protected_restore_fp_context32(struct sigcontext32 __user *sc)
 {
-       int err, tmp;
+       int err, tmp __maybe_unused;
        while (1) {
                lock_fpu_owner();
                own_fpu_inatomic(0);
index 383aeb9..32a2561 100644 (file)
@@ -193,6 +193,22 @@ void __devinit smp_prepare_boot_cpu(void)
  */
 static struct task_struct *cpu_idle_thread[NR_CPUS];
 
+struct create_idle {
+       struct work_struct work;
+       struct task_struct *idle;
+       struct completion done;
+       int cpu;
+};
+
+static void __cpuinit do_fork_idle(struct work_struct *work)
+{
+       struct create_idle *c_idle =
+               container_of(work, struct create_idle, work);
+
+       c_idle->idle = fork_idle(c_idle->cpu);
+       complete(&c_idle->done);
+}
+
 int __cpuinit __cpu_up(unsigned int cpu)
 {
        struct task_struct *idle;
@@ -203,8 +219,19 @@ int __cpuinit __cpu_up(unsigned int cpu)
         * Linux can schedule processes on this slave.
         */
        if (!cpu_idle_thread[cpu]) {
-               idle = fork_idle(cpu);
-               cpu_idle_thread[cpu] = idle;
+               /*
+                * Schedule work item to avoid forking user task
+                * Ported from arch/x86/kernel/smpboot.c
+                */
+               struct create_idle c_idle = {
+                       .cpu    = cpu,
+                       .done   = COMPLETION_INITIALIZER_ONSTACK(c_idle.done),
+               };
+
+               INIT_WORK_ONSTACK(&c_idle.work, do_fork_idle);
+               schedule_work(&c_idle.work);
+               wait_for_completion(&c_idle.done);
+               idle = cpu_idle_thread[cpu] = c_idle.idle;
 
                if (IS_ERR(idle))
                        panic(KERN_ERR "Fork failed for CPU %d", cpu);
index 1dc6edf..58beabf 100644 (file)
@@ -383,12 +383,11 @@ save_static_function(sys_sysmips);
 static int __used noinline
 _sys_sysmips(nabi_no_regargs struct pt_regs regs)
 {
-       long cmd, arg1, arg2, arg3;
+       long cmd, arg1, arg2;
 
        cmd = regs.regs[4];
        arg1 = regs.regs[5];
        arg2 = regs.regs[6];
-       arg3 = regs.regs[7];
 
        switch (cmd) {
        case MIPS_ATOMIC_SET:
@@ -405,7 +404,7 @@ _sys_sysmips(nabi_no_regargs struct pt_regs regs)
                if (arg1 & 2)
                        set_thread_flag(TIF_LOGADE);
                else
-                       clear_thread_flag(TIF_FIXADE);
+                       clear_thread_flag(TIF_LOGADE);
 
                return 0;
 
index 6a1fdfe..ab52b7c 100644 (file)
@@ -148,9 +148,9 @@ struct {
        spinlock_t tc_list_lock;
        struct list_head tc_list;       /* Thread contexts */
 } vpecontrol = {
-       .vpe_list_lock  = SPIN_LOCK_UNLOCKED,
+       .vpe_list_lock  = __SPIN_LOCK_UNLOCKED(vpe_list_lock),
        .vpe_list       = LIST_HEAD_INIT(vpecontrol.vpe_list),
-       .tc_list_lock   = SPIN_LOCK_UNLOCKED,
+       .tc_list_lock   = __SPIN_LOCK_UNLOCKED(tc_list_lock),
        .tc_list        = LIST_HEAD_INIT(vpecontrol.tc_list)
 };
 
index 6e1b77f..aca93ee 100644 (file)
@@ -1,6 +1,7 @@
+if MACH_LOONGSON
+
 choice
        prompt "Machine Type"
-       depends on MACH_LOONGSON
 
 config LEMOTE_FULOONG2E
        bool "Lemote Fuloong(2e) mini-PC"
@@ -87,3 +88,5 @@ config LOONGSON_UART_BASE
 config LOONGSON_MC146818
        bool
        default n
+
+endif # MACH_LOONGSON
index 1a06def..353e1d2 100644 (file)
@@ -44,10 +44,5 @@ void __init prom_init_cmdline(void)
                strcat(arcs_cmdline, " ");
        }
 
-       if ((strstr(arcs_cmdline, "console=")) == NULL)
-               strcat(arcs_cmdline, " console=ttyS0,115200");
-       if ((strstr(arcs_cmdline, "root=")) == NULL)
-               strcat(arcs_cmdline, " root=/dev/hda1");
-
        prom_init_machtype();
 }
index 81fbe6b..2efd5d9 100644 (file)
@@ -41,7 +41,7 @@ void __weak __init mach_prom_init_machtype(void)
 
 void __init prom_init_machtype(void)
 {
-       char *p, str[MACHTYPE_LEN];
+       char *p, str[MACHTYPE_LEN + 1];
        int machtype = MACH_LEMOTE_FL2E;
 
        mips_machtype = LOONGSON_MACHTYPE;
@@ -53,6 +53,7 @@ void __init prom_init_machtype(void)
        }
        p += strlen("machtype=");
        strncpy(str, p, MACHTYPE_LEN);
+       str[MACHTYPE_LEN] = '\0';
        p = strstr(str, " ");
        if (p)
                *p = '\0';
index 2701d95..2a7d43f 100644 (file)
@@ -70,7 +70,7 @@
 
 
 #define COMPXSP \
-  unsigned xm; int xe; int xs; int xc
+  unsigned xm; int xe; int xs __maybe_unused; int xc
 
 #define COMPYSP \
   unsigned ym; int ye; int ys; int yc
 
 
 #define COMPXDP \
-u64 xm; int xe; int xs; int xc
+u64 xm; int xe; int xs __maybe_unused; int xc
 
 #define COMPYDP \
 u64 ym; int ye; int ys; int yc
index 2efcbd2..279599e 100644 (file)
@@ -324,7 +324,7 @@ int page_is_ram(unsigned long pagenr)
 void __init paging_init(void)
 {
        unsigned long max_zone_pfns[MAX_NR_ZONES];
-       unsigned long lastpfn;
+       unsigned long lastpfn __maybe_unused;
 
        pagetable_init();
 
index 083d341..04f9e17 100644 (file)
@@ -109,6 +109,8 @@ static bool scratchpad_available(void)
 static int scratchpad_offset(int i)
 {
        BUG();
+       /* Really unreachable, but evidently some GCC want this. */
+       return 0;
 }
 #endif
 /*
index b7c03d8..68798f8 100644 (file)
@@ -308,7 +308,7 @@ static struct resource pci_mem_resource = {
  *  RETURNS:     PCIBIOS_SUCCESSFUL  - success
  *
  ****************************************************************************/
-static int bpci_interrupt(int irq, void *dev_id)
+static irqreturn_t bpci_interrupt(int irq, void *dev_id)
 {
        struct msp_pci_regs *preg = (void *)PCI_BASE_REG;
        unsigned int stat = preg->if_status;
@@ -326,7 +326,7 @@ static int bpci_interrupt(int irq, void *dev_id)
        /* write to clear all asserted interrupts */
        preg->if_status = stat;
 
-       return PCIBIOS_SUCCESSFUL;
+       return IRQ_HANDLED;
 }
 
 /*****************************************************************************
index c139988..8d79849 100644 (file)
@@ -4,15 +4,11 @@ choice
 
 config PMC_MSP4200_EVAL
        bool "PMC-Sierra MSP4200 Eval Board"
-       select CEVT_R4K
-       select CSRC_R4K
        select IRQ_MSP_SLP
        select HW_HAS_PCI
 
 config PMC_MSP4200_GW
        bool "PMC-Sierra MSP4200 VoIP Gateway"
-       select CEVT_R4K
-       select CSRC_R4K
        select IRQ_MSP_SLP
        select HW_HAS_PCI
 
index cca64e1..01df84c 100644 (file)
@@ -81,7 +81,7 @@ void __init plat_time_init(void)
        mips_hpt_frequency = cpu_rate/2;
 }
 
-unsigned int __init get_c0_compare_int(void)
+unsigned int __cpuinit get_c0_compare_int(void)
 {
        return MSP_INT_VPE0_TIMER;
 }
index 92d2f92..9d773a6 100644 (file)
@@ -139,7 +139,7 @@ static inline unsigned long __cmpxchg(volatile unsigned long *m,
  * Atomically reads the value of @v.  Note that the guaranteed
  * useful range of an atomic_t is only 24 bits.
  */
-#define atomic_read(v) ((v)->counter)
+#define atomic_read(v) (ACCESS_ONCE((v)->counter))
 
 /**
  * atomic_set - set atomic variable
index 679dee0..3d6e60d 100644 (file)
@@ -160,9 +160,10 @@ struct __large_struct { unsigned long buf[100]; };
 
 #define __get_user_check(x, ptr, size)                                 \
 ({                                                                     \
+       const __typeof__(ptr) __guc_ptr = (ptr);                        \
        int _e;                                                         \
-       if (likely(__access_ok((unsigned long) (ptr), (size))))         \
-               _e = __get_user_nocheck((x), (ptr), (size));            \
+       if (likely(__access_ok((unsigned long) __guc_ptr, (size))))     \
+               _e = __get_user_nocheck((x), __guc_ptr, (size));        \
        else {                                                          \
                _e = -EFAULT;                                           \
                (x) = (__typeof__(x))0;                                 \
index 75da468..5b95500 100644 (file)
@@ -104,8 +104,6 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
        unsigned tsc, elapse;
        irqreturn_t ret;
 
-       write_seqlock(&xtime_lock);
-
        while (tsc = get_cycles(),
               elapse = tsc - mn10300_last_tsc, /* time elapsed since last
                                                 * tick */
@@ -114,11 +112,9 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
                mn10300_last_tsc += MN10300_TSC_PER_HZ;
 
                /* advance the kernel's time tracking system */
-               do_timer(1);
+               xtime_update(1);
        }
 
-       write_sequnlock(&xtime_lock);
-
        ret = local_timer_interrupt();
 #ifdef CONFIG_SMP
        send_IPI_allbutself(LOCAL_TIMER_IPI);
index a8933a6..a6b63dd 100644 (file)
@@ -69,7 +69,7 @@ static void flush_icache_page_range(unsigned long start, unsigned long end)
 
        /* invalidate the icache coverage on that region */
        mn10300_local_icache_inv_range2(addr + off, size);
-       smp_cache_call(SMP_ICACHE_INV_FLUSH_RANGE, start, end);
+       smp_cache_call(SMP_ICACHE_INV_RANGE, start, end);
 }
 
 /**
@@ -101,7 +101,7 @@ void flush_icache_range(unsigned long start, unsigned long end)
                 * directly */
                start_page = (start >= 0x80000000UL) ? start : 0x80000000UL;
                mn10300_icache_inv_range(start_page, end);
-               smp_cache_call(SMP_ICACHE_INV_FLUSH_RANGE, start, end);
+               smp_cache_call(SMP_ICACHE_INV_RANGE, start, end);
                if (start_page == start)
                        goto done;
                end = start_page;
index 3039408..6ab9580 100644 (file)
@@ -185,26 +185,21 @@ struct hpux_statfs {
      int16_t f_pad;
 };
 
-static int do_statfs_hpux(struct path *path, struct hpux_statfs *buf)
+static int do_statfs_hpux(struct kstatfs *st, struct hpux_statfs __user *p)
 {
-       struct kstatfs st;
-       int retval;
-       
-       retval = vfs_statfs(path, &st);
-       if (retval)
-               return retval;
-
-       memset(buf, 0, sizeof(*buf));
-       buf->f_type = st.f_type;
-       buf->f_bsize = st.f_bsize;
-       buf->f_blocks = st.f_blocks;
-       buf->f_bfree = st.f_bfree;
-       buf->f_bavail = st.f_bavail;
-       buf->f_files = st.f_files;
-       buf->f_ffree = st.f_ffree;
-       buf->f_fsid[0] = st.f_fsid.val[0];
-       buf->f_fsid[1] = st.f_fsid.val[1];
-
+       struct hpux_statfs buf;
+       memset(&buf, 0, sizeof(buf));
+       buf.f_type = st->f_type;
+       buf.f_bsize = st->f_bsize;
+       buf.f_blocks = st->f_blocks;
+       buf.f_bfree = st->f_bfree;
+       buf.f_bavail = st->f_bavail;
+       buf.f_files = st->f_files;
+       buf.f_ffree = st->f_ffree;
+       buf.f_fsid[0] = st->f_fsid.val[0];
+       buf.f_fsid[1] = st->f_fsid.val[1];
+       if (copy_to_user(p, &buf, sizeof(buf)))
+               return -EFAULT;
        return 0;
 }
 
@@ -212,35 +207,19 @@ static int do_statfs_hpux(struct path *path, struct hpux_statfs *buf)
 asmlinkage long hpux_statfs(const char __user *pathname,
                                                struct hpux_statfs __user *buf)
 {
-       struct path path;
-       int error;
-
-       error = user_path(pathname, &path);
-       if (!error) {
-               struct hpux_statfs tmp;
-               error = do_statfs_hpux(&path, &tmp);
-               if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
-                       error = -EFAULT;
-               path_put(&path);
-       }
+       struct kstatfs st;
+       int error = user_statfs(pathname, &st);
+       if (!error)
+               error = do_statfs_hpux(&st, buf);
        return error;
 }
 
 asmlinkage long hpux_fstatfs(unsigned int fd, struct hpux_statfs __user * buf)
 {
-       struct file *file;
-       struct hpux_statfs tmp;
-       int error;
-
-       error = -EBADF;
-       file = fget(fd);
-       if (!file)
-               goto out;
-       error = do_statfs_hpux(&file->f_path, &tmp);
-       if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
-               error = -EFAULT;
-       fput(file);
- out:
+       struct kstatfs st;
+       int error = fd_statfs(fd, &st);
+       if (!error)
+               error = do_statfs_hpux(&st, buf);
        return error;
 }
 
index f357fc6..0304b92 100644 (file)
@@ -19,6 +19,8 @@
 #define O_NOFOLLOW     000000200 /* don't follow links */
 #define O_INVISIBLE    004000000 /* invisible I/O, for DMAPI/XDSM */
 
+#define O_PATH         020000000
+
 #define F_GETLK64      8
 #define F_SETLK64      9
 #define F_SETLKW64     10
index 0c705c3..67a33cc 100644 (file)
@@ -8,7 +8,7 @@
 #include <asm/errno.h>
 
 static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
 {
        int op = (encoded_op >> 28) & 7;
        int cmp = (encoded_op >> 24) & 15;
@@ -18,7 +18,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
        if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
                oparg = 1 << oparg;
 
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
        pagefault_disable();
@@ -51,10 +51,10 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
 
 /* Non-atomic version */
 static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+                             u32 oldval, u32 newval)
 {
-       int err = 0;
-       int uval;
+       u32 val;
 
        /* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is
         * our gateway page, and causes no end of trouble...
@@ -62,15 +62,15 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
        if (segment_eq(KERNEL_DS, get_fs()) && !uaddr)
                return -EFAULT;
 
-       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
-       err = get_user(uval, uaddr);
-       if (err) return -EFAULT;
-       if (uval == oldval)
-               err = put_user(newval, uaddr);
-       if (err) return -EFAULT;
-       return uval;
+       if (get_user(val, uaddr))
+               return -EFAULT;
+       if (val == oldval && put_user(newval, uaddr))
+               return -EFAULT;
+       *uval = val;
+       return 0;
 }
 
 #endif /*__KERNEL__*/
index 11bdd68..fc770be 100644 (file)
@@ -169,11 +169,11 @@ static int __init pdc_console_tty_driver_init(void)
 
        struct console *tmp;
 
-       acquire_console_sem();
+       console_lock();
        for_each_console(tmp)
                if (tmp == &pdc_cons)
                        break;
-       release_console_sem();
+       console_unlock();
 
        if (!tmp) {
                printk(KERN_INFO "PDC console driver not registered anymore, not creating %s\n", pdc_cons.name);
index 05511cc..45b7389 100644 (file)
@@ -162,11 +162,8 @@ irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id)
                update_process_times(user_mode(get_irq_regs()));
        }
 
-       if (cpu == 0) {
-               write_seqlock(&xtime_lock);
-               do_timer(ticks_elapsed);
-               write_sequnlock(&xtime_lock);
-       }
+       if (cpu == 0)
+               xtime_update(ticks_elapsed);
 
        return IRQ_HANDLED;
 }
index 7c589ef..c94e4a3 100644 (file)
@@ -30,7 +30,7 @@
        : "b" (uaddr), "i" (-EFAULT), "r" (oparg) \
        : "cr0", "memory")
 
-static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
 {
        int op = (encoded_op >> 28) & 7;
        int cmp = (encoded_op >> 24) & 15;
@@ -40,7 +40,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
        if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
                oparg = 1 << oparg;
 
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
        pagefault_disable();
@@ -82,35 +82,38 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
 }
 
 static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+                             u32 oldval, u32 newval)
 {
-       int prev;
+       int ret = 0;
+       u32 prev;
 
-       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
         __asm__ __volatile__ (
         PPC_RELEASE_BARRIER
-"1:     lwarx   %0,0,%2         # futex_atomic_cmpxchg_inatomic\n\
-        cmpw    0,%0,%3\n\
+"1:     lwarx   %1,0,%3         # futex_atomic_cmpxchg_inatomic\n\
+        cmpw    0,%1,%4\n\
         bne-    3f\n"
-        PPC405_ERR77(0,%2)
-"2:     stwcx.  %4,0,%2\n\
+        PPC405_ERR77(0,%3)
+"2:     stwcx.  %5,0,%3\n\
         bne-    1b\n"
         PPC_ACQUIRE_BARRIER
 "3:    .section .fixup,\"ax\"\n\
-4:     li      %0,%5\n\
+4:     li      %0,%6\n\
        b       3b\n\
        .previous\n\
        .section __ex_table,\"a\"\n\
        .align 3\n\
        " PPC_LONG "1b,4b,2b,4b\n\
        .previous" \
-        : "=&r" (prev), "+m" (*uaddr)
+        : "+r" (ret), "=&r" (prev), "+m" (*uaddr)
         : "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT)
         : "cc", "memory");
 
-        return prev;
+       *uval = prev;
+        return ret;
 }
 
 #endif /* __KERNEL__ */
index 380d48b..26b8c80 100644 (file)
 //
 //----------------------------------------------------------------------------
 #include <linux/cache.h>
+#include <linux/threads.h>
 #include <asm/types.h>
 #include <asm/mmu.h>
 
+/*
+ * We only have to have statically allocated lppaca structs on
+ * legacy iSeries, which supports at most 64 cpus.
+ */
+#ifdef CONFIG_PPC_ISERIES
+#if NR_CPUS < 64
+#define NR_LPPACAS     NR_CPUS
+#else
+#define NR_LPPACAS     64
+#endif
+#else /* not iSeries */
+#define NR_LPPACAS     1
+#endif
+
+
 /* The Hypervisor barfs if the lppaca crosses a page boundary.  A 1k
  * alignment is sufficient to prevent this */
 struct lppaca {
index 991d599..fe56a23 100644 (file)
@@ -240,6 +240,12 @@ struct machdep_calls {
         * claims to support kexec.
         */
        int (*machine_kexec_prepare)(struct kimage *image);
+
+       /* Called to perform the _real_ kexec.
+        * Do NOT allocate memory or fail here. We are past the point of
+        * no return.
+        */
+       void (*machine_kexec)(struct kimage *image);
 #endif /* CONFIG_KEXEC */
 
 #ifdef CONFIG_SUSPEND
index 8eaed81..17194fc 100644 (file)
@@ -40,8 +40,8 @@
 
 /* MAS registers bit definitions */
 
-#define MAS0_TLBSEL(x)         ((x << 28) & 0x30000000)
-#define MAS0_ESEL(x)           ((x << 16) & 0x0FFF0000)
+#define MAS0_TLBSEL(x)         (((x) << 28) & 0x30000000)
+#define MAS0_ESEL(x)           (((x) << 16) & 0x0FFF0000)
 #define MAS0_NV(x)             ((x) & 0x00000FFF)
 #define MAS0_HES               0x00004000
 #define MAS0_WQ_ALLWAYS                0x00000000
 
 #define MAS1_VALID             0x80000000
 #define MAS1_IPROT             0x40000000
-#define MAS1_TID(x)            ((x << 16) & 0x3FFF0000)
+#define MAS1_TID(x)            (((x) << 16) & 0x3FFF0000)
 #define MAS1_IND               0x00002000
 #define MAS1_TS                        0x00001000
 #define MAS1_TSIZE_MASK                0x00000f80
 #define MAS1_TSIZE_SHIFT       7
-#define MAS1_TSIZE(x)          ((x << MAS1_TSIZE_SHIFT) & MAS1_TSIZE_MASK)
+#define MAS1_TSIZE(x)          (((x) << MAS1_TSIZE_SHIFT) & MAS1_TSIZE_MASK)
 
 #define MAS2_EPN               0xFFFFF000
 #define MAS2_X0                        0x00000040
index 53b64be..da4b200 100644 (file)
@@ -101,7 +101,7 @@ extern phys_addr_t kernstart_addr;
 
 #ifdef CONFIG_FLATMEM
 #define ARCH_PFN_OFFSET                (MEMORY_START >> PAGE_SHIFT)
-#define pfn_valid(pfn)         ((pfn) >= ARCH_PFN_OFFSET && (pfn) < (ARCH_PFN_OFFSET + max_mapnr))
+#define pfn_valid(pfn)         ((pfn) >= ARCH_PFN_OFFSET && (pfn) < max_mapnr)
 #endif
 
 #define virt_to_page(kaddr)    pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
index 51e9e6f..edeb80f 100644 (file)
@@ -171,6 +171,16 @@ static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus)
        return bus->sysdata;
 }
 
+static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
+{
+       struct pci_controller *host;
+
+       if (bus->self)
+               return pci_device_to_OF_node(bus->self);
+       host = pci_bus_to_host(bus);
+       return host ? host->dn : NULL;
+}
+
 static inline int isa_vaddr_is_ioport(void __iomem *address)
 {
        /* No specific ISA handling on ppc32 at this stage, it
index d727575..c189aa5 100644 (file)
@@ -70,21 +70,6 @@ static inline int of_node_to_nid(struct device_node *device) { return 0; }
 #endif
 #define of_node_to_nid of_node_to_nid
 
-/**
- * of_irq_map_pci - Resolve the interrupt for a PCI device
- * @pdev:      the device whose interrupt is to be resolved
- * @out_irq:   structure of_irq filled by this function
- *
- * This function resolves the PCI interrupt for a given PCI device. If a
- * device-node exists for a given pci_dev, it will use normal OF tree
- * walking. If not, it will implement standard swizzling and walk up the
- * PCI tree until an device-node is found, at which point it will finish
- * resolving using the OF tree walking.
- */
-struct pci_dev;
-struct of_irq;
-extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq);
-
 extern void of_instantiate_rtc(void);
 
 /* These includes are put at the bottom because they may contain things
index 8447d89..bb1e2cd 100644 (file)
  * by Paul Mackerras <paulus@samba.org>.
  */
 
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <asm/atomic.h>
-#include <asm/system.h>
-
 /*
  * the semaphore definition
  */
 #define RWSEM_ACTIVE_READ_BIAS         RWSEM_ACTIVE_BIAS
 #define RWSEM_ACTIVE_WRITE_BIAS                (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
 
-struct rw_semaphore {
-       long                    count;
-       spinlock_t              wait_lock;
-       struct list_head        wait_list;
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-       struct lockdep_map      dep_map;
-#endif
-};
-
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
-#else
-# define __RWSEM_DEP_MAP_INIT(lockname)
-#endif
-
-#define __RWSEM_INITIALIZER(name)                              \
-{                                                              \
-       RWSEM_UNLOCKED_VALUE,                                   \
-       __SPIN_LOCK_UNLOCKED((name).wait_lock),                 \
-       LIST_HEAD_INIT((name).wait_list)                        \
-       __RWSEM_DEP_MAP_INIT(name)                              \
-}
-
-#define DECLARE_RWSEM(name)            \
-       struct rw_semaphore name = __RWSEM_INITIALIZER(name)
-
-extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
-extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
-extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem);
-extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
-
-extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
-                        struct lock_class_key *key);
-
-#define init_rwsem(sem)                                        \
-       do {                                            \
-               static struct lock_class_key __key;     \
-                                                       \
-               __init_rwsem((sem), #sem, &__key);      \
-       } while (0)
-
 /*
  * lock for reading
  */
@@ -174,10 +128,5 @@ static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
        return atomic_long_add_return(delta, (atomic_long_t *)&sem->count);
 }
 
-static inline int rwsem_is_locked(struct rw_semaphore *sem)
-{
-       return sem->count != 0;
-}
-
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_RWSEM_H */
index 55cba4a..f8cd9fb 100644 (file)
@@ -18,7 +18,7 @@
 #include <asm/mmu.h>
 
 _GLOBAL(__setup_cpu_603)
-       mflr    r4
+       mflr    r5
 BEGIN_MMU_FTR_SECTION
        li      r10,0
        mtspr   SPRN_SPRG_603_LRU,r10           /* init SW LRU tracking */
@@ -27,60 +27,60 @@ BEGIN_FTR_SECTION
        bl      __init_fpu_registers
 END_FTR_SECTION_IFCLR(CPU_FTR_FPU_UNAVAILABLE)
        bl      setup_common_caches
-       mtlr    r4
+       mtlr    r5
        blr
 _GLOBAL(__setup_cpu_604)
-       mflr    r4
+       mflr    r5
        bl      setup_common_caches
        bl      setup_604_hid0
-       mtlr    r4
+       mtlr    r5
        blr
 _GLOBAL(__setup_cpu_750)
-       mflr    r4
+       mflr    r5
        bl      __init_fpu_registers
        bl      setup_common_caches
        bl      setup_750_7400_hid0
-       mtlr    r4
+       mtlr    r5
        blr
 _GLOBAL(__setup_cpu_750cx)
-       mflr    r4
+       mflr    r5
        bl      __init_fpu_registers
        bl      setup_common_caches
        bl      setup_750_7400_hid0
        bl      setup_750cx
-       mtlr    r4
+       mtlr    r5
        blr
 _GLOBAL(__setup_cpu_750fx)
-       mflr    r4
+       mflr    r5
        bl      __init_fpu_registers
        bl      setup_common_caches
        bl      setup_750_7400_hid0
        bl      setup_750fx
-       mtlr    r4
+       mtlr    r5
        blr
 _GLOBAL(__setup_cpu_7400)
-       mflr    r4
+       mflr    r5
        bl      __init_fpu_registers
        bl      setup_7400_workarounds
        bl      setup_common_caches
        bl      setup_750_7400_hid0
-       mtlr    r4
+       mtlr    r5
        blr
 _GLOBAL(__setup_cpu_7410)
-       mflr    r4
+       mflr    r5
        bl      __init_fpu_registers
        bl      setup_7410_workarounds
        bl      setup_common_caches
        bl      setup_750_7400_hid0
        li      r3,0
        mtspr   SPRN_L2CR2,r3
-       mtlr    r4
+       mtlr    r5
        blr
 _GLOBAL(__setup_cpu_745x)
-       mflr    r4
+       mflr    r5
        bl      setup_common_caches
        bl      setup_745x_specifics
-       mtlr    r4
+       mtlr    r5
        blr
 
 /* Enable caches for 603's, 604, 750 & 7400 */
@@ -194,10 +194,10 @@ setup_750cx:
        cror    4*cr0+eq,4*cr0+eq,4*cr1+eq
        cror    4*cr0+eq,4*cr0+eq,4*cr2+eq
        bnelr
-       lwz     r6,CPU_SPEC_FEATURES(r5)
+       lwz     r6,CPU_SPEC_FEATURES(r4)
        li      r7,CPU_FTR_CAN_NAP
        andc    r6,r6,r7
-       stw     r6,CPU_SPEC_FEATURES(r5)
+       stw     r6,CPU_SPEC_FEATURES(r4)
        blr
 
 /* 750fx specific
@@ -225,12 +225,12 @@ BEGIN_FTR_SECTION
        andis.  r11,r11,L3CR_L3E@h
        beq     1f
 END_FTR_SECTION_IFSET(CPU_FTR_L3CR)
-       lwz     r6,CPU_SPEC_FEATURES(r5)
+       lwz     r6,CPU_SPEC_FEATURES(r4)
        andi.   r0,r6,CPU_FTR_L3_DISABLE_NAP
        beq     1f
        li      r7,CPU_FTR_CAN_NAP
        andc    r6,r6,r7
-       stw     r6,CPU_SPEC_FEATURES(r5)
+       stw     r6,CPU_SPEC_FEATURES(r4)
 1:
        mfspr   r11,SPRN_HID0
 
index 8d74a24..e8e915c 100644 (file)
@@ -2076,8 +2076,8 @@ static void __init setup_cpu_spec(unsigned long offset, struct cpu_spec *s)
         * pointer on ppc64 and booke as we are running at 0 in real mode
         * on ppc64 and reloc_offset is always 0 on booke.
         */
-       if (s->cpu_setup) {
-               s->cpu_setup(offset, s);
+       if (t->cpu_setup) {
+               t->cpu_setup(offset, t);
        }
 #endif /* CONFIG_PPC64 || CONFIG_BOOKE */
 }
index 49a170a..a5f8672 100644 (file)
@@ -87,7 +87,10 @@ void machine_kexec(struct kimage *image)
 
        save_ftrace_enabled = __ftrace_enabled_save();
 
-       default_machine_kexec(image);
+       if (ppc_md.machine_kexec)
+               ppc_md.machine_kexec(image);
+       else
+               default_machine_kexec(image);
 
        __ftrace_enabled_restore(save_ftrace_enabled);
 
index ebf9846..f4adf89 100644 (file)
@@ -26,20 +26,6 @@ extern unsigned long __toc_start;
 
 #ifdef CONFIG_PPC_BOOK3S
 
-/*
- * We only have to have statically allocated lppaca structs on
- * legacy iSeries, which supports at most 64 cpus.
- */
-#ifdef CONFIG_PPC_ISERIES
-#if NR_CPUS < 64
-#define NR_LPPACAS     NR_CPUS
-#else
-#define NR_LPPACAS     64
-#endif
-#else /* not iSeries */
-#define NR_LPPACAS     1
-#endif
-
 /*
  * The structure which the hypervisor knows about - this structure
  * should not cross a page boundary.  The vpa_init/register_vpa call
index 10a44e6..eb341be 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/bootmem.h>
 #include <linux/of_address.h>
+#include <linux/of_pci.h>
 #include <linux/mm.h>
 #include <linux/list.h>
 #include <linux/syscalls.h>
index 7a1d5cb..8303a6c 100644 (file)
@@ -353,6 +353,7 @@ static void switch_booke_debug_regs(struct thread_struct *new_thread)
                        prime_debug_regs(new_thread);
 }
 #else  /* !CONFIG_PPC_ADV_DEBUG_REGS */
+#ifndef CONFIG_HAVE_HW_BREAKPOINT
 static void set_debug_reg_defaults(struct thread_struct *thread)
 {
        if (thread->dabr) {
@@ -360,6 +361,7 @@ static void set_debug_reg_defaults(struct thread_struct *thread)
                set_dabr(0);
        }
 }
+#endif /* !CONFIG_HAVE_HW_BREAKPOINT */
 #endif /* CONFIG_PPC_ADV_DEBUG_REGS */
 
 int set_dabr(unsigned long dabr)
@@ -670,11 +672,11 @@ void flush_thread(void)
 {
        discard_lazy_cpu_state();
 
-#ifdef CONFIG_HAVE_HW_BREAKPOINTS
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
        flush_ptrace_hw_breakpoint(current);
-#else /* CONFIG_HAVE_HW_BREAKPOINTS */
+#else /* CONFIG_HAVE_HW_BREAKPOINT */
        set_debug_reg_defaults(&current->thread);
-#endif /* CONFIG_HAVE_HW_BREAKPOINTS */
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */
 }
 
 void
index c2b7a07..47187cc 100644 (file)
@@ -2,95 +2,11 @@
 
 #include <linux/kernel.h>
 #include <linux/string.h>
-#include <linux/pci_regs.h>
 #include <linux/module.h>
 #include <linux/ioport.h>
 #include <linux/etherdevice.h>
 #include <linux/of_address.h>
 #include <asm/prom.h>
-#include <asm/pci-bridge.h>
-
-#ifdef CONFIG_PCI
-int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
-{
-       struct device_node *dn, *ppnode;
-       struct pci_dev *ppdev;
-       u32 lspec;
-       u32 laddr[3];
-       u8 pin;
-       int rc;
-
-       /* Check if we have a device node, if yes, fallback to standard OF
-        * parsing
-        */
-       dn = pci_device_to_OF_node(pdev);
-       if (dn) {
-               rc = of_irq_map_one(dn, 0, out_irq);
-               if (!rc)
-                       return rc;
-       }
-
-       /* Ok, we don't, time to have fun. Let's start by building up an
-        * interrupt spec.  we assume #interrupt-cells is 1, which is standard
-        * for PCI. If you do different, then don't use that routine.
-        */
-       rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin);
-       if (rc != 0)
-               return rc;
-       /* No pin, exit */
-       if (pin == 0)
-               return -ENODEV;
-
-       /* Now we walk up the PCI tree */
-       lspec = pin;
-       for (;;) {
-               /* Get the pci_dev of our parent */
-               ppdev = pdev->bus->self;
-
-               /* Ouch, it's a host bridge... */
-               if (ppdev == NULL) {
-#ifdef CONFIG_PPC64
-                       ppnode = pci_bus_to_OF_node(pdev->bus);
-#else
-                       struct pci_controller *host;
-                       host = pci_bus_to_host(pdev->bus);
-                       ppnode = host ? host->dn : NULL;
-#endif
-                       /* No node for host bridge ? give up */
-                       if (ppnode == NULL)
-                               return -EINVAL;
-               } else
-                       /* We found a P2P bridge, check if it has a node */
-                       ppnode = pci_device_to_OF_node(ppdev);
-
-               /* Ok, we have found a parent with a device-node, hand over to
-                * the OF parsing code.
-                * We build a unit address from the linux device to be used for
-                * resolution. Note that we use the linux bus number which may
-                * not match your firmware bus numbering.
-                * Fortunately, in most cases, interrupt-map-mask doesn't include
-                * the bus number as part of the matching.
-                * You should still be careful about that though if you intend
-                * to rely on this function (you ship  a firmware that doesn't
-                * create device nodes for all PCI devices).
-                */
-               if (ppnode)
-                       break;
-
-               /* We can only get here if we hit a P2P bridge with no node,
-                * let's do standard swizzling and try again
-                */
-               lspec = pci_swizzle_interrupt_pin(pdev, lspec);
-               pdev = ppdev;
-       }
-
-       laddr[0] = (pdev->bus->number << 16)
-               | (pdev->devfn << 8);
-       laddr[1]  = laddr[2] = 0;
-       return of_irq_map_raw(ppnode, &lspec, 1, laddr, out_irq);
-}
-EXPORT_SYMBOL_GPL(of_irq_map_pci);
-#endif /* CONFIG_PCI */
 
 void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
                unsigned long *busno, unsigned long *phys, unsigned long *size)
index bf5cb91..0dc95c0 100644 (file)
@@ -186,7 +186,7 @@ static void unmap_cpu_from_node(unsigned long cpu)
        dbg("removing cpu %lu from node %d\n", cpu, node);
 
        if (cpumask_test_cpu(cpu, node_to_cpumask_map[node])) {
-               cpumask_set_cpu(cpu, node_to_cpumask_map[node]);
+               cpumask_clear_cpu(cpu, node_to_cpumask_map[node]);
        } else {
                printk(KERN_ERR "WARNING: cpu %lu not found in node %d\n",
                       cpu, node);
@@ -1289,10 +1289,9 @@ u64 memory_hotplug_max(void)
 }
 #endif /* CONFIG_MEMORY_HOTPLUG */
 
-/* Vrtual Processor Home Node (VPHN) support */
+/* Virtual Processor Home Node (VPHN) support */
 #ifdef CONFIG_PPC_SPLPAR
-#define VPHN_NR_CHANGE_CTRS (8)
-static u8 vphn_cpu_change_counts[NR_CPUS][VPHN_NR_CHANGE_CTRS];
+static u8 vphn_cpu_change_counts[NR_CPUS][MAX_DISTANCE_REF_POINTS];
 static cpumask_t cpu_associativity_changes_mask;
 static int vphn_enabled;
 static void set_topology_timer(void);
@@ -1303,16 +1302,18 @@ static void set_topology_timer(void);
  */
 static void setup_cpu_associativity_change_counters(void)
 {
-       int cpu = 0;
+       int cpu;
+
+       /* The VPHN feature supports a maximum of 8 reference points */
+       BUILD_BUG_ON(MAX_DISTANCE_REF_POINTS > 8);
 
        for_each_possible_cpu(cpu) {
-               int i = 0;
+               int i;
                u8 *counts = vphn_cpu_change_counts[cpu];
                volatile u8 *hypervisor_counts = lppaca[cpu].vphn_assoc_counts;
 
-               for (i = 0; i < VPHN_NR_CHANGE_CTRS; i++) {
+               for (i = 0; i < distance_ref_points_depth; i++)
                        counts[i] = hypervisor_counts[i];
-               }
        }
 }
 
@@ -1329,7 +1330,7 @@ static void setup_cpu_associativity_change_counters(void)
  */
 static int update_cpu_associativity_changes_mask(void)
 {
-       int cpu = 0, nr_cpus = 0;
+       int cpu, nr_cpus = 0;
        cpumask_t *changes = &cpu_associativity_changes_mask;
 
        cpumask_clear(changes);
@@ -1339,8 +1340,8 @@ static int update_cpu_associativity_changes_mask(void)
                u8 *counts = vphn_cpu_change_counts[cpu];
                volatile u8 *hypervisor_counts = lppaca[cpu].vphn_assoc_counts;
 
-               for (i = 0; i < VPHN_NR_CHANGE_CTRS; i++) {
-                       if (hypervisor_counts[i] > counts[i]) {
+               for (i = 0; i < distance_ref_points_depth; i++) {
+                       if (hypervisor_counts[i] != counts[i]) {
                                counts[i] = hypervisor_counts[i];
                                changed = 1;
                        }
@@ -1354,8 +1355,11 @@ static int update_cpu_associativity_changes_mask(void)
        return nr_cpus;
 }
 
-/* 6 64-bit registers unpacked into 12 32-bit associativity values */
-#define VPHN_ASSOC_BUFSIZE (6*sizeof(u64)/sizeof(u32))
+/*
+ * 6 64-bit registers unpacked into 12 32-bit associativity values. To form
+ * the complete property we have to add the length in the first cell.
+ */
+#define VPHN_ASSOC_BUFSIZE (6*sizeof(u64)/sizeof(u32) + 1)
 
 /*
  * Convert the associativity domain numbers returned from the hypervisor
@@ -1363,15 +1367,14 @@ static int update_cpu_associativity_changes_mask(void)
  */
 static int vphn_unpack_associativity(const long *packed, unsigned int *unpacked)
 {
-       int i = 0;
-       int nr_assoc_doms = 0;
+       int i, nr_assoc_doms = 0;
        const u16 *field = (const u16*) packed;
 
 #define VPHN_FIELD_UNUSED      (0xffff)
 #define VPHN_FIELD_MSB         (0x8000)
 #define VPHN_FIELD_MASK                (~VPHN_FIELD_MSB)
 
-       for (i = 0; i < VPHN_ASSOC_BUFSIZE; i++) {
+       for (i = 1; i < VPHN_ASSOC_BUFSIZE; i++) {
                if (*field == VPHN_FIELD_UNUSED) {
                        /* All significant fields processed, and remaining
                         * fields contain the reserved value of all 1's.
@@ -1379,14 +1382,12 @@ static int vphn_unpack_associativity(const long *packed, unsigned int *unpacked)
                         */
                        unpacked[i] = *((u32*)field);
                        field += 2;
-               }
-               else if (*field & VPHN_FIELD_MSB) {
+               } else if (*field & VPHN_FIELD_MSB) {
                        /* Data is in the lower 15 bits of this field */
                        unpacked[i] = *field & VPHN_FIELD_MASK;
                        field++;
                        nr_assoc_doms++;
-               }
-               else {
+               } else {
                        /* Data is in the lower 15 bits of this field
                         * concatenated with the next 16 bit field
                         */
@@ -1396,6 +1397,9 @@ static int vphn_unpack_associativity(const long *packed, unsigned int *unpacked)
                }
        }
 
+       /* The first cell contains the length of the property */
+       unpacked[0] = nr_assoc_doms;
+
        return nr_assoc_doms;
 }
 
@@ -1405,7 +1409,7 @@ static int vphn_unpack_associativity(const long *packed, unsigned int *unpacked)
  */
 static long hcall_vphn(unsigned long cpu, unsigned int *associativity)
 {
-       long rc = 0;
+       long rc;
        long retbuf[PLPAR_HCALL9_BUFSIZE] = {0};
        u64 flags = 1;
        int hwcpu = get_hard_smp_processor_id(cpu);
@@ -1419,7 +1423,7 @@ static long hcall_vphn(unsigned long cpu, unsigned int *associativity)
 static long vphn_get_associativity(unsigned long cpu,
                                        unsigned int *associativity)
 {
-       long rc = 0;
+       long rc;
 
        rc = hcall_vphn(cpu, associativity);
 
@@ -1445,9 +1449,9 @@ static long vphn_get_associativity(unsigned long cpu,
  */
 int arch_update_cpu_topology(void)
 {
-       int cpu = 0, nid = 0, old_nid = 0;
+       int cpu, nid, old_nid;
        unsigned int associativity[VPHN_ASSOC_BUFSIZE] = {0};
-       struct sys_device *sysdev = NULL;
+       struct sys_device *sysdev;
 
        for_each_cpu_mask(cpu, cpu_associativity_changes_mask) {
                vphn_get_associativity(cpu, associativity);
@@ -1512,7 +1516,9 @@ int start_topology_update(void)
 {
        int rc = 0;
 
-       if (firmware_has_feature(FW_FEATURE_VPHN)) {
+       /* Disabled until races with load balancing are fixed */
+       if (0 && firmware_has_feature(FW_FEATURE_VPHN) &&
+           get_lppaca()->shared_proc) {
                vphn_enabled = 1;
                setup_cpu_associativity_change_counters();
                init_timer_deferrable(&topology_timer);
index 1ec0657..c14d09f 100644 (file)
@@ -38,13 +38,11 @@ DEFINE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch);
  * neesd to be flushed. This function will either perform the flush
  * immediately or will batch it up if the current CPU has an active
  * batch on it.
- *
- * Must be called from within some kind of spinlock/non-preempt region...
  */
 void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
                     pte_t *ptep, unsigned long pte, int huge)
 {
-       struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
+       struct ppc64_tlb_batch *batch = &get_cpu_var(ppc64_tlb_batch);
        unsigned long vsid, vaddr;
        unsigned int psize;
        int ssize;
@@ -99,6 +97,7 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
         */
        if (!batch->active) {
                flush_hash_page(vaddr, rpte, psize, ssize, 0);
+               put_cpu_var(ppc64_tlb_batch);
                return;
        }
 
@@ -127,6 +126,7 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
        batch->index = ++i;
        if (i >= PPC64_TLB_BATCH_NR)
                __flush_tlb_pending(batch);
+       put_cpu_var(ppc64_tlb_batch);
 }
 
 /*
index 187a7d3..a3d2ce5 100644 (file)
@@ -70,7 +70,7 @@ static long do_spu_create(const char __user *pathname, unsigned int flags,
        if (!IS_ERR(tmp)) {
                struct nameidata nd;
 
-               ret = path_lookup(tmp, LOOKUP_PARENT, &nd);
+               ret = kern_path_parent(tmp, &nd);
                if (!ret) {
                        nd.flags |= LOOKUP_OPEN | LOOKUP_CREATE;
                        ret = spufs_create(&nd, flags, mode, neighbor);
index fdb7384..f0491cc 100644 (file)
@@ -242,8 +242,8 @@ static void __init dt_cpus(struct iseries_flat_dt *dt)
        pft_size[0] = 0; /* NUMA CEC cookie, 0 for non NUMA  */
        pft_size[1] = __ilog2(HvCallHpt_getHptPages() * HW_PAGE_SIZE);
 
-       for (i = 0; i < NR_CPUS; i++) {
-               if (lppaca_of(i).dyn_proc_status >= 2)
+       for (i = 0; i < NR_LPPACAS; i++) {
+               if (lppaca[i].dyn_proc_status >= 2)
                        continue;
 
                snprintf(p, 32 - (p - buf), "@%d", i);
@@ -251,7 +251,7 @@ static void __init dt_cpus(struct iseries_flat_dt *dt)
 
                dt_prop_str(dt, "device_type", device_type_cpu);
 
-               index = lppaca_of(i).dyn_hv_phys_proc_index;
+               index = lppaca[i].dyn_hv_phys_proc_index;
                d = &xIoHriProcessorVpd[index];
 
                dt_prop_u32(dt, "i-cache-size", d->xInstCacheSize * 1024);
index b086341..2946ae1 100644 (file)
@@ -680,6 +680,7 @@ void * __init iSeries_early_setup(void)
         * on but calling this function multiple times is fine.
         */
        identify_cpu(0, mfspr(SPRN_PVR));
+       initialise_paca(&boot_paca, 0);
 
        powerpc_firmware_features |= FW_FEATURE_ISERIES;
        powerpc_firmware_features |= FW_FEATURE_LPAR;
index 5d3ea9f..ca5d589 100644 (file)
@@ -713,6 +713,13 @@ EXPORT_SYMBOL(arch_free_page);
 /* NB: reg/unreg are called while guarded with the tracepoints_mutex */
 extern long hcall_tracepoint_refcount;
 
+/* 
+ * Since the tracing code might execute hcalls we need to guard against
+ * recursion. One example of this are spinlocks calling H_YIELD on
+ * shared processor partitions.
+ */
+static DEFINE_PER_CPU(unsigned int, hcall_trace_depth);
+
 void hcall_tracepoint_regfunc(void)
 {
        hcall_tracepoint_refcount++;
@@ -725,12 +732,42 @@ void hcall_tracepoint_unregfunc(void)
 
 void __trace_hcall_entry(unsigned long opcode, unsigned long *args)
 {
+       unsigned long flags;
+       unsigned int *depth;
+
+       local_irq_save(flags);
+
+       depth = &__get_cpu_var(hcall_trace_depth);
+
+       if (*depth)
+               goto out;
+
+       (*depth)++;
        trace_hcall_entry(opcode, args);
+       (*depth)--;
+
+out:
+       local_irq_restore(flags);
 }
 
 void __trace_hcall_exit(long opcode, unsigned long retval,
                        unsigned long *retbuf)
 {
+       unsigned long flags;
+       unsigned int *depth;
+
+       local_irq_save(flags);
+
+       depth = &__get_cpu_var(hcall_trace_depth);
+
+       if (*depth)
+               goto out;
+
+       (*depth)++;
        trace_hcall_exit(opcode, retval, retbuf);
+       (*depth)--;
+
+out:
+       local_irq_restore(flags);
 }
 #endif
index ff19efd..636bcb8 100644 (file)
@@ -406,7 +406,7 @@ config QDIO
          If unsure, say Y.
 
 config CHSC_SCH
-       def_tristate y
+       def_tristate m
        prompt "Support for CHSC subchannels"
        help
          This driver allows usage of CHSC subchannels. A CHSC subchannel
index 0851eb1..2751b3a 100644 (file)
@@ -133,11 +133,12 @@ unsigned long decompress_kernel(void)
        unsigned long output_addr;
        unsigned char *output;
 
-       check_ipl_parmblock((void *) 0, (unsigned long) output + SZ__bss_start);
+       output_addr = ((unsigned long) &_end + HEAP_SIZE + 4095UL) & -4096UL;
+       check_ipl_parmblock((void *) 0, output_addr + SZ__bss_start);
        memset(&_bss, 0, &_ebss - &_bss);
        free_mem_ptr = (unsigned long)&_end;
        free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
-       output = (unsigned char *) ((free_mem_end_ptr + 4095UL) & -4096UL);
+       output = (unsigned char *) output_addr;
 
 #ifdef CONFIG_BLK_DEV_INITRD
        /*
index f42dbab..48884f8 100644 (file)
@@ -38,6 +38,7 @@ int s390_sha_update(struct shash_desc *desc, const u8 *data, unsigned int len)
                BUG_ON(ret != bsize);
                data += bsize - index;
                len -= bsize - index;
+               index = 0;
        }
 
        /* process as many blocks as possible */
index 76daea1..5c5ba10 100644 (file)
 
 static inline int atomic_read(const atomic_t *v)
 {
-       barrier();
-       return v->counter;
+       int c;
+
+       asm volatile(
+               "       l       %0,%1\n"
+               : "=d" (c) : "Q" (v->counter));
+       return c;
 }
 
 static inline void atomic_set(atomic_t *v, int i)
 {
-       v->counter = i;
-       barrier();
+       asm volatile(
+               "       st      %1,%0\n"
+               : "=Q" (v->counter) : "d" (i));
 }
 
 static inline int atomic_add_return(int i, atomic_t *v)
@@ -128,14 +133,19 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
 
 static inline long long atomic64_read(const atomic64_t *v)
 {
-       barrier();
-       return v->counter;
+       long long c;
+
+       asm volatile(
+               "       lg      %0,%1\n"
+               : "=d" (c) : "Q" (v->counter));
+       return c;
 }
 
 static inline void atomic64_set(atomic64_t *v, long long i)
 {
-       v->counter = i;
-       barrier();
+       asm volatile(
+               "       stg     %1,%0\n"
+               : "=Q" (v->counter) : "d" (i));
 }
 
 static inline long long atomic64_add_return(long long i, atomic64_t *v)
index 24aafa6..2a30d5a 100644 (file)
@@ -13,6 +13,7 @@
 
 #define L1_CACHE_BYTES     256
 #define L1_CACHE_SHIFT     8
+#define NET_SKB_PAD       32
 
 #define __read_mostly __attribute__((__section__(".data..read_mostly")))
 
index 405cc97..7e1f776 100644 (file)
@@ -1,29 +1,8 @@
 #ifndef _S390_CACHEFLUSH_H
 #define _S390_CACHEFLUSH_H
 
-/* Keep includes the same across arches.  */
-#include <linux/mm.h>
-
 /* Caches aren't brain-dead on the s390. */
-#define flush_cache_all()                      do { } while (0)
-#define flush_cache_mm(mm)                     do { } while (0)
-#define flush_cache_dup_mm(mm)                 do { } while (0)
-#define flush_cache_range(vma, start, end)     do { } while (0)
-#define flush_cache_page(vma, vmaddr, pfn)     do { } while (0)
-#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
-#define flush_dcache_page(page)                        do { } while (0)
-#define flush_dcache_mmap_lock(mapping)                do { } while (0)
-#define flush_dcache_mmap_unlock(mapping)      do { } while (0)
-#define flush_icache_range(start, end)         do { } while (0)
-#define flush_icache_page(vma,pg)              do { } while (0)
-#define flush_icache_user_range(vma,pg,adr,len)        do { } while (0)
-#define flush_cache_vmap(start, end)           do { } while (0)
-#define flush_cache_vunmap(start, end)         do { } while (0)
-
-#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
-       memcpy(dst, src, len)
-#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
-       memcpy(dst, src, len)
+#include <asm-generic/cacheflush.h>
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
 void kernel_map_pages(struct page *page, int numpages, int enable);
index 5c5d02d..81cf36b 100644 (file)
@@ -7,7 +7,7 @@
 #include <linux/uaccess.h>
 #include <asm/errno.h>
 
-static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
 {
        int op = (encoded_op >> 28) & 7;
        int cmp = (encoded_op >> 24) & 15;
@@ -18,7 +18,7 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
        if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
                oparg = 1 << oparg;
 
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
        pagefault_disable();
@@ -39,13 +39,13 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
        return ret;
 }
 
-static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr,
-                                               int oldval, int newval)
+static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+                                               u32 oldval, u32 newval)
 {
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
-       return uaccess.futex_atomic_cmpxchg(uaddr, oldval, newval);
+       return uaccess.futex_atomic_cmpxchg(uval, uaddr, oldval, newval);
 }
 
 #endif /* __KERNEL__ */
index bf3de04..2c79b64 100644 (file)
@@ -148,11 +148,6 @@ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
  */
 extern unsigned long thread_saved_pc(struct task_struct *t);
 
-/*
- * Print register of task into buffer. Used in fs/proc/array.c.
- */
-extern void task_show_regs(struct seq_file *m, struct task_struct *task);
-
 extern void show_code(struct pt_regs *regs);
 
 unsigned long get_wchan(struct task_struct *p);
index 423fdda..d0eb465 100644 (file)
 
 #ifdef __KERNEL__
 
-#include <linux/list.h>
-#include <linux/spinlock.h>
-
-struct rwsem_waiter;
-
-extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *);
-extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *);
-extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *);
-extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *);
-extern struct rw_semaphore *rwsem_downgrade_write(struct rw_semaphore *);
-
-/*
- * the semaphore definition
- */
-struct rw_semaphore {
-       signed long             count;
-       spinlock_t              wait_lock;
-       struct list_head        wait_list;
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-       struct lockdep_map      dep_map;
-#endif
-};
-
 #ifndef __s390x__
 #define RWSEM_UNLOCKED_VALUE   0x00000000
 #define RWSEM_ACTIVE_BIAS      0x00000001
@@ -80,41 +57,6 @@ struct rw_semaphore {
 #define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
 #define RWSEM_ACTIVE_WRITE_BIAS        (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
 
-/*
- * initialisation
- */
-
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
-#else
-# define __RWSEM_DEP_MAP_INIT(lockname)
-#endif
-
-#define __RWSEM_INITIALIZER(name) \
- { RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait.lock), \
-   LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) }
-
-#define DECLARE_RWSEM(name) \
-       struct rw_semaphore name = __RWSEM_INITIALIZER(name)
-
-static inline void init_rwsem(struct rw_semaphore *sem)
-{
-       sem->count = RWSEM_UNLOCKED_VALUE;
-       spin_lock_init(&sem->wait_lock);
-       INIT_LIST_HEAD(&sem->wait_list);
-}
-
-extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
-                        struct lock_class_key *key);
-
-#define init_rwsem(sem)                                \
-do {                                           \
-       static struct lock_class_key __key;     \
-                                               \
-       __init_rwsem((sem), #sem, &__key);      \
-} while (0)
-
-
 /*
  * lock for reading
  */
@@ -377,10 +319,5 @@ static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
        return new;
 }
 
-static inline int rwsem_is_locked(struct rw_semaphore *sem)
-{
-       return (sem->count != 0);
-}
-
 #endif /* __KERNEL__ */
 #endif /* _S390_RWSEM_H */
index f1f644f..9074a54 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include <linux/mm.h>
+#include <linux/pagemap.h>
 #include <linux/swap.h>
 #include <asm/processor.h>
 #include <asm/pgalloc.h>
index d6b1ed0..2d9ea11 100644 (file)
@@ -83,8 +83,8 @@ struct uaccess_ops {
        size_t (*clear_user)(size_t, void __user *);
        size_t (*strnlen_user)(size_t, const char __user *);
        size_t (*strncpy_from_user)(size_t, const char __user *, char *);
-       int (*futex_atomic_op)(int op, int __user *, int oparg, int *old);
-       int (*futex_atomic_cmpxchg)(int __user *, int old, int new);
+       int (*futex_atomic_op)(int op, u32 __user *, int oparg, int *old);
+       int (*futex_atomic_cmpxchg)(u32 *, u32 __user *, u32 old, u32 new);
 };
 
 extern struct uaccess_ops uaccess;
index 5eb78dd..b5a4a73 100644 (file)
@@ -237,43 +237,6 @@ void show_regs(struct pt_regs *regs)
        show_last_breaking_event(regs);
 }
 
-/* This is called from fs/proc/array.c */
-void task_show_regs(struct seq_file *m, struct task_struct *task)
-{
-       struct pt_regs *regs;
-
-       regs = task_pt_regs(task);
-       seq_printf(m, "task: %p, ksp: %p\n",
-                      task, (void *)task->thread.ksp);
-       seq_printf(m, "User PSW : %p %p\n",
-                      (void *) regs->psw.mask, (void *)regs->psw.addr);
-
-       seq_printf(m, "User GPRS: " FOURLONG,
-                         regs->gprs[0], regs->gprs[1],
-                         regs->gprs[2], regs->gprs[3]);
-       seq_printf(m, "           " FOURLONG,
-                         regs->gprs[4], regs->gprs[5],
-                         regs->gprs[6], regs->gprs[7]);
-       seq_printf(m, "           " FOURLONG,
-                         regs->gprs[8], regs->gprs[9],
-                         regs->gprs[10], regs->gprs[11]);
-       seq_printf(m, "           " FOURLONG,
-                         regs->gprs[12], regs->gprs[13],
-                         regs->gprs[14], regs->gprs[15]);
-       seq_printf(m, "User ACRS: %08x %08x %08x %08x\n",
-                         task->thread.acrs[0], task->thread.acrs[1],
-                         task->thread.acrs[2], task->thread.acrs[3]);
-       seq_printf(m, "           %08x %08x %08x %08x\n",
-                         task->thread.acrs[4], task->thread.acrs[5],
-                         task->thread.acrs[6], task->thread.acrs[7]);
-       seq_printf(m, "           %08x %08x %08x %08x\n",
-                         task->thread.acrs[8], task->thread.acrs[9],
-                         task->thread.acrs[10], task->thread.acrs[11]);
-       seq_printf(m, "           %08x %08x %08x %08x\n",
-                         task->thread.acrs[12], task->thread.acrs[13],
-                         task->thread.acrs[14], task->thread.acrs[15]);
-}
-
 static DEFINE_SPINLOCK(die_lock);
 
 void die(const char * str, struct pt_regs * regs, long err)
index 126011d..1d2536c 100644 (file)
@@ -12,12 +12,12 @@ extern size_t copy_from_user_std(size_t, const void __user *, void *);
 extern size_t copy_to_user_std(size_t, void __user *, const void *);
 extern size_t strnlen_user_std(size_t, const char __user *);
 extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
-extern int futex_atomic_cmpxchg_std(int __user *, int, int);
-extern int futex_atomic_op_std(int, int __user *, int, int *);
+extern int futex_atomic_cmpxchg_std(u32 *, u32 __user *, u32, u32);
+extern int futex_atomic_op_std(int, u32 __user *, int, int *);
 
 extern size_t copy_from_user_pt(size_t, const void __user *, void *);
 extern size_t copy_to_user_pt(size_t, void __user *, const void *);
-extern int futex_atomic_op_pt(int, int __user *, int, int *);
-extern int futex_atomic_cmpxchg_pt(int __user *, int, int);
+extern int futex_atomic_op_pt(int, u32 __user *, int, int *);
+extern int futex_atomic_cmpxchg_pt(u32 *, u32 __user *, u32, u32);
 
 #endif /* __ARCH_S390_LIB_UACCESS_H */
index 404f2de..7483383 100644 (file)
@@ -302,7 +302,7 @@ fault:
                     : "0" (-EFAULT), "d" (oparg), "a" (uaddr),         \
                       "m" (*uaddr) : "cc" );
 
-static int __futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
+static int __futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old)
 {
        int oldval = 0, newval, ret;
 
@@ -335,7 +335,7 @@ static int __futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
        return ret;
 }
 
-int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
+int futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old)
 {
        int ret;
 
@@ -354,26 +354,29 @@ int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
        return ret;
 }
 
-static int __futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
+static int __futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
+                                    u32 oldval, u32 newval)
 {
        int ret;
 
        asm volatile("0: cs   %1,%4,0(%5)\n"
-                    "1: lr   %0,%1\n"
+                    "1: la   %0,0\n"
                     "2:\n"
                     EX_TABLE(0b,2b) EX_TABLE(1b,2b)
                     : "=d" (ret), "+d" (oldval), "=m" (*uaddr)
                     : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
                     : "cc", "memory" );
+       *uval = oldval;
        return ret;
 }
 
-int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
+int futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
+                           u32 oldval, u32 newval)
 {
        int ret;
 
        if (segment_eq(get_fs(), KERNEL_DS))
-               return __futex_atomic_cmpxchg_pt(uaddr, oldval, newval);
+               return __futex_atomic_cmpxchg_pt(uval, uaddr, oldval, newval);
        spin_lock(&current->mm->page_table_lock);
        uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
        if (!uaddr) {
@@ -382,7 +385,7 @@ int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
        }
        get_page(virt_to_page(uaddr));
        spin_unlock(&current->mm->page_table_lock);
-       ret = __futex_atomic_cmpxchg_pt(uaddr, oldval, newval);
+       ret = __futex_atomic_cmpxchg_pt(uval, uaddr, oldval, newval);
        put_page(virt_to_page(uaddr));
        return ret;
 }
index 07deaee..bb1a7ee 100644 (file)
@@ -125,9 +125,9 @@ static size_t copy_in_user_std(size_t size, void __user *to,
        unsigned long tmp1;
 
        asm volatile(
+               "   sacf  256\n"
                "  "AHI"  %0,-1\n"
                "   jo    5f\n"
-               "   sacf  256\n"
                "   bras  %3,3f\n"
                "0:"AHI"  %0,257\n"
                "1: mvc   0(1,%1),0(%2)\n"
@@ -142,9 +142,8 @@ static size_t copy_in_user_std(size_t size, void __user *to,
                "3:"AHI"  %0,-256\n"
                "   jnm   2b\n"
                "4: ex    %0,1b-0b(%3)\n"
-               "   sacf  0\n"
                "5: "SLR"  %0,%0\n"
-               "6:\n"
+               "6: sacf  0\n"
                EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b)
                : "+a" (size), "+a" (to), "+a" (from), "=a" (tmp1)
                : : "cc", "memory");
@@ -156,9 +155,9 @@ static size_t clear_user_std(size_t size, void __user *to)
        unsigned long tmp1, tmp2;
 
        asm volatile(
+               "   sacf  256\n"
                "  "AHI"  %0,-1\n"
                "   jo    5f\n"
-               "   sacf  256\n"
                "   bras  %3,3f\n"
                "   xc    0(1,%1),0(%1)\n"
                "0:"AHI"  %0,257\n"
@@ -178,9 +177,8 @@ static size_t clear_user_std(size_t size, void __user *to)
                "3:"AHI"  %0,-256\n"
                "   jnm   2b\n"
                "4: ex    %0,0(%3)\n"
-               "   sacf  0\n"
                "5: "SLR"  %0,%0\n"
-               "6:\n"
+               "6: sacf  0\n"
                EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b)
                : "+a" (size), "+a" (to), "=a" (tmp1), "=a" (tmp2)
                : : "cc", "memory");
@@ -257,7 +255,7 @@ size_t strncpy_from_user_std(size_t size, const char __user *src, char *dst)
                : "0" (-EFAULT), "d" (oparg), "a" (uaddr),              \
                  "m" (*uaddr) : "cc");
 
-int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old)
+int futex_atomic_op_std(int op, u32 __user *uaddr, int oparg, int *old)
 {
        int oldval = 0, newval, ret;
 
@@ -289,19 +287,21 @@ int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old)
        return ret;
 }
 
-int futex_atomic_cmpxchg_std(int __user *uaddr, int oldval, int newval)
+int futex_atomic_cmpxchg_std(u32 *uval, u32 __user *uaddr,
+                            u32 oldval, u32 newval)
 {
        int ret;
 
        asm volatile(
                "   sacf 256\n"
                "0: cs   %1,%4,0(%5)\n"
-               "1: lr   %0,%1\n"
+               "1: la   %0,0\n"
                "2: sacf 0\n"
                EX_TABLE(0b,2b) EX_TABLE(1b,2b)
                : "=d" (ret), "+d" (oldval), "=m" (*uaddr)
                : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
                : "cc", "memory" );
+       *uval = oldval;
        return ret;
 }
 
index 0c719c6..e1850c2 100644 (file)
@@ -336,7 +336,8 @@ void page_table_free(struct mm_struct *mm, unsigned long *table)
        page->flags ^= bits;
        if (page->flags & FRAG_MASK) {
                /* Page now has some free pgtable fragments. */
-               list_move(&page->lru, &mm->context.pgtable_list);
+               if (!list_empty(&page->lru))
+                       list_move(&page->lru, &mm->context.pgtable_list);
                page = NULL;
        } else
                /* All fragments of the 4K page have been freed. */
index ae55556..8a9011d 100644 (file)
@@ -15,6 +15,7 @@ config SUPERH
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_BZIP2
        select HAVE_KERNEL_LZMA
+       select HAVE_KERNEL_XZ
        select HAVE_KERNEL_LZO
        select HAVE_SYSCALL_TRACEPOINTS
        select HAVE_REGS_AND_STACK_ACCESS_API
index 9c8c6e1..e3d8170 100644 (file)
@@ -200,7 +200,7 @@ endif
 libs-$(CONFIG_SUPERH32)                := arch/sh/lib/ $(libs-y)
 libs-$(CONFIG_SUPERH64)                := arch/sh/lib64/ $(libs-y)
 
-BOOT_TARGETS = uImage uImage.bz2 uImage.gz uImage.lzma uImage.lzo \
+BOOT_TARGETS = uImage uImage.bz2 uImage.gz uImage.lzma uImage.xz uImage.lzo \
               uImage.srec uImage.bin zImage vmlinux.bin vmlinux.srec \
               romImage
 PHONY += $(BOOT_TARGETS)
@@ -230,5 +230,6 @@ define archhelp
        @echo '* uImage.gz                 - Kernel-only image for U-Boot (gzip)'
        @echo '  uImage.bz2                - Kernel-only image for U-Boot (bzip2)'
        @echo '  uImage.lzma               - Kernel-only image for U-Boot (lzma)'
+       @echo '  uImage.xz                 - Kernel-only image for U-Boot (xz)'
        @echo '  uImage.lzo                - Kernel-only image for U-Boot (lzo)'
 endef
index 33b6629..701667a 100644 (file)
@@ -1294,6 +1294,7 @@ static int __init arch_setup(void)
        i2c_register_board_info(1, i2c1_devices,
                                ARRAY_SIZE(i2c1_devices));
 
+#if defined(CONFIG_VIDEO_SH_VOU) || defined(CONFIG_VIDEO_SH_VOU_MODULE)
        /* VOU */
        gpio_request(GPIO_FN_DV_D15, NULL);
        gpio_request(GPIO_FN_DV_D14, NULL);
@@ -1325,6 +1326,7 @@ static int __init arch_setup(void)
 
        /* Remove reset */
        gpio_set_value(GPIO_PTG4, 1);
+#endif
 
        return platform_add_devices(ecovec_devices,
                                    ARRAY_SIZE(ecovec_devices));
index 1ce6362..ba515d8 100644 (file)
@@ -24,12 +24,13 @@ suffix-y := bin
 suffix-$(CONFIG_KERNEL_GZIP)   := gz
 suffix-$(CONFIG_KERNEL_BZIP2)  := bz2
 suffix-$(CONFIG_KERNEL_LZMA)   := lzma
+suffix-$(CONFIG_KERNEL_XZ)     := xz
 suffix-$(CONFIG_KERNEL_LZO)    := lzo
 
 targets := zImage vmlinux.srec romImage uImage uImage.srec uImage.gz \
-          uImage.bz2 uImage.lzma uImage.lzo uImage.bin
+          uImage.bz2 uImage.lzma uImage.xz uImage.lzo uImage.bin
 extra-y += vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \
-          vmlinux.bin.lzo
+          vmlinux.bin.xz vmlinux.bin.lzo
 subdir- := compressed romimage
 
 $(obj)/zImage: $(obj)/compressed/vmlinux FORCE
@@ -76,6 +77,9 @@ $(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
 $(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
        $(call if_changed,lzma)
 
+$(obj)/vmlinux.bin.xz: $(obj)/vmlinux.bin FORCE
+       $(call if_changed,xzkern)
+
 $(obj)/vmlinux.bin.lzo: $(obj)/vmlinux.bin FORCE
        $(call if_changed,lzo)
 
@@ -88,6 +92,9 @@ $(obj)/uImage.gz: $(obj)/vmlinux.bin.gz
 $(obj)/uImage.lzma: $(obj)/vmlinux.bin.lzma
        $(call if_changed,uimage,lzma)
 
+$(obj)/uImage.xz: $(obj)/vmlinux.bin.xz
+       $(call if_changed,uimage,xz)
+
 $(obj)/uImage.lzo: $(obj)/vmlinux.bin.lzo
        $(call if_changed,uimage,lzo)
 
index cfa5a08..e0b0293 100644 (file)
@@ -6,7 +6,7 @@
 
 targets                := vmlinux vmlinux.bin vmlinux.bin.gz \
                   vmlinux.bin.bz2 vmlinux.bin.lzma \
-                  vmlinux.bin.lzo \
+                  vmlinux.bin.xz vmlinux.bin.lzo \
                   head_$(BITS).o misc.o piggy.o
 
 OBJECTS = $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/cache.o
@@ -50,6 +50,8 @@ $(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y) FORCE
        $(call if_changed,bzip2)
 $(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y) FORCE
        $(call if_changed,lzma)
+$(obj)/vmlinux.bin.xz: $(vmlinux.bin.all-y) FORCE
+       $(call if_changed,xzkern)
 $(obj)/vmlinux.bin.lzo: $(vmlinux.bin.all-y) FORCE
        $(call if_changed,lzo)
 
index 27140a6..95470a4 100644 (file)
@@ -61,6 +61,10 @@ static unsigned long free_mem_end_ptr;
 #include "../../../../lib/decompress_unlzma.c"
 #endif
 
+#ifdef CONFIG_KERNEL_XZ
+#include "../../../../lib/decompress_unxz.c"
+#endif
+
 #ifdef CONFIG_KERNEL_LZO
 #include "../../../../lib/decompress_unlzo.c"
 #endif
index a9f16a7..6cb9f19 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <asm/system.h>
 
-static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr,
+static inline int atomic_futex_op_xchg_set(int oparg, u32 __user *uaddr,
                                           int *oldval)
 {
        unsigned long flags;
@@ -20,7 +20,7 @@ static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr,
        return ret;
 }
 
-static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr,
+static inline int atomic_futex_op_xchg_add(int oparg, u32 __user *uaddr,
                                           int *oldval)
 {
        unsigned long flags;
@@ -37,7 +37,7 @@ static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr,
        return ret;
 }
 
-static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr,
+static inline int atomic_futex_op_xchg_or(int oparg, u32 __user *uaddr,
                                          int *oldval)
 {
        unsigned long flags;
@@ -54,7 +54,7 @@ static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr,
        return ret;
 }
 
-static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr,
+static inline int atomic_futex_op_xchg_and(int oparg, u32 __user *uaddr,
                                           int *oldval)
 {
        unsigned long flags;
@@ -71,7 +71,7 @@ static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr,
        return ret;
 }
 
-static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr,
+static inline int atomic_futex_op_xchg_xor(int oparg, u32 __user *uaddr,
                                           int *oldval)
 {
        unsigned long flags;
@@ -88,11 +88,13 @@ static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr,
        return ret;
 }
 
-static inline int atomic_futex_op_cmpxchg_inatomic(int __user *uaddr,
-                                                  int oldval, int newval)
+static inline int atomic_futex_op_cmpxchg_inatomic(u32 *uval,
+                                                  u32 __user *uaddr,
+                                                  u32 oldval, u32 newval)
 {
        unsigned long flags;
-       int ret, prev = 0;
+       int ret;
+       u32 prev = 0;
 
        local_irq_save(flags);
 
@@ -102,10 +104,8 @@ static inline int atomic_futex_op_cmpxchg_inatomic(int __user *uaddr,
 
        local_irq_restore(flags);
 
-       if (ret)
-               return ret;
-
-       return prev;
+       *uval = prev;
+       return ret;
 }
 
 #endif /* __ASM_SH_FUTEX_IRQ_H */
index 68256ec..7be39a6 100644 (file)
@@ -10,7 +10,7 @@
 /* XXX: UP variants, fix for SH-4A and SMP.. */
 #include <asm/futex-irq.h>
 
-static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
 {
        int op = (encoded_op >> 28) & 7;
        int cmp = (encoded_op >> 24) & 15;
@@ -21,7 +21,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
        if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
                oparg = 1 << oparg;
 
-       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
        pagefault_disable();
@@ -65,12 +65,13 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
 }
 
 static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+                             u32 oldval, u32 newval)
 {
-       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
-       return atomic_futex_op_cmpxchg_inatomic(uaddr, oldval, newval);
+       return atomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval);
 }
 
 #endif /* __KERNEL__ */
index 083ea06..db85916 100644 (file)
@@ -134,6 +134,7 @@ typedef pte_t *pte_addr_t;
 extern void pgtable_cache_init(void);
 
 struct vm_area_struct;
+struct mm_struct;
 
 extern void __update_cache(struct vm_area_struct *vma,
                           unsigned long address, pte_t pte);
index 06e2251..edab572 100644 (file)
 #endif
 
 #ifdef __KERNEL__
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <asm/atomic.h>
-#include <asm/system.h>
 
-/*
- * the semaphore definition
- */
-struct rw_semaphore {
-       long            count;
 #define RWSEM_UNLOCKED_VALUE           0x00000000
 #define RWSEM_ACTIVE_BIAS              0x00000001
 #define RWSEM_ACTIVE_MASK              0x0000ffff
 #define RWSEM_WAITING_BIAS             (-0x00010000)
 #define RWSEM_ACTIVE_READ_BIAS         RWSEM_ACTIVE_BIAS
 #define RWSEM_ACTIVE_WRITE_BIAS                (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
-       spinlock_t              wait_lock;
-       struct list_head        wait_list;
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-       struct lockdep_map      dep_map;
-#endif
-};
-
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
-#else
-# define __RWSEM_DEP_MAP_INIT(lockname)
-#endif
-
-#define __RWSEM_INITIALIZER(name) \
-       { RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait_lock), \
-         LIST_HEAD_INIT((name).wait_list) \
-         __RWSEM_DEP_MAP_INIT(name) }
-
-#define DECLARE_RWSEM(name)            \
-       struct rw_semaphore name = __RWSEM_INITIALIZER(name)
-
-extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
-extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
-extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem);
-extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
-
-extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
-                        struct lock_class_key *key);
-
-#define init_rwsem(sem)                                \
-do {                                           \
-       static struct lock_class_key __key;     \
-                                               \
-       __init_rwsem((sem), #sem, &__key);      \
-} while (0)
-
-static inline void init_rwsem(struct rw_semaphore *sem)
-{
-       sem->count = RWSEM_UNLOCKED_VALUE;
-       spin_lock_init(&sem->wait_lock);
-       INIT_LIST_HEAD(&sem->wait_list);
-}
 
 /*
  * lock for reading
@@ -179,10 +128,5 @@ static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
        return atomic_add_return(delta, (atomic_t *)(&sem->count));
 }
 
-static inline int rwsem_is_locked(struct rw_semaphore *sem)
-{
-       return (sem->count != 0);
-}
-
 #endif /* __KERNEL__ */
 #endif /* _ASM_SH_RWSEM_H */
index a78701d..4a53500 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <asm-generic/sections.h>
 
-extern void __nosave_begin, __nosave_end;
+extern long __nosave_begin, __nosave_end;
 extern long __machvec_start, __machvec_end;
 extern char __uncached_start, __uncached_end;
 extern char _ebss[];
index c2b0aaa..e53b4b3 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/io.h>
 #include <linux/sh_timer.h>
 #include <linux/serial_sci.h>
-#include <asm/machtypes.h>
+#include <generated/machtypes.h>
 
 static struct resource rtc_resources[] = {
        [0] = {
@@ -230,10 +230,10 @@ static struct platform_device *sh7750_devices[] __initdata = {
 static int __init sh7750_devices_setup(void)
 {
        if (mach_is_rts7751r2d()) {
-               platform_register_device(&scif_device);
+               platform_device_register(&scif_device);
        } else {
-               platform_register_device(&sci_device);
-               platform_register_device(&scif_device);
+               platform_device_register(&sci_device);
+               platform_device_register(&scif_device);
        }
 
        return platform_add_devices(sh7750_devices,
@@ -255,12 +255,17 @@ static struct platform_device *sh7750_early_devices[] __initdata = {
 
 void __init plat_early_device_setup(void)
 {
+       struct platform_device *dev[1];
+
        if (mach_is_rts7751r2d()) {
                scif_platform_data.scscr |= SCSCR_CKE1;
-               early_platform_add_devices(&scif_device, 1);
+               dev[0] = &scif_device;
+               early_platform_add_devices(dev, 1);
        } else {
-               early_platform_add_devices(&sci_device, 1);
-               early_platform_add_devices(&scif_device, 1);
+               dev[0] = &sci_device;
+               early_platform_add_devices(dev, 1);
+               dev[0] = &scif_device;
+               early_platform_add_devices(dev, 1);
        }
 
        early_platform_add_devices(sh7750_early_devices,
index 948fdb6..38e8628 100644 (file)
@@ -17,6 +17,7 @@
 static DEFINE_PER_CPU(struct cpu, cpu_devices);
 
 cpumask_t cpu_core_map[NR_CPUS];
+EXPORT_SYMBOL(cpu_core_map);
 
 static cpumask_t cpu_coregroup_map(unsigned int cpu)
 {
index faa8f86..0901b2f 100644 (file)
 void __delay(unsigned long loops)
 {
        __asm__ __volatile__(
+               /*
+                * ST40-300 appears to have an issue with this code,
+                * normally taking two cycles each loop, as with all
+                * other SH variants. If however the branch and the
+                * delay slot straddle an 8 byte boundary, this increases
+                * to 3 cycles.
+                * This align directive ensures this doesn't occur.
+                */
+               ".balign 8\n\t"
+
                "tst    %0, %0\n\t"
                "1:\t"
                "bf/s   1b\n\t"
index 88d3dc3..5a580ea 100644 (file)
@@ -108,7 +108,8 @@ void copy_user_highpage(struct page *to, struct page *from,
                kunmap_atomic(vfrom, KM_USER0);
        }
 
-       if (pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK))
+       if (pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK) ||
+           (vma->vm_flags & VM_EXEC))
                __flush_purge_region(vto, PAGE_SIZE);
 
        kunmap_atomic(vto, KM_USER1);
index 38f37b3..d0b83f6 100644 (file)
@@ -34,6 +34,8 @@
 #define __O_SYNC       0x800000
 #define O_SYNC         (__O_SYNC|O_DSYNC)
 
+#define O_PATH         0x1000000
+
 #define F_GETOWN       5       /*  for sockets. */
 #define F_SETOWN       6       /*  for sockets. */
 #define F_GETLK                7
index 47f9583..444e7be 100644 (file)
@@ -30,7 +30,7 @@
        : "r" (uaddr), "r" (oparg), "i" (-EFAULT)       \
        : "memory")
 
-static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
 {
        int op = (encoded_op >> 28) & 7;
        int cmp = (encoded_op >> 24) & 15;
@@ -38,7 +38,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
        int cmparg = (encoded_op << 20) >> 20;
        int oldval = 0, ret, tem;
 
-       if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(int))))
+       if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))))
                return -EFAULT;
        if (unlikely((((unsigned long) uaddr) & 0x3UL)))
                return -EINVAL;
@@ -85,26 +85,30 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
 }
 
 static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+                             u32 oldval, u32 newval)
 {
+       int ret = 0;
+
        __asm__ __volatile__(
-       "\n1:   casa    [%3] %%asi, %2, %0\n"
+       "\n1:   casa    [%4] %%asi, %3, %1\n"
        "2:\n"
        "       .section .fixup,#alloc,#execinstr\n"
        "       .align  4\n"
        "3:     sethi   %%hi(2b), %0\n"
        "       jmpl    %0 + %%lo(2b), %%g0\n"
-       "        mov    %4, %0\n"
+       "       mov     %5, %0\n"
        "       .previous\n"
        "       .section __ex_table,\"a\"\n"
        "       .align  4\n"
        "       .word   1b, 3b\n"
        "       .previous\n"
-       : "=r" (newval)
-       : "0" (newval), "r" (oldval), "r" (uaddr), "i" (-EFAULT)
+       : "+r" (ret), "=r" (newval)
+       : "1" (newval), "r" (oldval), "r" (uaddr), "i" (-EFAULT)
        : "memory");
 
-       return newval;
+       *uval = newval;
+       return ret;
 }
 
 #endif /* !(_SPARC64_FUTEX_H) */
index a2f5c61..843e4fa 100644 (file)
@@ -43,4 +43,6 @@ static inline u64 picl_value(unsigned int nmi_hz)
 
 extern u64 pcr_enable;
 
+extern int pcr_arch_init(void);
+
 #endif /* __PCR_H */
index a2b4302..069bf4d 100644 (file)
 
 #ifdef __KERNEL__
 
-#include <linux/list.h>
-#include <linux/spinlock.h>
-
-struct rwsem_waiter;
-
-struct rw_semaphore {
-       signed long                     count;
 #define RWSEM_UNLOCKED_VALUE           0x00000000L
 #define RWSEM_ACTIVE_BIAS              0x00000001L
 #define RWSEM_ACTIVE_MASK              0xffffffffL
 #define RWSEM_WAITING_BIAS             (-RWSEM_ACTIVE_MASK-1)
 #define RWSEM_ACTIVE_READ_BIAS         RWSEM_ACTIVE_BIAS
 #define RWSEM_ACTIVE_WRITE_BIAS                (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
-       spinlock_t                      wait_lock;
-       struct list_head                wait_list;
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-       struct lockdep_map              dep_map;
-#endif
-};
-
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
-#else
-# define __RWSEM_DEP_MAP_INIT(lockname)
-#endif
-
-#define __RWSEM_INITIALIZER(name) \
-{ RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait_lock), \
-  LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) }
-
-#define DECLARE_RWSEM(name) \
-       struct rw_semaphore name = __RWSEM_INITIALIZER(name)
-
-extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
-extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
-extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem);
-extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
-
-extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
-                        struct lock_class_key *key);
-
-#define init_rwsem(sem)                                                \
-do {                                                           \
-       static struct lock_class_key __key;                     \
-                                                               \
-       __init_rwsem((sem), #sem, &__key);                      \
-} while (0)
 
 /*
  * lock for reading
@@ -160,11 +119,6 @@ static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
        return atomic64_add_return(delta, (atomic64_t *)(&sem->count));
 }
 
-static inline int rwsem_is_locked(struct rw_semaphore *sem)
-{
-       return (sem->count != 0);
-}
-
 #endif /* __KERNEL__ */
 
 #endif /* _SPARC64_RWSEM_H */
index 47977a7..72509d0 100644 (file)
@@ -255,10 +255,9 @@ static inline iopte_t *alloc_npages(struct device *dev, struct iommu *iommu,
 static int iommu_alloc_ctx(struct iommu *iommu)
 {
        int lowest = iommu->ctx_lowest_free;
-       int sz = IOMMU_NUM_CTXS - lowest;
-       int n = find_next_zero_bit(iommu->ctx_bitmap, sz, lowest);
+       int n = find_next_zero_bit(iommu->ctx_bitmap, IOMMU_NUM_CTXS, lowest);
 
-       if (unlikely(n == sz)) {
+       if (unlikely(n == IOMMU_NUM_CTXS)) {
                n = find_next_zero_bit(iommu->ctx_bitmap, lowest, 1);
                if (unlikely(n == lowest)) {
                        printk(KERN_WARNING "IOMMU: Ran out of contexts.\n");
index aeaa09a..2cdc131 100644 (file)
@@ -700,10 +700,8 @@ static void pcic_clear_clock_irq(void)
 
 static irqreturn_t pcic_timer_handler (int irq, void *h)
 {
-       write_seqlock(&xtime_lock);     /* Dummy, to show that we remember */
        pcic_clear_clock_irq();
-       do_timer(1);
-       write_sequnlock(&xtime_lock);
+       xtime_update(1);
 #ifndef CONFIG_SMP
        update_process_times(user_mode(get_irq_regs()));
 #endif
index ae96cf5..7c2ced6 100644 (file)
@@ -167,5 +167,3 @@ out_unregister:
        unregister_perf_hsvc();
        return err;
 }
-
-early_initcall(pcr_arch_init);
index b6a2b8f..555a76d 100644 (file)
@@ -49,6 +49,7 @@
 #include <asm/mdesc.h>
 #include <asm/ldc.h>
 #include <asm/hypervisor.h>
+#include <asm/pcr.h>
 
 #include "cpumap.h"
 
@@ -1358,6 +1359,7 @@ void __cpu_die(unsigned int cpu)
 
 void __init smp_cpus_done(unsigned int max_cpus)
 {
+       pcr_arch_init();
 }
 
 void smp_send_reschedule(int cpu)
index 9c743b1..4211bfc 100644 (file)
@@ -85,7 +85,7 @@ int update_persistent_clock(struct timespec now)
 
 /*
  * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
+ * as well as call the "xtime_update()" routine every clocktick
  */
 
 #define TICK_SIZE (tick_nsec / 1000)
@@ -96,14 +96,9 @@ static irqreturn_t timer_interrupt(int dummy, void *dev_id)
        profile_tick(CPU_PROFILING);
 #endif
 
-       /* Protect counter clear so that do_gettimeoffset works */
-       write_seqlock(&xtime_lock);
-
        clear_clock_irq();
 
-       do_timer(1);
-
-       write_sequnlock(&xtime_lock);
+       xtime_update(1);
 
 #ifndef CONFIG_SMP
        update_process_times(user_mode(get_irq_regs()));
index 8cc0345..8f096e8 100644 (file)
@@ -24,9 +24,9 @@ retl_efault:
        .globl  __do_int_store
 __do_int_store:
        ld      [%o2], %g1
-       cmp     %1, 2
+       cmp     %o1, 2
        be      2f
-        cmp    %1, 4
+        cmp    %o1, 4
        be      1f
         srl    %g1, 24, %g2
        srl     %g1, 16, %g7
index cbddeb3..d3c7a12 100644 (file)
@@ -16,7 +16,7 @@
 #define ATOMIC_HASH(a) (&__atomic_hash[(((unsigned long)a)>>8) & (ATOMIC_HASH_SIZE-1)])
 
 spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] = {
-       [0 ... (ATOMIC_HASH_SIZE-1)] = SPIN_LOCK_UNLOCKED
+       [0 ... (ATOMIC_HASH_SIZE-1)] = __SPIN_LOCK_UNLOCKED(__atomic_hash)
 };
 
 #else /* SMP */
index 764b3eb..48d00e7 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include <linux/string.h>
-#include <linux/bitops.h>
+#include <linux/bitmap.h>
 
 #include <asm/bitext.h>
 
@@ -80,8 +80,7 @@ int bit_map_string_get(struct bit_map *t, int len, int align)
                while (test_bit(offset + i, t->map) == 0) {
                        i++;
                        if (i == len) {
-                               for (i = 0; i < len; i++)
-                                       __set_bit(offset + i, t->map);
+                               bitmap_set(t->map, offset, len);
                                if (offset == t->first_free)
                                        t->first_free = find_next_zero_bit
                                                        (t->map, t->size,
index fe0d10d..d03ec12 100644 (file)
 #include <linux/uaccess.h>
 #include <linux/errno.h>
 
-extern struct __get_user futex_set(int __user *v, int i);
-extern struct __get_user futex_add(int __user *v, int n);
-extern struct __get_user futex_or(int __user *v, int n);
-extern struct __get_user futex_andn(int __user *v, int n);
-extern struct __get_user futex_cmpxchg(int __user *v, int o, int n);
+extern struct __get_user futex_set(u32 __user *v, int i);
+extern struct __get_user futex_add(u32 __user *v, int n);
+extern struct __get_user futex_or(u32 __user *v, int n);
+extern struct __get_user futex_andn(u32 __user *v, int n);
+extern struct __get_user futex_cmpxchg(u32 __user *v, int o, int n);
 
 #ifndef __tilegx__
-extern struct __get_user futex_xor(int __user *v, int n);
+extern struct __get_user futex_xor(u32 __user *v, int n);
 #else
-static inline struct __get_user futex_xor(int __user *uaddr, int n)
+static inline struct __get_user futex_xor(u32 __user *uaddr, int n)
 {
        struct __get_user asm_ret = __get_user_4(uaddr);
        if (!asm_ret.err) {
@@ -53,7 +53,7 @@ static inline struct __get_user futex_xor(int __user *uaddr, int n)
 }
 #endif
 
-static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
 {
        int op = (encoded_op >> 28) & 7;
        int cmp = (encoded_op >> 24) & 15;
@@ -65,7 +65,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
        if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
                oparg = 1 << oparg;
 
-       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
        pagefault_disable();
@@ -119,16 +119,17 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
        return ret;
 }
 
-static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
-                                               int newval)
+static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+                                               u32 oldval, u32 newval)
 {
        struct __get_user asm_ret;
 
-       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
        asm_ret = futex_cmpxchg(uaddr, oldval, newval);
-       return asm_ret.err ? asm_ret.err : asm_ret.val;
+       *uval = asm_ret.val;
+       return asm_ret.err;
 }
 
 #ifndef __tilegx__
index e351e14..1e78940 100644 (file)
@@ -7,6 +7,7 @@ config UML
        bool
        default y
        select HAVE_GENERIC_HARDIRQS
+       select GENERIC_HARDIRQS_NO_DEPRECATED
 
 config MMU
        bool
index 5ee3280..02fb017 100644 (file)
@@ -10,6 +10,8 @@ endmenu
 
 config UML_X86
        def_bool y
+       select GENERIC_FIND_FIRST_BIT
+       select GENERIC_FIND_NEXT_BIT
 
 config 64BIT
        bool
@@ -19,6 +21,9 @@ config X86_32
        def_bool !64BIT
        select HAVE_AOUT
 
+config X86_64
+       def_bool 64BIT
+
 config RWSEM_XCHGADD_ALGORITHM
        def_bool X86_XADD
 
index 975613b..c70e047 100644 (file)
@@ -124,35 +124,18 @@ void mconsole_log(struct mc_request *req)
 #if 0
 void mconsole_proc(struct mc_request *req)
 {
-       struct nameidata nd;
        struct vfsmount *mnt = current->nsproxy->pid_ns->proc_mnt;
        struct file *file;
-       int n, err;
+       int n;
        char *ptr = req->request.data, *buf;
        mm_segment_t old_fs = get_fs();
 
        ptr += strlen("proc");
        ptr = skip_spaces(ptr);
 
-       err = vfs_path_lookup(mnt->mnt_root, mnt, ptr, LOOKUP_FOLLOW, &nd);
-       if (err) {
-               mconsole_reply(req, "Failed to look up file", 1, 0);
-               goto out;
-       }
-
-       err = may_open(&nd.path, MAY_READ, O_RDONLY);
-       if (result) {
-               mconsole_reply(req, "Failed to open file", 1, 0);
-               path_put(&nd.path);
-               goto out;
-       }
-
-       file = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY,
-                          current_cred());
-       err = PTR_ERR(file);
+       file = file_open_root(mnt->mnt_root, mnt, ptr, O_RDONLY);
        if (IS_ERR(file)) {
                mconsole_reply(req, "Failed to open file", 1, 0);
-               path_put(&nd.path);
                goto out;
        }
 
index ba4a98b..620f5b7 100644 (file)
@@ -185,7 +185,7 @@ struct ubd {
        .no_cow =               0, \
        .shared =               0, \
        .cow =                  DEFAULT_COW, \
-       .lock =                 SPIN_LOCK_UNLOCKED,     \
+       .lock =                 __SPIN_LOCK_UNLOCKED(ubd_devs.lock), \
        .request =              NULL, \
        .start_sg =             0, \
        .end_sg =               0, \
index 3f0ac9e..64cfea8 100644 (file)
@@ -35,8 +35,10 @@ int show_interrupts(struct seq_file *p, void *v)
        }
 
        if (i < NR_IRQS) {
-               raw_spin_lock_irqsave(&irq_desc[i].lock, flags);
-               action = irq_desc[i].action;
+               struct irq_desc *desc = irq_to_desc(i);
+
+               raw_spin_lock_irqsave(&desc->lock, flags);
+               action = desc->action;
                if (!action)
                        goto skip;
                seq_printf(p, "%3d: ",i);
@@ -46,7 +48,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
 #endif
-               seq_printf(p, " %14s", irq_desc[i].chip->name);
+               seq_printf(p, " %14s", get_irq_desc_chip(desc)->name);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
@@ -54,7 +56,7 @@ int show_interrupts(struct seq_file *p, void *v)
 
                seq_putc(p, '\n');
 skip:
-               raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+               raw_spin_unlock_irqrestore(&desc->lock, flags);
        } else if (i == NR_IRQS)
                seq_putc(p, '\n');
 
@@ -360,10 +362,10 @@ EXPORT_SYMBOL(um_request_irq);
 EXPORT_SYMBOL(reactivate_fd);
 
 /*
- * irq_chip must define (startup || enable) &&
- * (shutdown || disable) && end
+ * irq_chip must define at least enable/disable and ack when
+ * the edge handler is used.
  */
-static void dummy(unsigned int irq)
+static void dummy(struct irq_data *d)
 {
 }
 
@@ -371,20 +373,17 @@ static void dummy(unsigned int irq)
 static struct irq_chip normal_irq_type = {
        .name = "SIGIO",
        .release = free_irq_by_irq_and_dev,
-       .disable = dummy,
-       .enable = dummy,
-       .ack = dummy,
-       .end = dummy
+       .irq_disable = dummy,
+       .irq_enable = dummy,
+       .irq_ack = dummy,
 };
 
 static struct irq_chip SIGVTALRM_irq_type = {
        .name = "SIGVTALRM",
        .release = free_irq_by_irq_and_dev,
-       .shutdown = dummy, /* never called */
-       .disable = dummy,
-       .enable = dummy,
-       .ack = dummy,
-       .end = dummy
+       .irq_disable = dummy,
+       .irq_enable = dummy,
+       .irq_ack = dummy,
 };
 
 void __init init_IRQ(void)
index d5ed94d..f8958b0 100644 (file)
@@ -64,8 +64,12 @@ config X86
        select HAVE_TEXT_POKE_SMP
        select HAVE_GENERIC_HARDIRQS
        select HAVE_SPARSE_IRQ
+       select GENERIC_FIND_FIRST_BIT
+       select GENERIC_FIND_NEXT_BIT
        select GENERIC_IRQ_PROBE
        select GENERIC_PENDING_IRQ if SMP
+       select GENERIC_IRQ_SHOW
+       select IRQ_FORCED_THREADING
        select USE_GENERIC_SMP_HELPERS if SMP
 
 config INSTRUCTION_DECODER
@@ -382,6 +386,8 @@ config X86_INTEL_CE
        depends on X86_32
        depends on X86_EXTENDED_PLATFORM
        select X86_REBOOTFIXUPS
+       select OF
+       select OF_EARLY_FLATTREE
        ---help---
          Select for the Intel CE media processor (CE4100) SOC.
          This option compiles in support for the CE4100 SOC for settop
@@ -811,7 +817,7 @@ config X86_LOCAL_APIC
 
 config X86_IO_APIC
        def_bool y
-       depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC
+       depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_IOAPIC
 
 config X86_VISWS_APIC
        def_bool y
@@ -1705,7 +1711,7 @@ config HAVE_ARCH_EARLY_PFN_TO_NID
        depends on NUMA
 
 config USE_PERCPU_NUMA_NODE_ID
-       def_bool X86_64
+       def_bool y
        depends on NUMA
 
 menu "Power management and ACPI options"
@@ -2066,9 +2072,10 @@ config SCx200HR_TIMER
 
 config OLPC
        bool "One Laptop Per Child support"
+       depends on !X86_PAE
        select GPIOLIB
-       select OLPC_OPENFIRMWARE
-       depends on !X86_64 && !X86_PAE
+       select OF
+       select OF_PROMTREE if PROC_DEVICETREE
        ---help---
          Add support for detecting the unique features of the OLPC
          XO hardware.
@@ -2079,21 +2086,6 @@ config OLPC_XO1
        ---help---
          Add support for non-essential features of the OLPC XO-1 laptop.
 
-config OLPC_OPENFIRMWARE
-       bool "Support for OLPC's Open Firmware"
-       depends on !X86_64 && !X86_PAE
-       default n
-       select OF
-       help
-         This option adds support for the implementation of Open Firmware
-         that is used on the OLPC XO-1 Children's Machine.
-         If unsure, say N here.
-
-config OLPC_OPENFIRMWARE_DT
-       bool
-       default y if OLPC_OPENFIRMWARE && PROC_DEVICETREE
-       select OF_PROMTREE
-
 endif # X86_32
 
 config AMD_NB
index 283c5a6..ed47e6e 100644 (file)
@@ -294,11 +294,6 @@ config X86_GENERIC
 
 endif
 
-config X86_CPU
-       def_bool y
-       select GENERIC_FIND_FIRST_BIT
-       select GENERIC_FIND_NEXT_BIT
-
 #
 # Define implied options from the CPU selection here
 config X86_INTERNODE_CACHE_SHIFT
index 646aa78..46a8238 100644 (file)
@@ -62,7 +62,12 @@ int main(int argc, char *argv[])
        if (fseek(f, -4L, SEEK_END)) {
                perror(argv[1]);
        }
-       fread(&olen, sizeof olen, 1, f);
+
+       if (fread(&olen, sizeof(olen), 1, f) != 1) {
+               perror(argv[1]);
+               return 1;
+       }
+
        ilen = ftell(f);
        olen = getle32(&olen);
        fclose(f);
index 518bb99..430312b 100644 (file)
@@ -25,6 +25,8 @@
 #define sysretl_audit ia32_ret_from_sys_call
 #endif
 
+       .section .entry.text, "ax"
+
 #define IA32_NR_syscalls ((ia32_syscall_end - ia32_sys_call_table)/8)
 
        .macro IA32_ARG_FIXUP noebp=0
@@ -126,26 +128,20 @@ ENTRY(ia32_sysenter_target)
         */
        ENABLE_INTERRUPTS(CLBR_NONE)
        movl    %ebp,%ebp               /* zero extension */
-       pushq   $__USER32_DS
-       CFI_ADJUST_CFA_OFFSET 8
+       pushq_cfi $__USER32_DS
        /*CFI_REL_OFFSET ss,0*/
-       pushq   %rbp
-       CFI_ADJUST_CFA_OFFSET 8
+       pushq_cfi %rbp
        CFI_REL_OFFSET rsp,0
-       pushfq
-       CFI_ADJUST_CFA_OFFSET 8
+       pushfq_cfi
        /*CFI_REL_OFFSET rflags,0*/
        movl    8*3-THREAD_SIZE+TI_sysenter_return(%rsp), %r10d
        CFI_REGISTER rip,r10
-       pushq   $__USER32_CS
-       CFI_ADJUST_CFA_OFFSET 8
+       pushq_cfi $__USER32_CS
        /*CFI_REL_OFFSET cs,0*/
        movl    %eax, %eax
-       pushq   %r10
-       CFI_ADJUST_CFA_OFFSET 8
+       pushq_cfi %r10
        CFI_REL_OFFSET rip,0
-       pushq   %rax
-       CFI_ADJUST_CFA_OFFSET 8
+       pushq_cfi %rax
        cld
        SAVE_ARGS 0,0,1
        /* no need to do an access_ok check here because rbp has been
@@ -182,11 +178,9 @@ sysexit_from_sys_call:
        xorq    %r9,%r9
        xorq    %r10,%r10
        xorq    %r11,%r11
-       popfq
-       CFI_ADJUST_CFA_OFFSET -8
+       popfq_cfi
        /*CFI_RESTORE rflags*/
-       popq    %rcx                            /* User %esp */
-       CFI_ADJUST_CFA_OFFSET -8
+       popq_cfi %rcx                           /* User %esp */
        CFI_REGISTER rsp,rcx
        TRACE_IRQS_ON
        ENABLE_INTERRUPTS_SYSEXIT32
@@ -421,8 +415,7 @@ ENTRY(ia32_syscall)
         */
        ENABLE_INTERRUPTS(CLBR_NONE)
        movl %eax,%eax
-       pushq %rax
-       CFI_ADJUST_CFA_OFFSET 8
+       pushq_cfi %rax
        cld
        /* note the registers are not zero extended to the sf.
           this could be a problem. */
@@ -851,4 +844,7 @@ ia32_sys_call_table:
        .quad sys_fanotify_init
        .quad sys32_fanotify_mark
        .quad sys_prlimit64             /* 340 */
+       .quad sys_name_to_handle_at
+       .quad compat_sys_open_by_handle_at
+       .quad compat_sys_clock_adjtime
 ia32_syscall_end:
index 211ca3f..b964ec4 100644 (file)
@@ -88,6 +88,7 @@ extern int acpi_disabled;
 extern int acpi_pci_disabled;
 extern int acpi_skip_timer_override;
 extern int acpi_use_timer_override;
+extern int acpi_fix_pin2_polarity;
 
 extern u8 acpi_sci_flags;
 extern int acpi_sci_override_gsi;
@@ -185,15 +186,7 @@ struct bootnode;
 
 #ifdef CONFIG_ACPI_NUMA
 extern int acpi_numa;
-extern void acpi_get_nodes(struct bootnode *physnodes, unsigned long start,
-                               unsigned long end);
-extern int acpi_scan_nodes(unsigned long start, unsigned long end);
-#define NR_NODE_MEMBLKS (MAX_NUMNODES*2)
-
-#ifdef CONFIG_NUMA_EMU
-extern void acpi_fake_nodes(const struct bootnode *fake_nodes,
-                                  int num_nodes);
-#endif
+extern int x86_acpi_numa_init(void);
 #endif /* CONFIG_ACPI_NUMA */
 
 #define acpi_unlazy_tlb(x)     leave_mm(x)
index 64dc82e..e264ae5 100644 (file)
@@ -9,23 +9,20 @@ struct amd_nb_bus_dev_range {
        u8 dev_limit;
 };
 
-extern struct pci_device_id amd_nb_misc_ids[];
+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 int early_is_amd_nb(u32 value);
 extern int amd_cache_northbridges(void);
 extern void amd_flush_garts(void);
-extern int amd_numa_init(unsigned long start_pfn, unsigned long end_pfn);
-extern int amd_scan_nodes(void);
-
-#ifdef CONFIG_NUMA_EMU
-extern void amd_fake_nodes(const struct bootnode *nodes, int nr_nodes);
-extern void amd_get_nodes(struct bootnode *nodes);
-#endif
+extern int amd_numa_init(void);
+extern int amd_get_subcaches(int);
+extern int amd_set_subcaches(int, int);
 
 struct amd_northbridge {
        struct pci_dev *misc;
+       struct pci_dev *link;
 };
 
 struct amd_northbridge_info {
@@ -37,6 +34,7 @@ extern struct amd_northbridge_info amd_northbridges;
 
 #define AMD_NB_GART                    0x1
 #define AMD_NB_L3_INDEX_DISABLE                0x2
+#define AMD_NB_L3_PARTITIONING         0x4
 
 #ifdef CONFIG_AMD_NB
 
index 5e3969c..a279d98 100644 (file)
@@ -220,7 +220,6 @@ extern void enable_IR_x2apic(void);
 
 extern int get_physical_broadcast(void);
 
-extern void apic_disable(void);
 extern int lapic_get_maxlvt(void);
 extern void clear_local_APIC(void);
 extern void connect_bsp_APIC(void);
@@ -228,18 +227,17 @@ extern void disconnect_bsp_APIC(int virt_wire_setup);
 extern void disable_local_APIC(void);
 extern void lapic_shutdown(void);
 extern int verify_local_APIC(void);
-extern void cache_APIC_registers(void);
 extern void sync_Arb_IDs(void);
 extern void init_bsp_APIC(void);
 extern void setup_local_APIC(void);
 extern void end_local_APIC_setup(void);
+extern void bsp_end_local_APIC_setup(void);
 extern void init_apic_mappings(void);
 void register_lapic_address(unsigned long address);
 extern void setup_boot_APIC_clock(void);
 extern void setup_secondary_APIC_clock(void);
 extern int APIC_init_uniprocessor(void);
-extern void enable_NMI_through_LVT0(void);
-extern int apic_force_enable(void);
+extern int apic_force_enable(unsigned long addr);
 
 /*
  * On 32bit this is mach-xxx local
@@ -260,7 +258,6 @@ static inline void lapic_shutdown(void) { }
 #define local_apic_timer_c2_ok         1
 static inline void init_apic_mappings(void) { }
 static inline void disable_local_APIC(void) { }
-static inline void apic_disable(void) { }
 # define setup_boot_APIC_clock x86_init_noop
 # define setup_secondary_APIC_clock x86_init_noop
 #endif /* !CONFIG_X86_LOCAL_APIC */
@@ -306,8 +303,6 @@ struct apic {
 
        void (*setup_apic_routing)(void);
        int (*multi_timer_check)(int apic, int irq);
-       int (*apicid_to_node)(int logical_apicid);
-       int (*cpu_to_logical_apicid)(int cpu);
        int (*cpu_present_to_apicid)(int mps_cpu);
        void (*apicid_to_cpu_present)(int phys_apicid, physid_mask_t *retmap);
        void (*setup_portio_remap)(void);
@@ -355,6 +350,23 @@ struct apic {
        void (*icr_write)(u32 low, u32 high);
        void (*wait_icr_idle)(void);
        u32 (*safe_wait_icr_idle)(void);
+
+#ifdef CONFIG_X86_32
+       /*
+        * Called very early during boot from get_smp_config().  It should
+        * return the logical apicid.  x86_[bios]_cpu_to_apicid is
+        * initialized before this function is called.
+        *
+        * If logical apicid can't be determined that early, the function
+        * may return BAD_APICID.  Logical apicid will be configured after
+        * init_apic_ldr() while bringing up CPUs.  Note that NUMA affinity
+        * won't be applied properly during early boot in this case.
+        */
+       int (*x86_32_early_logical_apicid)(int cpu);
+
+       /* determine CPU -> NUMA node mapping */
+       int (*x86_32_numa_cpu_node)(int cpu);
+#endif
 };
 
 /*
@@ -502,6 +514,11 @@ extern struct apic apic_noop;
 
 extern struct apic apic_default;
 
+static inline int noop_x86_32_early_logical_apicid(int cpu)
+{
+       return BAD_APICID;
+}
+
 /*
  * Set up the logical destination ID.
  *
@@ -521,7 +538,7 @@ static inline int default_phys_pkg_id(int cpuid_apic, int index_msb)
        return cpuid_apic >> index_msb;
 }
 
-extern int default_apicid_to_node(int logical_apicid);
+extern int default_x86_32_numa_cpu_node(int cpu);
 
 #endif
 
@@ -557,12 +574,6 @@ static inline void default_ioapic_phys_id_map(physid_mask_t *phys_map, physid_ma
        *retmap = *phys_map;
 }
 
-/* Mapping from cpu number to logical apicid */
-static inline int default_cpu_to_logical_apicid(int cpu)
-{
-       return 1 << cpu;
-}
-
 static inline int __default_cpu_present_to_apicid(int mps_cpu)
 {
        if (mps_cpu < nr_cpu_ids && cpu_present(mps_cpu))
@@ -595,8 +606,4 @@ extern int default_check_phys_apicid_present(int phys_apicid);
 
 #endif /* CONFIG_X86_LOCAL_APIC */
 
-#ifdef CONFIG_X86_32
-extern u8 cpu_2_logical_apicid[NR_CPUS];
-#endif
-
 #endif /* _ASM_X86_APIC_H */
index 47a30ff..d87988b 100644 (file)
@@ -426,4 +426,16 @@ struct local_apic {
 #else
  #define BAD_APICID 0xFFFFu
 #endif
+
+enum ioapic_irq_destination_types {
+       dest_Fixed              = 0,
+       dest_LowestPrio         = 1,
+       dest_SMI                = 2,
+       dest__reserved_1        = 3,
+       dest_NMI                = 4,
+       dest_INIT               = 5,
+       dest__reserved_2        = 6,
+       dest_ExtINT             = 7
+};
+
 #endif /* _ASM_X86_APICDEF_H */
index c8bfe63..e020d88 100644 (file)
@@ -12,6 +12,7 @@
 /* setup data types */
 #define SETUP_NONE                     0
 #define SETUP_E820_EXT                 1
+#define SETUP_DTB                      2
 
 /* extensible setup data list node */
 struct setup_data {
diff --git a/arch/x86/include/asm/ce4100.h b/arch/x86/include/asm/ce4100.h
new file mode 100644 (file)
index 0000000..e656ad8
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _ASM_CE4100_H_
+#define _ASM_CE4100_H_
+
+int ce4100_pci_init(void);
+
+#endif
index 6e6e755..4564c8e 100644 (file)
@@ -32,6 +32,6 @@ extern void arch_unregister_cpu(int);
 
 DECLARE_PER_CPU(int, cpu_state);
 
-int __cpuinit mwait_usable(const struct cpuinfo_x86 *);
+int mwait_usable(const struct cpuinfo_x86 *);
 
 #endif /* _ASM_X86_CPU_H */
index 220e2ea..91f3e08 100644 (file)
 #define X86_FEATURE_NODEID_MSR (6*32+19) /* NodeId MSR */
 #define X86_FEATURE_TBM                (6*32+21) /* trailing bit manipulations */
 #define X86_FEATURE_TOPOEXT    (6*32+22) /* topology extensions CPUID leafs */
+#define X86_FEATURE_PERFCTR_CORE (6*32+23) /* core performance counter extensions */
 
 /*
  * Auxiliary flags: Linux defined - For features scattered in various
@@ -279,6 +280,7 @@ extern const char * const x86_power_flags[32];
 #define cpu_has_xsave          boot_cpu_has(X86_FEATURE_XSAVE)
 #define cpu_has_hypervisor     boot_cpu_has(X86_FEATURE_HYPERVISOR)
 #define cpu_has_pclmulqdq      boot_cpu_has(X86_FEATURE_PCLMULQDQ)
+#define cpu_has_perfctr_core   boot_cpu_has(X86_FEATURE_PERFCTR_CORE)
 
 #if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64)
 # define cpu_has_invlpg                1
index e99d55d..908b969 100644 (file)
@@ -96,7 +96,7 @@ extern void e820_setup_gap(void);
 extern int e820_search_gap(unsigned long *gapstart, unsigned long *gapsize,
                        unsigned long start_addr, unsigned long long end_addr);
 struct setup_data;
-extern void parse_e820_ext(struct setup_data *data, unsigned long pa_data);
+extern void parse_e820_ext(struct setup_data *data);
 
 #if defined(CONFIG_X86_64) || \
        (defined(CONFIG_X86_32) && defined(CONFIG_HIBERNATION))
index 57650ab..1cd6d26 100644 (file)
@@ -16,10 +16,13 @@ BUILD_INTERRUPT(call_function_single_interrupt,CALL_FUNCTION_SINGLE_VECTOR)
 BUILD_INTERRUPT(irq_move_cleanup_interrupt,IRQ_MOVE_CLEANUP_VECTOR)
 BUILD_INTERRUPT(reboot_interrupt,REBOOT_VECTOR)
 
-.irpc idx, "01234567"
+.irp idx,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, \
+       16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+.if NUM_INVALIDATE_TLB_VECTORS > \idx
 BUILD_INTERRUPT3(invalidate_interrupt\idx,
                 (INVALIDATE_TLB_VECTOR_START)+\idx,
                 smp_invalidate_interrupt)
+.endif
 .endr
 #endif
 
index 06850a7..2c6fc9e 100644 (file)
@@ -7,14 +7,12 @@
    frame pointer later */
 #ifdef CONFIG_FRAME_POINTER
        .macro FRAME
-       pushl %ebp
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %ebp
        CFI_REL_OFFSET ebp,0
        movl %esp,%ebp
        .endm
        .macro ENDFRAME
-       popl %ebp
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %ebp
        CFI_RESTORE ebp
        .endm
 #else
index 1f11ce4..d09bb03 100644 (file)
@@ -37,7 +37,7 @@
                       "+m" (*uaddr), "=&r" (tem)               \
                     : "r" (oparg), "i" (-EFAULT), "1" (0))
 
-static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
 {
        int op = (encoded_op >> 28) & 7;
        int cmp = (encoded_op >> 24) & 15;
@@ -48,7 +48,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
        if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
                oparg = 1 << oparg;
 
-       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
 #if defined(CONFIG_X86_32) && !defined(CONFIG_X86_BSWAP)
@@ -109,9 +109,10 @@ static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
        return ret;
 }
 
-static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
-                                               int newval)
+static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+                                               u32 oldval, u32 newval)
 {
+       int ret = 0;
 
 #if defined(CONFIG_X86_32) && !defined(CONFIG_X86_BSWAP)
        /* Real i386 machines have no cmpxchg instruction */
@@ -119,21 +120,22 @@ static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
                return -ENOSYS;
 #endif
 
-       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+       if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
-       asm volatile("1:\t" LOCK_PREFIX "cmpxchgl %3, %1\n"
+       asm volatile("1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n"
                     "2:\t.section .fixup, \"ax\"\n"
-                    "3:\tmov     %2, %0\n"
+                    "3:\tmov     %3, %0\n"
                     "\tjmp     2b\n"
                     "\t.previous\n"
                     _ASM_EXTABLE(1b, 3b)
-                    : "=a" (oldval), "+m" (*uaddr)
-                    : "i" (-EFAULT), "r" (newval), "0" (oldval)
+                    : "+r" (ret), "=a" (oldval), "+m" (*uaddr)
+                    : "i" (-EFAULT), "r" (newval), "1" (oldval)
                     : "memory"
        );
 
-       return oldval;
+       *uval = oldval;
+       return ret;
 }
 
 #endif
index 0274ec5..bb9efe8 100644 (file)
@@ -45,6 +45,30 @@ extern void invalidate_interrupt4(void);
 extern void invalidate_interrupt5(void);
 extern void invalidate_interrupt6(void);
 extern void invalidate_interrupt7(void);
+extern void invalidate_interrupt8(void);
+extern void invalidate_interrupt9(void);
+extern void invalidate_interrupt10(void);
+extern void invalidate_interrupt11(void);
+extern void invalidate_interrupt12(void);
+extern void invalidate_interrupt13(void);
+extern void invalidate_interrupt14(void);
+extern void invalidate_interrupt15(void);
+extern void invalidate_interrupt16(void);
+extern void invalidate_interrupt17(void);
+extern void invalidate_interrupt18(void);
+extern void invalidate_interrupt19(void);
+extern void invalidate_interrupt20(void);
+extern void invalidate_interrupt21(void);
+extern void invalidate_interrupt22(void);
+extern void invalidate_interrupt23(void);
+extern void invalidate_interrupt24(void);
+extern void invalidate_interrupt25(void);
+extern void invalidate_interrupt26(void);
+extern void invalidate_interrupt27(void);
+extern void invalidate_interrupt28(void);
+extern void invalidate_interrupt29(void);
+extern void invalidate_interrupt30(void);
+extern void invalidate_interrupt31(void);
 
 extern void irq_move_cleanup_interrupt(void);
 extern void reboot_interrupt(void);
index 36fb1a6..8dbe353 100644 (file)
@@ -11,8 +11,8 @@ kernel_physical_mapping_init(unsigned long start,
                             unsigned long page_size_mask);
 
 
-extern unsigned long __initdata e820_table_start;
-extern unsigned long __meminitdata e820_table_end;
-extern unsigned long __meminitdata e820_table_top;
+extern unsigned long __initdata pgt_buf_start;
+extern unsigned long __meminitdata pgt_buf_end;
+extern unsigned long __meminitdata pgt_buf_top;
 
 #endif /* _ASM_X86_INIT_32_H */
index f327d38..c4bd267 100644 (file)
@@ -63,17 +63,6 @@ union IO_APIC_reg_03 {
        } __attribute__ ((packed)) bits;
 };
 
-enum ioapic_irq_destination_types {
-       dest_Fixed = 0,
-       dest_LowestPrio = 1,
-       dest_SMI = 2,
-       dest__reserved_1 = 3,
-       dest_NMI = 4,
-       dest_INIT = 5,
-       dest__reserved_2 = 6,
-       dest_ExtINT = 7
-};
-
 struct IO_APIC_route_entry {
        __u32   vector          :  8,
                delivery_mode   :  3,   /* 000: FIXED
@@ -106,6 +95,10 @@ struct IR_IO_APIC_route_entry {
                index           : 15;
 } __attribute__ ((packed));
 
+#define IOAPIC_AUTO     -1
+#define IOAPIC_EDGE     0
+#define IOAPIC_LEVEL    1
+
 #ifdef CONFIG_X86_IO_APIC
 
 /*
@@ -150,11 +143,6 @@ extern int timer_through_8259;
 #define io_apic_assign_pci_irqs \
        (mp_irq_entries && !skip_ioapic_setup && io_apic_irqs)
 
-extern u8 io_apic_unique_id(u8 id);
-extern int io_apic_get_unique_id(int ioapic, int apic_id);
-extern int io_apic_get_version(int ioapic);
-extern int io_apic_get_redir_entries(int ioapic);
-
 struct io_apic_irq_attr;
 extern int io_apic_set_pci_routing(struct device *dev, int irq,
                 struct io_apic_irq_attr *irq_attr);
@@ -162,6 +150,8 @@ void setup_IO_APIC_irq_extra(u32 gsi);
 extern void ioapic_and_gsi_init(void);
 extern void ioapic_insert_resources(void);
 
+int io_apic_setup_irq_pin(unsigned int irq, int node, struct io_apic_irq_attr *attr);
+
 extern struct IO_APIC_route_entry **alloc_ioapic_entries(void);
 extern void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries);
 extern int save_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
@@ -186,6 +176,8 @@ extern void __init pre_init_apic_IRQ0(void);
 
 extern void mp_save_irq(struct mpc_intsrc *m);
 
+extern void disable_ioapic_support(void);
+
 #else  /* !CONFIG_X86_IO_APIC */
 
 #define io_apic_assign_pci_irqs 0
@@ -199,6 +191,26 @@ static inline int mp_find_ioapic(u32 gsi) { return 0; }
 struct io_apic_irq_attr;
 static inline int io_apic_set_pci_routing(struct device *dev, int irq,
                 struct io_apic_irq_attr *irq_attr) { return 0; }
+
+static inline struct IO_APIC_route_entry **alloc_ioapic_entries(void)
+{
+       return NULL;
+}
+
+static inline void free_ioapic_entries(struct IO_APIC_route_entry **ent) { }
+static inline int save_IO_APIC_setup(struct IO_APIC_route_entry **ent)
+{
+       return -ENOMEM;
+}
+
+static inline void mask_IO_APIC_setup(struct IO_APIC_route_entry **ent) { }
+static inline int restore_IO_APIC_setup(struct IO_APIC_route_entry **ent)
+{
+       return -ENOMEM;
+}
+
+static inline void mp_save_irq(struct mpc_intsrc *m) { };
+static inline void disable_ioapic_support(void) { }
 #endif
 
 #endif /* _ASM_X86_IO_APIC_H */
index 0b72282..615fa90 100644 (file)
@@ -123,10 +123,6 @@ extern void default_send_IPI_mask_sequence_phys(const struct cpumask *mask,
                                                 int vector);
 extern void default_send_IPI_mask_allbutself_phys(const struct cpumask *mask,
                                                         int vector);
-extern void default_send_IPI_mask_sequence_logical(const struct cpumask *mask,
-                                                        int vector);
-extern void default_send_IPI_mask_allbutself_logical(const struct cpumask *mask,
-                                                        int vector);
 
 /* Avoid include hell */
 #define NMI_VECTOR 0x02
@@ -150,6 +146,10 @@ static inline void __default_local_send_IPI_all(int vector)
 }
 
 #ifdef CONFIG_X86_32
+extern void default_send_IPI_mask_sequence_logical(const struct cpumask *mask,
+                                                        int vector);
+extern void default_send_IPI_mask_allbutself_logical(const struct cpumask *mask,
+                                                        int vector);
 extern void default_send_IPI_mask_logical(const struct cpumask *mask,
                                                 int vector);
 extern void default_send_IPI_allbutself(int vector);
index c704b38..ba870bb 100644 (file)
@@ -10,9 +10,6 @@
 #include <asm/apicdef.h>
 #include <asm/irq_vectors.h>
 
-/* Even though we don't support this, supply it to appease OF */
-static inline void irq_dispose_mapping(unsigned int virq) { }
-
 static inline int irq_canonicalize(int irq)
 {
        return ((irq == 2) ? 9 : irq);
diff --git a/arch/x86/include/asm/irq_controller.h b/arch/x86/include/asm/irq_controller.h
new file mode 100644 (file)
index 0000000..423bbbd
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef __IRQ_CONTROLLER__
+#define __IRQ_CONTROLLER__
+
+struct irq_domain {
+       int (*xlate)(struct irq_domain *h, const u32 *intspec, u32 intsize,
+                       u32 *out_hwirq, u32 *out_type);
+       void *priv;
+       struct device_node *controller;
+       struct list_head l;
+};
+
+#endif
index 6af0894..6e976ee 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _ASM_X86_IRQ_VECTORS_H
 #define _ASM_X86_IRQ_VECTORS_H
 
+#include <linux/threads.h>
 /*
  * Linux IRQ vector layout.
  *
@@ -16,8 +17,8 @@
  *  Vectors   0 ...  31 : system traps and exceptions - hardcoded events
  *  Vectors  32 ... 127 : device interrupts
  *  Vector  128         : legacy int80 syscall interface
- *  Vectors 129 ... 237 : device interrupts
- *  Vectors 238 ... 255 : special interrupts
+ *  Vectors 129 ... INVALIDATE_TLB_VECTOR_START-1 : device interrupts
+ *  Vectors INVALIDATE_TLB_VECTOR_START ... 255 : special interrupts
  *
  * 64-bit x86 has per CPU IDT tables, 32-bit has one shared IDT table.
  *
 #define THRESHOLD_APIC_VECTOR          0xf9
 #define REBOOT_VECTOR                  0xf8
 
-/* f0-f7 used for spreading out TLB flushes: */
-#define INVALIDATE_TLB_VECTOR_END      0xf7
-#define INVALIDATE_TLB_VECTOR_START    0xf0
-#define NUM_INVALIDATE_TLB_VECTORS        8
-
-/*
- * Local APIC timer IRQ vector is on a different priority level,
- * to work around the 'lost local interrupt if more than 2 IRQ
- * sources per level' errata.
- */
-#define LOCAL_TIMER_VECTOR             0xef
-
 /*
  * Generic system vector for platform specific use
  */
-#define X86_PLATFORM_IPI_VECTOR                0xed
+#define X86_PLATFORM_IPI_VECTOR                0xf7
 
 /*
  * IRQ work vector:
  */
-#define IRQ_WORK_VECTOR                        0xec
+#define IRQ_WORK_VECTOR                        0xf6
 
-#define UV_BAU_MESSAGE                 0xea
+#define UV_BAU_MESSAGE                 0xf5
 
 /*
  * Self IPI vector for machine checks
  */
-#define MCE_SELF_VECTOR                        0xeb
+#define MCE_SELF_VECTOR                        0xf4
 
 /* Xen vector callback to receive events in a HVM domain */
-#define XEN_HVM_EVTCHN_CALLBACK                0xe9
+#define XEN_HVM_EVTCHN_CALLBACK                0xf3
+
+/*
+ * Local APIC timer IRQ vector is on a different priority level,
+ * to work around the 'lost local interrupt if more than 2 IRQ
+ * sources per level' errata.
+ */
+#define LOCAL_TIMER_VECTOR             0xef
+
+/* up to 32 vectors used for spreading out TLB flushes: */
+#if NR_CPUS <= 32
+# define NUM_INVALIDATE_TLB_VECTORS    (NR_CPUS)
+#else
+# define NUM_INVALIDATE_TLB_VECTORS    (32)
+#endif
+
+#define INVALIDATE_TLB_VECTOR_END      (0xee)
+#define INVALIDATE_TLB_VECTOR_START    \
+       (INVALIDATE_TLB_VECTOR_END-NUM_INVALIDATE_TLB_VECTORS+1)
 
 #define NR_VECTORS                      256
 
index ca242d3..518bbbb 100644 (file)
@@ -13,7 +13,6 @@ enum die_val {
        DIE_PANIC,
        DIE_NMI,
        DIE_DIE,
-       DIE_NMIWATCHDOG,
        DIE_KERNELDEBUG,
        DIE_TRAP,
        DIE_GPF,
index 4a2d4e0..8b5393e 100644 (file)
@@ -36,8 +36,6 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
        unsigned cpu = smp_processor_id();
 
        if (likely(prev != next)) {
-               /* stop flush ipis for the previous mm */
-               cpumask_clear_cpu(cpu, mm_cpumask(prev));
 #ifdef CONFIG_SMP
                percpu_write(cpu_tlbstate.state, TLBSTATE_OK);
                percpu_write(cpu_tlbstate.active_mm, next);
@@ -47,6 +45,9 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
                /* Re-load page tables */
                load_cr3(next->pgd);
 
+               /* stop flush ipis for the previous mm */
+               cpumask_clear_cpu(cpu, mm_cpumask(prev));
+
                /*
                 * load the LDT, if the LDT is different:
                 */
index 0c90dd9..9c7d95f 100644 (file)
@@ -25,7 +25,6 @@ extern int pic_mode;
 #define MAX_IRQ_SOURCES                256
 
 extern unsigned int def_to_bigsmp;
-extern u8 apicid_2_node[];
 
 #ifdef CONFIG_X86_NUMAQ
 extern int mp_bus_id_to_node[MAX_MP_BUSSES];
@@ -33,8 +32,6 @@ extern int mp_bus_id_to_local[MAX_MP_BUSSES];
 extern int quad_local_to_mp_bus_id [NR_CPUS/4][4];
 #endif
 
-#define MAX_APICID             256
-
 #else /* CONFIG_X86_64: */
 
 #define MAX_MP_BUSSES          256
index 4d0dfa0..823d482 100644 (file)
 #define MSR_IA32_PERFCTR1              0x000000c2
 #define MSR_FSB_FREQ                   0x000000cd
 
+#define MSR_NHM_SNB_PKG_CST_CFG_CTL    0x000000e2
+#define NHM_C3_AUTO_DEMOTE             (1UL << 25)
+#define NHM_C1_AUTO_DEMOTE             (1UL << 26)
+#define ATM_LNC_C6_AUTO_DEMOTE         (1UL << 25)
+
 #define MSR_MTRRcap                    0x000000fe
 #define MSR_IA32_BBL_CR_CTL            0x00000119
 
@@ -47,6 +52,9 @@
 #define MSR_IA32_MCG_STATUS            0x0000017a
 #define MSR_IA32_MCG_CTL               0x0000017b
 
+#define MSR_OFFCORE_RSP_0              0x000001a6
+#define MSR_OFFCORE_RSP_1              0x000001a7
+
 #define MSR_IA32_PEBS_ENABLE           0x000003f1
 #define MSR_IA32_DS_AREA               0x00000600
 #define MSR_IA32_PERF_CAPABILITIES     0x00000345
index c76f5b9..07f4601 100644 (file)
@@ -7,7 +7,6 @@
 
 #ifdef CONFIG_X86_LOCAL_APIC
 
-extern void die_nmi(char *str, struct pt_regs *regs, int do_panic);
 extern int avail_to_resrv_perfctr_nmi_bit(unsigned int);
 extern int reserve_perfctr_nmi(unsigned int);
 extern void release_perfctr_nmi(unsigned int);
index 27da400..3d4dab4 100644 (file)
@@ -1,5 +1,57 @@
+#ifndef _ASM_X86_NUMA_H
+#define _ASM_X86_NUMA_H
+
+#include <asm/topology.h>
+#include <asm/apicdef.h>
+
+#ifdef CONFIG_NUMA
+
+#define NR_NODE_MEMBLKS                (MAX_NUMNODES*2)
+
+/*
+ * __apicid_to_node[] stores the raw mapping between physical apicid and
+ * node and is used to initialize cpu_to_node mapping.
+ *
+ * The mapping may be overridden by apic->numa_cpu_node() on 32bit and thus
+ * should be accessed by the accessors - set_apicid_to_node() and
+ * numa_cpu_node().
+ */
+extern s16 __apicid_to_node[MAX_LOCAL_APIC];
+
+static inline void set_apicid_to_node(int apicid, s16 node)
+{
+       __apicid_to_node[apicid] = node;
+}
+#else  /* CONFIG_NUMA */
+static inline void set_apicid_to_node(int apicid, s16 node)
+{
+}
+#endif /* CONFIG_NUMA */
+
 #ifdef CONFIG_X86_32
 # include "numa_32.h"
 #else
 # include "numa_64.h"
 #endif
+
+#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)            { }
+#endif /* CONFIG_NUMA */
+
+#ifdef CONFIG_DEBUG_PER_CPU_MAPS
+struct cpumask __cpuinit *debug_cpumask_set_cpu(int cpu, int enable);
+#endif
+
+#endif /* _ASM_X86_NUMA_H */
index b0ef2b4..c6beed1 100644 (file)
@@ -4,7 +4,12 @@
 extern int numa_off;
 
 extern int pxm_to_nid(int pxm);
-extern void numa_remove_cpu(int cpu);
+
+#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);
index 0493be3..344eb17 100644 (file)
@@ -2,23 +2,16 @@
 #define _ASM_X86_NUMA_64_H
 
 #include <linux/nodemask.h>
-#include <asm/apicdef.h>
 
 struct bootnode {
        u64 start;
        u64 end;
 };
 
-extern int compute_hash_shift(struct bootnode *nodes, int numblks,
-                             int *nodeids);
-
 #define ZONE_ALIGN (1UL << (MAX_ORDER+PAGE_SHIFT))
 
-extern void numa_init_array(void);
 extern int numa_off;
 
-extern s16 apicid_to_node[MAX_LOCAL_APIC];
-
 extern unsigned long numa_free_all_bootmem(void);
 extern void setup_node_bootmem(int nodeid, unsigned long start,
                               unsigned long end);
@@ -31,11 +24,11 @@ extern void setup_node_bootmem(int nodeid, unsigned long start,
  */
 #define NODE_MIN_SIZE (4*1024*1024)
 
-extern void __init init_cpu_to_node(void);
-extern void __cpuinit numa_set_node(int cpu, int node);
-extern void __cpuinit numa_clear_node(int cpu);
-extern void __cpuinit numa_add_cpu(int cpu);
-extern void __cpuinit numa_remove_cpu(int cpu);
+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)
@@ -43,11 +36,7 @@ extern void __cpuinit numa_remove_cpu(int cpu);
 void numa_emu_cmdline(char *);
 #endif /* CONFIG_NUMA_EMU */
 #else
-static inline void init_cpu_to_node(void)              { }
-static inline void numa_set_node(int cpu, int node)    { }
-static inline void numa_clear_node(int cpu)            { }
-static inline void numa_add_cpu(int cpu, int node)     { }
-static inline void numa_remove_cpu(int cpu)            { }
+static inline int numa_cpu_node(int cpu)               { return NUMA_NO_NODE; }
 #endif
 
 #endif /* _ASM_X86_NUMA_64_H */
index 641988e..c5d3a5a 100644 (file)
@@ -6,7 +6,7 @@
 
 #define OLPC_OFW_SIG 0x2057464F        /* aka "OFW " */
 
-#ifdef CONFIG_OLPC_OPENFIRMWARE
+#ifdef CONFIG_OLPC
 
 extern bool olpc_ofw_is_installed(void);
 
@@ -26,19 +26,15 @@ extern void setup_olpc_ofw_pgd(void);
 /* check if OFW was detected during boot */
 extern bool olpc_ofw_present(void);
 
-#else /* !CONFIG_OLPC_OPENFIRMWARE */
-
-static inline bool olpc_ofw_is_installed(void) { return false; }
+#else /* !CONFIG_OLPC */
 static inline void olpc_ofw_detect(void) { }
 static inline void setup_olpc_ofw_pgd(void) { }
-static inline bool olpc_ofw_present(void) { return false; }
-
-#endif /* !CONFIG_OLPC_OPENFIRMWARE */
+#endif /* !CONFIG_OLPC */
 
-#ifdef CONFIG_OLPC_OPENFIRMWARE_DT
+#ifdef CONFIG_OF_PROMTREE
 extern void olpc_dt_build_devicetree(void);
 #else
 static inline void olpc_dt_build_devicetree(void) { }
-#endif /* CONFIG_OLPC_OPENFIRMWARE_DT */
+#endif
 
 #endif /* _ASM_X86_OLPC_OFW_H */
index 1df6621..bce688d 100644 (file)
@@ -2,6 +2,7 @@
 #define _ASM_X86_PAGE_DEFS_H
 
 #include <linux/const.h>
+#include <linux/types.h>
 
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT     12
@@ -45,11 +46,15 @@ extern int devmem_is_allowed(unsigned long pagenr);
 extern unsigned long max_low_pfn_mapped;
 extern unsigned long max_pfn_mapped;
 
+static inline phys_addr_t get_max_mapped(void)
+{
+       return (phys_addr_t)max_pfn_mapped << PAGE_SHIFT;
+}
+
 extern unsigned long init_memory_mapping(unsigned long start,
                                         unsigned long end);
 
-extern void initmem_init(unsigned long start_pfn, unsigned long end_pfn,
-                               int acpi, int k8);
+extern void initmem_init(void);
 extern void free_initmem(void);
 
 #endif /* !__ASSEMBLY__ */
index 2071a8b..ebbc4d8 100644 (file)
@@ -558,13 +558,12 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
 static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
                              pmd_t *pmdp, pmd_t pmd)
 {
-#if PAGETABLE_LEVELS >= 3
        if (sizeof(pmdval_t) > sizeof(long))
                /* 5 arg words */
                pv_mmu_ops.set_pmd_at(mm, addr, pmdp, pmd);
        else
-               PVOP_VCALL4(pv_mmu_ops.set_pmd_at, mm, addr, pmdp, pmd.pmd);
-#endif
+               PVOP_VCALL4(pv_mmu_ops.set_pmd_at, mm, addr, pmdp,
+                           native_pmd_val(pmd));
 }
 #endif
 
index 260ac7a..a09e1f0 100644 (file)
@@ -273,34 +273,34 @@ do {                                                                      \
        typeof(var) pxo_new__ = (nval);                                 \
        switch (sizeof(var)) {                                          \
        case 1:                                                         \
-               asm("\n1:mov "__percpu_arg(1)",%%al"                    \
-                   "\n\tcmpxchgb %2, "__percpu_arg(1)                  \
+               asm("\n\tmov "__percpu_arg(1)",%%al"                    \
+                   "\n1:\tcmpxchgb %2, "__percpu_arg(1)                \
                    "\n\tjnz 1b"                                        \
-                           : "=a" (pxo_ret__), "+m" (var)              \
+                           : "=&a" (pxo_ret__), "+m" (var)             \
                            : "q" (pxo_new__)                           \
                            : "memory");                                \
                break;                                                  \
        case 2:                                                         \
-               asm("\n1:mov "__percpu_arg(1)",%%ax"                    \
-                   "\n\tcmpxchgw %2, "__percpu_arg(1)                  \
+               asm("\n\tmov "__percpu_arg(1)",%%ax"                    \
+                   "\n1:\tcmpxchgw %2, "__percpu_arg(1)                \
                    "\n\tjnz 1b"                                        \
-                           : "=a" (pxo_ret__), "+m" (var)              \
+                           : "=&a" (pxo_ret__), "+m" (var)             \
                            : "r" (pxo_new__)                           \
                            : "memory");                                \
                break;                                                  \
        case 4:                                                         \
-               asm("\n1:mov "__percpu_arg(1)",%%eax"                   \
-                   "\n\tcmpxchgl %2, "__percpu_arg(1)                  \
+               asm("\n\tmov "__percpu_arg(1)",%%eax"                   \
+                   "\n1:\tcmpxchgl %2, "__percpu_arg(1)                \
                    "\n\tjnz 1b"                                        \
-                           : "=a" (pxo_ret__), "+m" (var)              \
+                           : "=&a" (pxo_ret__), "+m" (var)             \
                            : "r" (pxo_new__)                           \
                            : "memory");                                \
                break;                                                  \
        case 8:                                                         \
-               asm("\n1:mov "__percpu_arg(1)",%%rax"                   \
-                   "\n\tcmpxchgq %2, "__percpu_arg(1)                  \
+               asm("\n\tmov "__percpu_arg(1)",%%rax"                   \
+                   "\n1:\tcmpxchgq %2, "__percpu_arg(1)                \
                    "\n\tjnz 1b"                                        \
-                           : "=a" (pxo_ret__), "+m" (var)              \
+                           : "=&a" (pxo_ret__), "+m" (var)             \
                            : "r" (pxo_new__)                           \
                            : "memory");                                \
                break;                                                  \
index e2f6a99..cc29086 100644 (file)
@@ -22,6 +22,7 @@
 
 #define ARCH_P4_CNTRVAL_BITS   (40)
 #define ARCH_P4_CNTRVAL_MASK   ((1ULL << ARCH_P4_CNTRVAL_BITS) - 1)
+#define ARCH_P4_UNFLAGGED_BIT  ((1ULL) << (ARCH_P4_CNTRVAL_BITS - 1))
 
 #define P4_ESCR_EVENT_MASK     0x7e000000U
 #define P4_ESCR_EVENT_SHIFT    25
index 45636ce..4c25ab4 100644 (file)
@@ -94,10 +94,6 @@ struct cpuinfo_x86 {
        int                     x86_cache_alignment;    /* In bytes */
        int                     x86_power;
        unsigned long           loops_per_jiffy;
-#ifdef CONFIG_SMP
-       /* cpus sharing the last level cache: */
-       cpumask_var_t           llc_shared_map;
-#endif
        /* cpuid returned max cores value: */
        u16                      x86_max_cores;
        u16                     apicid;
index b4ec95f..971e0b4 100644 (file)
@@ -1 +1,69 @@
-/* dummy prom.h; here to make linux/of.h's #includes happy */
+/*
+ * Definitions for Device tree / OpenFirmware handling on X86
+ *
+ * based on arch/powerpc/include/asm/prom.h which is
+ *         Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * 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.
+ */
+
+#ifndef _ASM_X86_PROM_H
+#define _ASM_X86_PROM_H
+#ifndef __ASSEMBLY__
+
+#include <linux/of.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+
+#include <asm/irq.h>
+#include <asm/atomic.h>
+#include <asm/setup.h>
+#include <asm/irq_controller.h>
+
+#ifdef CONFIG_OF
+extern int of_ioapic;
+extern u64 initial_dtb;
+extern void add_dtb(u64 data);
+extern void x86_add_irq_domains(void);
+void __cpuinit x86_of_pci_init(void);
+void x86_dtb_init(void);
+
+static inline struct device_node *pci_device_to_OF_node(struct pci_dev *pdev)
+{
+       return pdev ? pdev->dev.of_node : NULL;
+}
+
+static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
+{
+       return pci_device_to_OF_node(bus->self);
+}
+
+#else
+static inline void add_dtb(u64 data) { }
+static inline void x86_add_irq_domains(void) { }
+static inline void x86_of_pci_init(void) { }
+static inline void x86_dtb_init(void) { }
+#define of_ioapic 0
+#endif
+
+extern char cmd_line[COMMAND_LINE_SIZE];
+
+#define pci_address_to_pio pci_address_to_pio
+unsigned long pci_address_to_pio(phys_addr_t addr);
+
+/**
+ * irq_dispose_mapping - Unmap an interrupt
+ * @virq: linux virq number of the interrupt to unmap
+ *
+ * FIXME: We really should implement proper virq handling like power,
+ * but that's going to be major surgery.
+ */
+static inline void irq_dispose_mapping(unsigned int virq) { }
+
+#define HAVE_ARCH_DEVTREE_FIXUPS
+
+#endif /* __ASSEMBLY__ */
+#endif
index d1e41b0..df4cd32 100644 (file)
 #endif
 
 #ifdef __KERNEL__
-
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/lockdep.h>
 #include <asm/asm.h>
 
-struct rwsem_waiter;
-
-extern asmregparm struct rw_semaphore *
- rwsem_down_read_failed(struct rw_semaphore *sem);
-extern asmregparm struct rw_semaphore *
- rwsem_down_write_failed(struct rw_semaphore *sem);
-extern asmregparm struct rw_semaphore *
- rwsem_wake(struct rw_semaphore *);
-extern asmregparm struct rw_semaphore *
- rwsem_downgrade_wake(struct rw_semaphore *sem);
-
 /*
- * the semaphore definition
- *
  * The bias values and the counter type limits the number of
  * potential readers/writers to 32767 for 32 bits and 2147483647
  * for 64 bits.
@@ -74,43 +57,6 @@ extern asmregparm struct rw_semaphore *
 #define RWSEM_ACTIVE_READ_BIAS         RWSEM_ACTIVE_BIAS
 #define RWSEM_ACTIVE_WRITE_BIAS                (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
 
-typedef signed long rwsem_count_t;
-
-struct rw_semaphore {
-       rwsem_count_t           count;
-       spinlock_t              wait_lock;
-       struct list_head        wait_list;
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-       struct lockdep_map dep_map;
-#endif
-};
-
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
-#else
-# define __RWSEM_DEP_MAP_INIT(lockname)
-#endif
-
-
-#define __RWSEM_INITIALIZER(name)                              \
-{                                                              \
-       RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait_lock), \
-       LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) \
-}
-
-#define DECLARE_RWSEM(name)                                    \
-       struct rw_semaphore name = __RWSEM_INITIALIZER(name)
-
-extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
-                        struct lock_class_key *key);
-
-#define init_rwsem(sem)                                                \
-do {                                                           \
-       static struct lock_class_key __key;                     \
-                                                               \
-       __init_rwsem((sem), #sem, &__key);                      \
-} while (0)
-
 /*
  * lock for reading
  */
@@ -133,7 +79,7 @@ static inline void __down_read(struct rw_semaphore *sem)
  */
 static inline int __down_read_trylock(struct rw_semaphore *sem)
 {
-       rwsem_count_t result, tmp;
+       long result, tmp;
        asm volatile("# beginning __down_read_trylock\n\t"
                     "  mov          %0,%1\n\t"
                     "1:\n\t"
@@ -155,7 +101,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
  */
 static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
 {
-       rwsem_count_t tmp;
+       long tmp;
        asm volatile("# beginning down_write\n\t"
                     LOCK_PREFIX "  xadd      %1,(%2)\n\t"
                     /* adds 0xffff0001, returns the old value */
@@ -180,9 +126,8 @@ static inline void __down_write(struct rw_semaphore *sem)
  */
 static inline int __down_write_trylock(struct rw_semaphore *sem)
 {
-       rwsem_count_t ret = cmpxchg(&sem->count,
-                                   RWSEM_UNLOCKED_VALUE,
-                                   RWSEM_ACTIVE_WRITE_BIAS);
+       long ret = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
+                          RWSEM_ACTIVE_WRITE_BIAS);
        if (ret == RWSEM_UNLOCKED_VALUE)
                return 1;
        return 0;
@@ -193,7 +138,7 @@ static inline int __down_write_trylock(struct rw_semaphore *sem)
  */
 static inline void __up_read(struct rw_semaphore *sem)
 {
-       rwsem_count_t tmp;
+       long tmp;
        asm volatile("# beginning __up_read\n\t"
                     LOCK_PREFIX "  xadd      %1,(%2)\n\t"
                     /* subtracts 1, returns the old value */
@@ -211,7 +156,7 @@ static inline void __up_read(struct rw_semaphore *sem)
  */
 static inline void __up_write(struct rw_semaphore *sem)
 {
-       rwsem_count_t tmp;
+       long tmp;
        asm volatile("# beginning __up_write\n\t"
                     LOCK_PREFIX "  xadd      %1,(%2)\n\t"
                     /* subtracts 0xffff0001, returns the old value */
@@ -247,8 +192,7 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
 /*
  * implement atomic add functionality
  */
-static inline void rwsem_atomic_add(rwsem_count_t delta,
-                                   struct rw_semaphore *sem)
+static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
 {
        asm volatile(LOCK_PREFIX _ASM_ADD "%1,%0"
                     : "+m" (sem->count)
@@ -258,10 +202,9 @@ static inline void rwsem_atomic_add(rwsem_count_t delta,
 /*
  * implement exchange and add functionality
  */
-static inline rwsem_count_t rwsem_atomic_update(rwsem_count_t delta,
-                                               struct rw_semaphore *sem)
+static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
 {
-       rwsem_count_t tmp = delta;
+       long tmp = delta;
 
        asm volatile(LOCK_PREFIX "xadd %0,%1"
                     : "+r" (tmp), "+m" (sem->count)
@@ -270,10 +213,5 @@ static inline rwsem_count_t rwsem_atomic_update(rwsem_count_t delta,
        return tmp + delta;
 }
 
-static inline int rwsem_is_locked(struct rw_semaphore *sem)
-{
-       return (sem->count != 0);
-}
-
 #endif /* __KERNEL__ */
 #endif /* _ASM_X86_RWSEM_H */
index 4c2f63c..73b11bc 100644 (file)
 #endif
 #include <asm/thread_info.h>
 #include <asm/cpumask.h>
+#include <asm/cpufeature.h>
 
 extern int smp_num_siblings;
 extern unsigned int num_processors;
 
+static inline bool cpu_has_ht_siblings(void)
+{
+       bool has_siblings = false;
+#ifdef CONFIG_SMP
+       has_siblings = cpu_has_ht && smp_num_siblings > 1;
+#endif
+       return has_siblings;
+}
+
 DECLARE_PER_CPU(cpumask_var_t, cpu_sibling_map);
 DECLARE_PER_CPU(cpumask_var_t, cpu_core_map);
+/* cpus sharing the last level cache: */
+DECLARE_PER_CPU(cpumask_var_t, cpu_llc_shared_map);
 DECLARE_PER_CPU(u16, cpu_llc_id);
 DECLARE_PER_CPU(int, cpu_number);
 
@@ -36,14 +48,19 @@ static inline struct cpumask *cpu_core_mask(int cpu)
        return per_cpu(cpu_core_map, cpu);
 }
 
+static inline struct cpumask *cpu_llc_shared_mask(int cpu)
+{
+       return per_cpu(cpu_llc_shared_map, cpu);
+}
+
 DECLARE_EARLY_PER_CPU(u16, x86_cpu_to_apicid);
 DECLARE_EARLY_PER_CPU(u16, x86_bios_cpu_apicid);
+#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_32)
+DECLARE_EARLY_PER_CPU(int, x86_cpu_to_logical_apicid);
+#endif
 
 /* Static state in head.S used to set up a CPU */
-extern struct {
-       void *sp;
-       unsigned short ss;
-} stack_start;
+extern unsigned long stack_start; /* Initial stack pointer address */
 
 struct smp_ops {
        void (*smp_prepare_boot_cpu)(void);
index 6c22bf3..725b778 100644 (file)
@@ -34,7 +34,7 @@ static inline void smpboot_restore_warm_reset_vector(void)
         */
        CMOS_WRITE(0, 0xf);
 
-       *((volatile long *)phys_to_virt(apic->trampoline_phys_low)) = 0;
+       *((volatile u32 *)phys_to_virt(apic->trampoline_phys_low)) = 0;
 }
 
 static inline void __init smpboot_setup_io_apic(void)
index 33ecc3e..12569e6 100644 (file)
@@ -98,8 +98,6 @@ do {                                                                  \
  */
 #define HAVE_DISABLE_HLT
 #else
-#define __SAVE(reg, offset) "movq %%" #reg ",(14-" #offset ")*8(%%rsp)\n\t"
-#define __RESTORE(reg, offset) "movq (14-" #offset ")*8(%%rsp),%%" #reg "\n\t"
 
 /* frame pointer must be last for get_wchan */
 #define SAVE_CONTEXT    "pushf ; pushq %%rbp ; movq %%rsi,%%rbp\n\t"
diff --git a/arch/x86/include/asm/system_64.h b/arch/x86/include/asm/system_64.h
deleted file mode 100644 (file)
index 1159e09..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef _ASM_X86_SYSTEM_64_H
-#define _ASM_X86_SYSTEM_64_H
-
-#include <asm/segment.h>
-#include <asm/cmpxchg.h>
-
-
-static inline unsigned long read_cr8(void)
-{
-       unsigned long cr8;
-       asm volatile("movq %%cr8,%0" : "=r" (cr8));
-       return cr8;
-}
-
-static inline void write_cr8(unsigned long val)
-{
-       asm volatile("movq %0,%%cr8" :: "r" (val) : "memory");
-}
-
-#include <linux/irqflags.h>
-
-#endif /* _ASM_X86_SYSTEM_64_H */
index 21899cc..910a708 100644 (file)
 
 #include <asm/mpspec.h>
 
-#ifdef CONFIG_X86_32
-
-/* Mappings between logical cpu number and node number */
-extern int cpu_to_node_map[];
-
-/* Returns the number of the node containing CPU 'cpu' */
-static inline int __cpu_to_node(int cpu)
-{
-       return cpu_to_node_map[cpu];
-}
-#define early_cpu_to_node __cpu_to_node
-#define cpu_to_node __cpu_to_node
-
-#else /* CONFIG_X86_64 */
-
 /* Mappings between logical cpu number and node number */
 DECLARE_EARLY_PER_CPU(int, x86_cpu_to_node_map);
 
@@ -84,8 +69,6 @@ static inline int early_cpu_to_node(int cpu)
 
 #endif /* !CONFIG_DEBUG_PER_CPU_MAPS */
 
-#endif /* CONFIG_X86_64 */
-
 /* Mappings between node number and cpus on that node. */
 extern cpumask_var_t node_to_cpumask_map[MAX_NUMNODES];
 
@@ -155,7 +138,7 @@ extern unsigned long node_remap_size[];
        .balance_interval       = 1,                                    \
 }
 
-#ifdef CONFIG_X86_64_ACPI_NUMA
+#ifdef CONFIG_X86_64
 extern int __node_distance(int, int);
 #define node_distance(a, b) __node_distance(a, b)
 #endif
index b766a5e..ffaf183 100644 (file)
 #define __NR_fanotify_init     338
 #define __NR_fanotify_mark     339
 #define __NR_prlimit64         340
+#define __NR_name_to_handle_at 341
+#define __NR_open_by_handle_at  342
+#define __NR_clock_adjtime     343
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 341
+#define NR_syscalls 344
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index 363e9b8..5466bea 100644 (file)
@@ -669,6 +669,12 @@ __SYSCALL(__NR_fanotify_init, sys_fanotify_init)
 __SYSCALL(__NR_fanotify_mark, sys_fanotify_mark)
 #define __NR_prlimit64                         302
 __SYSCALL(__NR_prlimit64, sys_prlimit64)
+#define __NR_name_to_handle_at                 303
+__SYSCALL(__NR_name_to_handle_at, sys_name_to_handle_at)
+#define __NR_open_by_handle_at                 304
+__SYSCALL(__NR_open_by_handle_at, sys_open_by_handle_at)
+#define __NR_clock_adjtime                     305
+__SYSCALL(__NR_clock_adjtime, sys_clock_adjtime)
 
 #ifndef __NO_STUBS
 #define __ARCH_WANT_OLD_READDIR
index ce1d54c..3e094af 100644 (file)
@@ -176,7 +176,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 (pnode<<1) of */
+       unsigned int base_dest_nodeid:15; /* nasid of the */
        /* bits 20:6 */                   /* first bit in uvhub map */
        unsigned int command:8; /* message type */
        /* bits 28:21 */
index 64642ad..643ebf2 100644 (file)
@@ -83,11 +83,13 @@ struct x86_init_paging {
  *                             boot cpu
  * @tsc_pre_init:              platform function called before TSC init
  * @timer_init:                        initialize the platform timer (default PIT/HPET)
+ * @wallclock_init:            init the wallclock device
  */
 struct x86_init_timers {
        void (*setup_percpu_clockev)(void);
        void (*tsc_pre_init)(void);
        void (*timer_init)(void);
+       void (*wallclock_init)(void);
 };
 
 /**
index a3c28ae..8508bfe 100644 (file)
@@ -287,7 +287,7 @@ HYPERVISOR_fpu_taskswitch(int set)
 static inline int
 HYPERVISOR_sched_op(int cmd, void *arg)
 {
-       return _hypercall2(int, sched_op_new, cmd, arg);
+       return _hypercall2(int, sched_op, cmd, arg);
 }
 
 static inline long
@@ -422,10 +422,17 @@ HYPERVISOR_set_segment_base(int reg, unsigned long value)
 #endif
 
 static inline int
-HYPERVISOR_suspend(unsigned long srec)
+HYPERVISOR_suspend(unsigned long start_info_mfn)
 {
-       return _hypercall3(int, sched_op, SCHEDOP_shutdown,
-                          SHUTDOWN_suspend, srec);
+       struct sched_shutdown r = { .reason = SHUTDOWN_suspend };
+
+       /*
+        * For a PV guest the tools require that the start_info mfn be
+        * present in rdx/edx when the hypercall is made. Per the
+        * hypercall calling convention this is the third hypercall
+        * argument, which is start_info_mfn here.
+        */
+       return _hypercall3(int, sched_op, SCHEDOP_shutdown, &r, start_info_mfn);
 }
 
 static inline int
index f25bdf2..c61934f 100644 (file)
@@ -29,8 +29,10 @@ typedef struct xpaddr {
 
 /**** MACHINE <-> PHYSICAL CONVERSION MACROS ****/
 #define INVALID_P2M_ENTRY      (~0UL)
-#define FOREIGN_FRAME_BIT      (1UL<<31)
+#define FOREIGN_FRAME_BIT      (1UL<<(BITS_PER_LONG-1))
+#define IDENTITY_FRAME_BIT     (1UL<<(BITS_PER_LONG-2))
 #define FOREIGN_FRAME(m)       ((m) | FOREIGN_FRAME_BIT)
+#define IDENTITY_FRAME(m)      ((m) | IDENTITY_FRAME_BIT)
 
 /* Maximum amount of memory we can handle in a domain in pages */
 #define MAX_DOMAIN_PAGES                                               \
@@ -41,12 +43,18 @@ extern unsigned int   machine_to_phys_order;
 
 extern unsigned long get_phys_to_machine(unsigned long pfn);
 extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn);
+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 struct page *m2p_find_override(unsigned long mfn);
 extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn);
 
+#ifdef CONFIG_XEN_DEBUG_FS
+extern int p2m_dump_show(struct seq_file *m, void *v);
+#endif
 static inline unsigned long pfn_to_mfn(unsigned long pfn)
 {
        unsigned long mfn;
@@ -57,7 +65,7 @@ static inline unsigned long pfn_to_mfn(unsigned long pfn)
        mfn = get_phys_to_machine(pfn);
 
        if (mfn != INVALID_P2M_ENTRY)
-               mfn &= ~FOREIGN_FRAME_BIT;
+               mfn &= ~(FOREIGN_FRAME_BIT | IDENTITY_FRAME_BIT);
 
        return mfn;
 }
@@ -73,25 +81,44 @@ static inline int phys_to_machine_mapping_valid(unsigned long pfn)
 static inline unsigned long mfn_to_pfn(unsigned long mfn)
 {
        unsigned long pfn;
+       int ret = 0;
 
        if (xen_feature(XENFEAT_auto_translated_physmap))
                return mfn;
 
+       if (unlikely((mfn >> machine_to_phys_order) != 0)) {
+               pfn = ~0;
+               goto try_override;
+       }
        pfn = 0;
        /*
         * The array access can fail (e.g., device space beyond end of RAM).
         * In such cases it doesn't matter what we return (we return garbage),
         * but we must handle the fault without crashing!
         */
-       __get_user(pfn, &machine_to_phys_mapping[mfn]);
-
-       /*
-        * If this appears to be a foreign mfn (because the pfn
-        * doesn't map back to the mfn), then check the local override
-        * table to see if there's a better pfn to use.
+       ret = __get_user(pfn, &machine_to_phys_mapping[mfn]);
+try_override:
+       /* ret might be < 0 if there are no entries in the m2p for mfn */
+       if (ret < 0)
+               pfn = ~0;
+       else if (get_phys_to_machine(pfn) != mfn)
+               /*
+                * If this appears to be a foreign mfn (because the pfn
+                * doesn't map back to the mfn), then check the local override
+                * table to see if there's a better pfn to use.
+                *
+                * m2p_find_override_pfn returns ~0 if it doesn't find anything.
+                */
+               pfn = m2p_find_override_pfn(mfn, ~0);
+
+       /* 
+        * pfn is ~0 if there are no entries in the m2p for mfn or if the
+        * entry doesn't map back to the mfn and m2p_override doesn't have a
+        * valid entry for it.
         */
-       if (get_phys_to_machine(pfn) != mfn)
-               pfn = m2p_find_override_pfn(mfn, pfn);
+       if (pfn == ~0 &&
+                       get_phys_to_machine(mfn) == IDENTITY_FRAME(mfn))
+               pfn = mfn;
 
        return pfn;
 }
index 2329b3e..aa86209 100644 (file)
@@ -27,16 +27,16 @@ static inline void __init xen_setup_pirqs(void)
  * its own functions.
  */
 struct xen_pci_frontend_ops {
-       int (*enable_msi)(struct pci_dev *dev, int **vectors);
+       int (*enable_msi)(struct pci_dev *dev, int vectors[]);
        void (*disable_msi)(struct pci_dev *dev);
-       int (*enable_msix)(struct pci_dev *dev, int **vectors, int nvec);
+       int (*enable_msix)(struct pci_dev *dev, int vectors[], int nvec);
        void (*disable_msix)(struct pci_dev *dev);
 };
 
 extern struct xen_pci_frontend_ops *xen_pci_frontend;
 
 static inline int xen_pci_frontend_enable_msi(struct pci_dev *dev,
-                                             int **vectors)
+                                             int vectors[])
 {
        if (xen_pci_frontend && xen_pci_frontend->enable_msi)
                return xen_pci_frontend->enable_msi(dev, vectors);
@@ -48,7 +48,7 @@ static inline void xen_pci_frontend_disable_msi(struct pci_dev *dev)
                        xen_pci_frontend->disable_msi(dev);
 }
 static inline int xen_pci_frontend_enable_msix(struct pci_dev *dev,
-                                              int **vectors, int nvec)
+                                              int vectors[], int nvec)
 {
        if (xen_pci_frontend && xen_pci_frontend->enable_msix)
                return xen_pci_frontend->enable_msix(dev, vectors, nvec);
index 34244b2..62445ba 100644 (file)
@@ -66,9 +66,9 @@ obj-$(CONFIG_PCI)             += early-quirks.o
 apm-y                          := apm_32.o
 obj-$(CONFIG_APM)              += apm.o
 obj-$(CONFIG_SMP)              += smp.o
-obj-$(CONFIG_SMP)              += smpboot.o tsc_sync.o
+obj-$(CONFIG_SMP)              += smpboot.o
+obj-$(CONFIG_SMP)              += tsc_sync.o
 obj-$(CONFIG_SMP)              += setup_percpu.o
-obj-$(CONFIG_X86_64_SMP)       += tsc_sync.o
 obj-$(CONFIG_X86_TRAMPOLINE)   += trampoline_$(BITS).o
 obj-$(CONFIG_X86_MPPARSE)      += mpparse.o
 obj-y                          += apic/
@@ -109,6 +109,7 @@ obj-$(CONFIG_MICROCODE)                     += microcode.o
 obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o
 
 obj-$(CONFIG_SWIOTLB)                  += pci-swiotlb.o
+obj-$(CONFIG_OF)                       += devicetree.o
 
 ###
 # 64 bit specific files
index b3a7113..9a966c5 100644 (file)
@@ -72,6 +72,7 @@ u8 acpi_sci_flags __initdata;
 int acpi_sci_override_gsi __initdata;
 int acpi_skip_timer_override __initdata;
 int acpi_use_timer_override __initdata;
+int acpi_fix_pin2_polarity __initdata;
 
 #ifdef CONFIG_X86_LOCAL_APIC
 static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
@@ -415,10 +416,15 @@ acpi_parse_int_src_ovr(struct acpi_subtable_header * header,
                return 0;
        }
 
-       if (acpi_skip_timer_override &&
-           intsrc->source_irq == 0 && intsrc->global_irq == 2) {
-               printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n");
-               return 0;
+       if (intsrc->source_irq == 0 && intsrc->global_irq == 2) {
+               if (acpi_skip_timer_override) {
+                       printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n");
+                       return 0;
+               }
+               if (acpi_fix_pin2_polarity && (intsrc->inti_flags & ACPI_MADT_POLARITY_MASK)) {
+                       intsrc->inti_flags &= ~ACPI_MADT_POLARITY_MASK;
+                       printk(PREFIX "BIOS IRQ0 pin2 override: forcing polarity to high active.\n");
+               }
        }
 
        mp_override_legacy_irq(intsrc->source_irq,
@@ -589,14 +595,8 @@ static void acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
        nid = acpi_get_node(handle);
        if (nid == -1 || !node_online(nid))
                return;
-#ifdef CONFIG_X86_64
-       apicid_to_node[physid] = nid;
+       set_apicid_to_node(physid, nid);
        numa_set_node(cpu, nid);
-#else /* CONFIG_X86_32 */
-       apicid_2_node[physid] = nid;
-       cpu_to_node_map[cpu] = nid;
-#endif
-
 #endif
 }
 
index 69fd72a..68d1537 100644 (file)
 #include <linux/cpumask.h>
 #include <asm/segment.h>
 #include <asm/desc.h>
-
-#ifdef CONFIG_X86_32
 #include <asm/pgtable.h>
-#endif
+#include <asm/cacheflush.h>
 
 #include "realmode/wakeup.h"
 #include "sleep.h"
@@ -100,7 +98,7 @@ int acpi_save_state_mem(void)
 #else /* CONFIG_64BIT */
        header->trampoline_segment = setup_trampoline() >> 4;
 #ifdef CONFIG_SMP
-       stack_start.sp = temp_stack + sizeof(temp_stack);
+       stack_start = (unsigned long)temp_stack + sizeof(temp_stack);
        early_gdt_descr.address =
                        (unsigned long)get_cpu_gdt_table(smp_processor_id());
        initial_gs = per_cpu_offset(smp_processor_id());
@@ -149,6 +147,15 @@ void __init acpi_reserve_wakeup_memory(void)
        memblock_x86_reserve_range(mem, mem + WAKEUP_SIZE, "ACPI WAKEUP");
 }
 
+int __init acpi_configure_wakeup_memory(void)
+{
+       if (acpi_realmode)
+               set_memory_x(acpi_realmode, WAKEUP_SIZE >> PAGE_SHIFT);
+
+       return 0;
+}
+arch_initcall(acpi_configure_wakeup_memory);
+
 
 static int __init acpi_sleep_setup(char *str)
 {
index 1236085..7038b95 100644 (file)
@@ -671,7 +671,7 @@ void __kprobes text_poke_smp_batch(struct text_poke_param *params, int n)
 
        atomic_set(&stop_machine_first, 1);
        wrote_text = 0;
-       stop_machine(stop_machine_text_poke, (void *)&tpp, NULL);
+       __stop_machine(stop_machine_text_poke, (void *)&tpp, NULL);
 }
 
 #if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL)
index 0a99f71..ed3c2e5 100644 (file)
@@ -12,7 +12,7 @@
 
 static u32 *flush_words;
 
-struct pci_device_id amd_nb_misc_ids[] = {
+const struct pci_device_id amd_nb_misc_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_MISC) },
@@ -20,6 +20,11 @@ struct pci_device_id amd_nb_misc_ids[] = {
 };
 EXPORT_SYMBOL(amd_nb_misc_ids);
 
+static struct pci_device_id amd_nb_link_ids[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_LINK) },
+       {}
+};
+
 const struct amd_nb_bus_dev_range amd_nb_bus_dev_ranges[] __initconst = {
        { 0x00, 0x18, 0x20 },
        { 0xff, 0x00, 0x20 },
@@ -31,7 +36,7 @@ struct amd_northbridge_info amd_northbridges;
 EXPORT_SYMBOL(amd_northbridges);
 
 static struct pci_dev *next_northbridge(struct pci_dev *dev,
-                                       struct pci_device_id *ids)
+                                       const struct pci_device_id *ids)
 {
        do {
                dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
@@ -45,7 +50,7 @@ int amd_cache_northbridges(void)
 {
        int i = 0;
        struct amd_northbridge *nb;
-       struct pci_dev *misc;
+       struct pci_dev *misc, *link;
 
        if (amd_nb_num())
                return 0;
@@ -64,10 +69,12 @@ int amd_cache_northbridges(void)
        amd_northbridges.nb = nb;
        amd_northbridges.num = i;
 
-       misc = NULL;
+       link = misc = NULL;
        for (i = 0; i != amd_nb_num(); i++) {
                node_to_amd_nb(i)->misc = misc =
                        next_northbridge(misc, amd_nb_misc_ids);
+               node_to_amd_nb(i)->link = link =
+                       next_northbridge(link, amd_nb_link_ids);
         }
 
        /* some CPU families (e.g. family 0x11) do not support GART */
@@ -85,6 +92,13 @@ int amd_cache_northbridges(void)
             boot_cpu_data.x86_mask >= 0x1))
                amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
 
+       if (boot_cpu_data.x86 == 0x15)
+               amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
+
+       /* L3 cache partitioning is supported on family 0x15 */
+       if (boot_cpu_data.x86 == 0x15)
+               amd_northbridges.flags |= AMD_NB_L3_PARTITIONING;
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(amd_cache_northbridges);
@@ -93,8 +107,9 @@ EXPORT_SYMBOL_GPL(amd_cache_northbridges);
    they're useless anyways */
 int __init early_is_amd_nb(u32 device)
 {
-       struct pci_device_id *id;
+       const struct pci_device_id *id;
        u32 vendor = device & 0xffff;
+
        device >>= 16;
        for (id = amd_nb_misc_ids; id->vendor; id++)
                if (vendor == id->vendor && device == id->device)
@@ -102,6 +117,65 @@ int __init early_is_amd_nb(u32 device)
        return 0;
 }
 
+int amd_get_subcaches(int cpu)
+{
+       struct pci_dev *link = node_to_amd_nb(amd_get_nb_id(cpu))->link;
+       unsigned int mask;
+       int cuid = 0;
+
+       if (!amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
+               return 0;
+
+       pci_read_config_dword(link, 0x1d4, &mask);
+
+#ifdef CONFIG_SMP
+       cuid = cpu_data(cpu).compute_unit_id;
+#endif
+       return (mask >> (4 * cuid)) & 0xf;
+}
+
+int amd_set_subcaches(int cpu, int mask)
+{
+       static unsigned int reset, ban;
+       struct amd_northbridge *nb = node_to_amd_nb(amd_get_nb_id(cpu));
+       unsigned int reg;
+       int cuid = 0;
+
+       if (!amd_nb_has_feature(AMD_NB_L3_PARTITIONING) || mask > 0xf)
+               return -EINVAL;
+
+       /* if necessary, collect reset state of L3 partitioning and BAN mode */
+       if (reset == 0) {
+               pci_read_config_dword(nb->link, 0x1d4, &reset);
+               pci_read_config_dword(nb->misc, 0x1b8, &ban);
+               ban &= 0x180000;
+       }
+
+       /* deactivate BAN mode if any subcaches are to be disabled */
+       if (mask != 0xf) {
+               pci_read_config_dword(nb->misc, 0x1b8, &reg);
+               pci_write_config_dword(nb->misc, 0x1b8, reg & ~0x180000);
+       }
+
+#ifdef CONFIG_SMP
+       cuid = cpu_data(cpu).compute_unit_id;
+#endif
+       mask <<= 4 * cuid;
+       mask |= (0xf ^ (1 << cuid)) << 26;
+
+       pci_write_config_dword(nb->link, 0x1d4, mask);
+
+       /* reset BAN mode if L3 partitioning returned to reset state */
+       pci_read_config_dword(nb->link, 0x1d4, &reg);
+       if (reg == reset) {
+               pci_read_config_dword(nb->misc, 0x1b8, &reg);
+               reg &= ~0x180000;
+               pci_write_config_dword(nb->misc, 0x1b8, reg | ban);
+       }
+
+       return 0;
+}
+
 int amd_cache_gart(void)
 {
        int i;
index 51ef31a..1293c70 100644 (file)
@@ -284,7 +284,7 @@ static int __init apbt_clockevent_register(void)
        memcpy(&adev->evt, &apbt_clockevent, sizeof(struct clock_event_device));
 
        if (mrst_timer_options == MRST_TIMER_LAPIC_APBT) {
-               apbt_clockevent.rating = APBT_CLOCKEVENT_RATING - 100;
+               adev->evt.rating = APBT_CLOCKEVENT_RATING - 100;
                global_clock_event = &adev->evt;
                printk(KERN_DEBUG "%s clockevent registered as global\n",
                       global_clock_event->name);
@@ -508,64 +508,12 @@ static int apbt_next_event(unsigned long delta,
        return 0;
 }
 
-/*
- * APB timer clock is not in sync with pclk on Langwell, which translates to
- * unreliable read value caused by sampling error. the error does not add up
- * overtime and only happens when sampling a 0 as a 1 by mistake. so the time
- * would go backwards. the following code is trying to prevent time traveling
- * backwards. little bit paranoid.
- */
 static cycle_t apbt_read_clocksource(struct clocksource *cs)
 {
-       unsigned long t0, t1, t2;
-       static unsigned long last_read;
-
-bad_count:
-       t1 = apbt_readl(phy_cs_timer_id,
-                       APBTMR_N_CURRENT_VALUE);
-       t2 = apbt_readl(phy_cs_timer_id,
-                       APBTMR_N_CURRENT_VALUE);
-       if (unlikely(t1 < t2)) {
-               pr_debug("APBT: read current count error %lx:%lx:%lx\n",
-                        t1, t2, t2 - t1);
-               goto bad_count;
-       }
-       /*
-        * check against cached last read, makes sure time does not go back.
-        * it could be a normal rollover but we will do tripple check anyway
-        */
-       if (unlikely(t2 > last_read)) {
-               /* check if we have a normal rollover */
-               unsigned long raw_intr_status =
-                       apbt_readl_reg(APBTMRS_RAW_INT_STATUS);
-               /*
-                * cs timer interrupt is masked but raw intr bit is set if
-                * rollover occurs. then we read EOI reg to clear it.
-                */
-               if (raw_intr_status & (1 << phy_cs_timer_id)) {
-                       apbt_readl(phy_cs_timer_id, APBTMR_N_EOI);
-                       goto out;
-               }
-               pr_debug("APB CS going back %lx:%lx:%lx ",
-                        t2, last_read, t2 - last_read);
-bad_count_x3:
-               pr_debug("triple check enforced\n");
-               t0 = apbt_readl(phy_cs_timer_id,
-                               APBTMR_N_CURRENT_VALUE);
-               udelay(1);
-               t1 = apbt_readl(phy_cs_timer_id,
-                               APBTMR_N_CURRENT_VALUE);
-               udelay(1);
-               t2 = apbt_readl(phy_cs_timer_id,
-                               APBTMR_N_CURRENT_VALUE);
-               if ((t2 > t1) || (t1 > t0)) {
-                       printk(KERN_ERR "Error: APB CS tripple check failed\n");
-                       goto bad_count_x3;
-               }
-       }
-out:
-       last_read = t2;
-       return (cycle_t)~t2;
+       unsigned long current_count;
+
+       current_count = apbt_readl(phy_cs_timer_id, APBTMR_N_CURRENT_VALUE);
+       return (cycle_t)~current_count;
 }
 
 static int apbt_clocksource_register(void)
index 5955a78..7b1e8e1 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/init.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/mmzone.h>
 #include <linux/pci_ids.h>
 #include <linux/pci.h>
@@ -57,7 +57,7 @@ static void __init insert_aperture_resource(u32 aper_base, u32 aper_size)
 static u32 __init allocate_aperture(void)
 {
        u32 aper_size;
-       void *p;
+       unsigned long addr;
 
        /* aper_size should <= 1G */
        if (fallback_aper_order > 5)
@@ -83,27 +83,26 @@ static u32 __init allocate_aperture(void)
         * so don't use 512M below as gart iommu, leave the space for kernel
         * code for safe
         */
-       p = __alloc_bootmem_nopanic(aper_size, aper_size, 512ULL<<20);
+       addr = memblock_find_in_range(0, 1ULL<<32, aper_size, 512ULL<<20);
+       if (addr == MEMBLOCK_ERROR || addr + aper_size > 0xffffffff) {
+               printk(KERN_ERR
+                       "Cannot allocate aperture memory hole (%lx,%uK)\n",
+                               addr, aper_size>>10);
+               return 0;
+       }
+       memblock_x86_reserve_range(addr, addr + aper_size, "aperture64");
        /*
         * Kmemleak should not scan this block as it may not be mapped via the
         * kernel direct mapping.
         */
-       kmemleak_ignore(p);
-       if (!p || __pa(p)+aper_size > 0xffffffff) {
-               printk(KERN_ERR
-                       "Cannot allocate aperture memory hole (%p,%uK)\n",
-                               p, aper_size>>10);
-               if (p)
-                       free_bootmem(__pa(p), aper_size);
-               return 0;
-       }
+       kmemleak_ignore(phys_to_virt(addr));
        printk(KERN_INFO "Mapping aperture over %d KB of RAM @ %lx\n",
-                       aper_size >> 10, __pa(p));
-       insert_aperture_resource((u32)__pa(p), aper_size);
-       register_nosave_region((u32)__pa(p) >> PAGE_SHIFT,
-                               (u32)__pa(p+aper_size) >> PAGE_SHIFT);
+                       aper_size >> 10, addr);
+       insert_aperture_resource((u32)addr, aper_size);
+       register_nosave_region(addr >> PAGE_SHIFT,
+                              (addr+aper_size) >> PAGE_SHIFT);
 
-       return (u32)__pa(p);
+       return (u32)addr;
 }
 
 
index 06c196d..966673f 100644 (file)
@@ -43,6 +43,7 @@
 #include <asm/i8259.h>
 #include <asm/proto.h>
 #include <asm/apic.h>
+#include <asm/io_apic.h>
 #include <asm/desc.h>
 #include <asm/hpet.h>
 #include <asm/idle.h>
@@ -78,12 +79,21 @@ EXPORT_EARLY_PER_CPU_SYMBOL(x86_cpu_to_apicid);
 EXPORT_EARLY_PER_CPU_SYMBOL(x86_bios_cpu_apicid);
 
 #ifdef CONFIG_X86_32
+
+/*
+ * On x86_32, the mapping between cpu and logical apicid may vary
+ * depending on apic in use.  The following early percpu variable is
+ * used for the mapping.  This is where the behaviors of x86_64 and 32
+ * actually diverge.  Let's keep it ugly for now.
+ */
+DEFINE_EARLY_PER_CPU(int, x86_cpu_to_logical_apicid, BAD_APICID);
+
 /*
  * Knob to control our willingness to enable the local APIC.
  *
  * +1=force-enable
  */
-static int force_enable_local_apic;
+static int force_enable_local_apic __initdata;
 /*
  * APIC command line parameters
  */
@@ -153,7 +163,7 @@ early_param("nox2apic", setup_nox2apic);
 unsigned long mp_lapic_addr;
 int disable_apic;
 /* Disable local APIC timer from the kernel commandline or via dmi quirk */
-static int disable_apic_timer __cpuinitdata;
+static int disable_apic_timer __initdata;
 /* Local APIC timer works in C2 */
 int local_apic_timer_c2_ok;
 EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok);
@@ -177,29 +187,8 @@ static struct resource lapic_resource = {
 
 static unsigned int calibration_result;
 
-static int lapic_next_event(unsigned long delta,
-                           struct clock_event_device *evt);
-static void lapic_timer_setup(enum clock_event_mode mode,
-                             struct clock_event_device *evt);
-static void lapic_timer_broadcast(const struct cpumask *mask);
 static void apic_pm_activate(void);
 
-/*
- * The local apic timer can be used for any function which is CPU local.
- */
-static struct clock_event_device lapic_clockevent = {
-       .name           = "lapic",
-       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT
-                       | CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY,
-       .shift          = 32,
-       .set_mode       = lapic_timer_setup,
-       .set_next_event = lapic_next_event,
-       .broadcast      = lapic_timer_broadcast,
-       .rating         = 100,
-       .irq            = -1,
-};
-static DEFINE_PER_CPU(struct clock_event_device, lapic_events);
-
 static unsigned long apic_phys;
 
 /*
@@ -238,7 +227,7 @@ static int modern_apic(void)
  * right after this call apic become NOOP driven
  * so apic->write/read doesn't do anything
  */
-void apic_disable(void)
+static void __init apic_disable(void)
 {
        pr_info("APIC: switched to apic NOOP\n");
        apic = &apic_noop;
@@ -282,23 +271,6 @@ u64 native_apic_icr_read(void)
        return icr1 | ((u64)icr2 << 32);
 }
 
-/**
- * enable_NMI_through_LVT0 - enable NMI through local vector table 0
- */
-void __cpuinit enable_NMI_through_LVT0(void)
-{
-       unsigned int v;
-
-       /* unmask and set to NMI */
-       v = APIC_DM_NMI;
-
-       /* Level triggered for 82489DX (32bit mode) */
-       if (!lapic_is_integrated())
-               v |= APIC_LVT_LEVEL_TRIGGER;
-
-       apic_write(APIC_LVT0, v);
-}
-
 #ifdef CONFIG_X86_32
 /**
  * get_physical_broadcast - Get number of physical broadcast IDs
@@ -508,6 +480,23 @@ static void lapic_timer_broadcast(const struct cpumask *mask)
 #endif
 }
 
+
+/*
+ * The local apic timer can be used for any function which is CPU local.
+ */
+static struct clock_event_device lapic_clockevent = {
+       .name           = "lapic",
+       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT
+                       | CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY,
+       .shift          = 32,
+       .set_mode       = lapic_timer_setup,
+       .set_next_event = lapic_next_event,
+       .broadcast      = lapic_timer_broadcast,
+       .rating         = 100,
+       .irq            = -1,
+};
+static DEFINE_PER_CPU(struct clock_event_device, lapic_events);
+
 /*
  * Setup the local APIC timer for this CPU. Copy the initialized values
  * of the boot CPU and register the clock event in the framework.
@@ -1209,7 +1198,7 @@ void __cpuinit setup_local_APIC(void)
                rdtscll(tsc);
 
        if (disable_apic) {
-               arch_disable_smp_support();
+               disable_ioapic_support();
                return;
        }
 
@@ -1237,6 +1226,19 @@ void __cpuinit setup_local_APIC(void)
         */
        apic->init_apic_ldr();
 
+#ifdef CONFIG_X86_32
+       /*
+        * APIC LDR is initialized.  If logical_apicid mapping was
+        * initialized during get_smp_config(), make sure it matches the
+        * actual value.
+        */
+       i = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
+       WARN_ON(i != BAD_APICID && i != logical_smp_processor_id());
+       /* always use the value from LDR */
+       early_per_cpu(x86_cpu_to_logical_apicid, cpu) =
+               logical_smp_processor_id();
+#endif
+
        /*
         * Set Task Priority to 'accept all'. We never change this
         * later on.
@@ -1381,12 +1383,17 @@ void __cpuinit end_local_APIC_setup(void)
 #endif
 
        apic_pm_activate();
+}
+
+void __init bsp_end_local_APIC_setup(void)
+{
+       end_local_APIC_setup();
 
        /*
         * Now that local APIC setup is completed for BP, configure the fault
         * handling for interrupt remapping.
         */
-       if (!smp_processor_id() && intr_remapping_enabled)
+       if (intr_remapping_enabled)
                enable_drhd_fault_handling();
 
 }
@@ -1443,7 +1450,7 @@ int __init enable_IR(void)
 void __init enable_IR_x2apic(void)
 {
        unsigned long flags;
-       struct IO_APIC_route_entry **ioapic_entries = NULL;
+       struct IO_APIC_route_entry **ioapic_entries;
        int ret, x2apic_enabled = 0;
        int dmar_table_init_ret;
 
@@ -1532,7 +1539,7 @@ static int __init detect_init_APIC(void)
 }
 #else
 
-static int apic_verify(void)
+static int __init apic_verify(void)
 {
        u32 features, h, l;
 
@@ -1557,7 +1564,7 @@ static int apic_verify(void)
        return 0;
 }
 
-int apic_force_enable(void)
+int __init apic_force_enable(unsigned long addr)
 {
        u32 h, l;
 
@@ -1573,7 +1580,7 @@ int apic_force_enable(void)
        if (!(l & MSR_IA32_APICBASE_ENABLE)) {
                pr_info("Local APIC disabled by BIOS -- reenabling.\n");
                l &= ~MSR_IA32_APICBASE_BASE;
-               l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
+               l |= MSR_IA32_APICBASE_ENABLE | addr;
                wrmsr(MSR_IA32_APICBASE, l, h);
                enabled_via_apicbase = 1;
        }
@@ -1614,7 +1621,7 @@ static int __init detect_init_APIC(void)
                                "you can enable it with \"lapic\"\n");
                        return -1;
                }
-               if (apic_force_enable())
+               if (apic_force_enable(APIC_DEFAULT_PHYS_BASE))
                        return -1;
        } else {
                if (apic_verify())
@@ -1756,7 +1763,7 @@ int __init APIC_init_uniprocessor(void)
                enable_IO_APIC();
 #endif
 
-       end_local_APIC_setup();
+       bsp_end_local_APIC_setup();
 
 #ifdef CONFIG_X86_IO_APIC
        if (smp_found_config && !skip_ioapic_setup && nr_ioapics)
@@ -1925,17 +1932,6 @@ void __cpuinit generic_processor_info(int apicid, int version)
 {
        int cpu;
 
-       /*
-        * Validate version
-        */
-       if (version == 0x0) {
-               pr_warning("BIOS bug, APIC version is 0 for CPU#%d! "
-                          "fixing up to 0x10. (tell your hw vendor)\n",
-                               version);
-               version = 0x10;
-       }
-       apic_version[apicid] = version;
-
        if (num_processors >= nr_cpu_ids) {
                int max = nr_cpu_ids;
                int thiscpu = max + disabled_cpus;
@@ -1949,22 +1945,34 @@ void __cpuinit generic_processor_info(int apicid, int version)
        }
 
        num_processors++;
-       cpu = cpumask_next_zero(-1, cpu_present_mask);
-
-       if (version != apic_version[boot_cpu_physical_apicid])
-               WARN_ONCE(1,
-                       "ACPI: apic version mismatch, bootcpu: %x cpu %d: %x\n",
-                       apic_version[boot_cpu_physical_apicid], cpu, version);
-
-       physid_set(apicid, phys_cpu_present_map);
        if (apicid == boot_cpu_physical_apicid) {
                /*
                 * x86_bios_cpu_apicid is required to have processors listed
                 * in same order as logical cpu numbers. Hence the first
                 * entry is BSP, and so on.
+                * boot_cpu_init() already hold bit 0 in cpu_present_mask
+                * for BSP.
                 */
                cpu = 0;
+       } else
+               cpu = cpumask_next_zero(-1, cpu_present_mask);
+
+       /*
+        * Validate version
+        */
+       if (version == 0x0) {
+               pr_warning("BIOS bug: APIC version is 0 for CPU %d/0x%x, fixing up to 0x10\n",
+                          cpu, apicid);
+               version = 0x10;
        }
+       apic_version[apicid] = version;
+
+       if (version != apic_version[boot_cpu_physical_apicid]) {
+               pr_warning("BIOS bug: APIC version mismatch, boot CPU: %x, CPU %d: version %x\n",
+                       apic_version[boot_cpu_physical_apicid], cpu, version);
+       }
+
+       physid_set(apicid, phys_cpu_present_map);
        if (apicid > max_physical_apicid)
                max_physical_apicid = apicid;
 
@@ -1972,7 +1980,10 @@ void __cpuinit generic_processor_info(int apicid, int version)
        early_per_cpu(x86_cpu_to_apicid, cpu) = apicid;
        early_per_cpu(x86_bios_cpu_apicid, cpu) = apicid;
 #endif
-
+#ifdef CONFIG_X86_32
+       early_per_cpu(x86_cpu_to_logical_apicid, cpu) =
+               apic->x86_32_early_logical_apicid(cpu);
+#endif
        set_cpu_possible(cpu, true);
        set_cpu_present(cpu, true);
 }
@@ -1993,10 +2004,14 @@ void default_init_apic_ldr(void)
 }
 
 #ifdef CONFIG_X86_32
-int default_apicid_to_node(int logical_apicid)
+int default_x86_32_numa_cpu_node(int cpu)
 {
-#ifdef CONFIG_SMP
-       return apicid_2_node[hard_smp_processor_id()];
+#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
index 09d3b17..5652d31 100644 (file)
@@ -185,8 +185,6 @@ struct apic apic_flat =  {
        .ioapic_phys_id_map             = NULL,
        .setup_apic_routing             = NULL,
        .multi_timer_check              = NULL,
-       .apicid_to_node                 = NULL,
-       .cpu_to_logical_apicid          = NULL,
        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
        .apicid_to_cpu_present          = NULL,
        .setup_portio_remap             = NULL,
@@ -337,8 +335,6 @@ struct apic apic_physflat =  {
        .ioapic_phys_id_map             = NULL,
        .setup_apic_routing             = NULL,
        .multi_timer_check              = NULL,
-       .apicid_to_node                 = NULL,
-       .cpu_to_logical_apicid          = NULL,
        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
        .apicid_to_cpu_present          = NULL,
        .setup_portio_remap             = NULL,
index e31b9ff..f1baa2d 100644 (file)
@@ -54,11 +54,6 @@ static u64 noop_apic_icr_read(void)
        return 0;
 }
 
-static int noop_cpu_to_logical_apicid(int cpu)
-{
-       return 0;
-}
-
 static int noop_phys_pkg_id(int cpuid_apic, int index_msb)
 {
        return 0;
@@ -113,12 +108,6 @@ static void noop_vector_allocation_domain(int cpu, struct cpumask *retmask)
        cpumask_set_cpu(cpu, retmask);
 }
 
-int noop_apicid_to_node(int logical_apicid)
-{
-       /* we're always on node 0 */
-       return 0;
-}
-
 static u32 noop_apic_read(u32 reg)
 {
        WARN_ON_ONCE((cpu_has_apic && !disable_apic));
@@ -130,6 +119,14 @@ 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,
@@ -153,9 +150,7 @@ struct apic apic_noop = {
        .ioapic_phys_id_map             = default_ioapic_phys_id_map,
        .setup_apic_routing             = NULL,
        .multi_timer_check              = NULL,
-       .apicid_to_node                 = noop_apicid_to_node,
 
-       .cpu_to_logical_apicid          = noop_cpu_to_logical_apicid,
        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
        .apicid_to_cpu_present          = physid_set_mask_of_physid,
 
@@ -197,4 +192,9 @@ struct apic apic_noop = {
        .icr_write                      = noop_apic_icr_write,
        .wait_icr_idle                  = noop_apic_wait_icr_idle,
        .safe_wait_icr_idle             = noop_safe_apic_wait_icr_idle,
+
+#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 cb804c5..541a2e4 100644 (file)
@@ -45,6 +45,12 @@ static unsigned long bigsmp_check_apicid_present(int bit)
        return 1;
 }
 
+static int bigsmp_early_logical_apicid(int cpu)
+{
+       /* on bigsmp, logical apicid is the same as physical */
+       return early_per_cpu(x86_cpu_to_apicid, cpu);
+}
+
 static inline unsigned long calculate_ldr(int cpu)
 {
        unsigned long val, id;
@@ -80,11 +86,6 @@ static void bigsmp_setup_apic_routing(void)
                nr_ioapics);
 }
 
-static int bigsmp_apicid_to_node(int logical_apicid)
-{
-       return apicid_2_node[hard_smp_processor_id()];
-}
-
 static int bigsmp_cpu_present_to_apicid(int mps_cpu)
 {
        if (mps_cpu < nr_cpu_ids)
@@ -93,14 +94,6 @@ static int bigsmp_cpu_present_to_apicid(int mps_cpu)
        return BAD_APICID;
 }
 
-/* Mapping from cpu number to logical apicid */
-static inline int bigsmp_cpu_to_logical_apicid(int cpu)
-{
-       if (cpu >= nr_cpu_ids)
-               return BAD_APICID;
-       return cpu_physical_id(cpu);
-}
-
 static void bigsmp_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap)
 {
        /* For clustered we don't have a good way to do this yet - hack */
@@ -115,7 +108,11 @@ static int bigsmp_check_phys_apicid_present(int phys_apicid)
 /* As we are using single CPU as destination, pick only one CPU here */
 static unsigned int bigsmp_cpu_mask_to_apicid(const struct cpumask *cpumask)
 {
-       return bigsmp_cpu_to_logical_apicid(cpumask_first(cpumask));
+       int cpu = cpumask_first(cpumask);
+
+       if (cpu < nr_cpu_ids)
+               return cpu_physical_id(cpu);
+       return BAD_APICID;
 }
 
 static unsigned int bigsmp_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
@@ -129,9 +126,9 @@ static unsigned int bigsmp_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
         */
        for_each_cpu_and(cpu, cpumask, andmask) {
                if (cpumask_test_cpu(cpu, cpu_online_mask))
-                       break;
+                       return cpu_physical_id(cpu);
        }
-       return bigsmp_cpu_to_logical_apicid(cpu);
+       return BAD_APICID;
 }
 
 static int bigsmp_phys_pkg_id(int cpuid_apic, int index_msb)
@@ -219,8 +216,6 @@ struct apic apic_bigsmp = {
        .ioapic_phys_id_map             = bigsmp_ioapic_phys_id_map,
        .setup_apic_routing             = bigsmp_setup_apic_routing,
        .multi_timer_check              = NULL,
-       .apicid_to_node                 = bigsmp_apicid_to_node,
-       .cpu_to_logical_apicid          = bigsmp_cpu_to_logical_apicid,
        .cpu_present_to_apicid          = bigsmp_cpu_present_to_apicid,
        .apicid_to_cpu_present          = physid_set_mask_of_physid,
        .setup_portio_remap             = NULL,
@@ -256,4 +251,7 @@ struct apic apic_bigsmp = {
        .icr_write                      = native_apic_icr_write,
        .wait_icr_idle                  = native_apic_wait_icr_idle,
        .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 8593582..3e9de48 100644 (file)
@@ -460,6 +460,12 @@ static unsigned long es7000_check_apicid_present(int bit)
        return physid_isset(bit, phys_cpu_present_map);
 }
 
+static int es7000_early_logical_apicid(int cpu)
+{
+       /* on es7000, logical apicid is the same as physical */
+       return early_per_cpu(x86_bios_cpu_apicid, cpu);
+}
+
 static unsigned long calculate_ldr(int cpu)
 {
        unsigned long id = per_cpu(x86_bios_cpu_apicid, cpu);
@@ -504,12 +510,11 @@ static void es7000_setup_apic_routing(void)
                nr_ioapics, cpumask_bits(es7000_target_cpus())[0]);
 }
 
-static int es7000_apicid_to_node(int logical_apicid)
+static int es7000_numa_cpu_node(int cpu)
 {
        return 0;
 }
 
-
 static int es7000_cpu_present_to_apicid(int mps_cpu)
 {
        if (!mps_cpu)
@@ -528,18 +533,6 @@ static void es7000_apicid_to_cpu_present(int phys_apicid, physid_mask_t *retmap)
        ++cpu_id;
 }
 
-/* Mapping from cpu number to logical apicid */
-static int es7000_cpu_to_logical_apicid(int cpu)
-{
-#ifdef CONFIG_SMP
-       if (cpu >= nr_cpu_ids)
-               return BAD_APICID;
-       return cpu_2_logical_apicid[cpu];
-#else
-       return logical_smp_processor_id();
-#endif
-}
-
 static void es7000_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap)
 {
        /* For clustered we don't have a good way to do this yet - hack */
@@ -561,7 +554,7 @@ static unsigned int es7000_cpu_mask_to_apicid(const struct cpumask *cpumask)
         * The cpus in the mask must all be on the apic cluster.
         */
        for_each_cpu(cpu, cpumask) {
-               int new_apicid = es7000_cpu_to_logical_apicid(cpu);
+               int new_apicid = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
 
                if (round && APIC_CLUSTER(apicid) != APIC_CLUSTER(new_apicid)) {
                        WARN(1, "Not a valid mask!");
@@ -578,7 +571,7 @@ static unsigned int
 es7000_cpu_mask_to_apicid_and(const struct cpumask *inmask,
                              const struct cpumask *andmask)
 {
-       int apicid = es7000_cpu_to_logical_apicid(0);
+       int apicid = early_per_cpu(x86_cpu_to_logical_apicid, 0);
        cpumask_var_t cpumask;
 
        if (!alloc_cpumask_var(&cpumask, GFP_ATOMIC))
@@ -655,8 +648,6 @@ struct apic __refdata apic_es7000_cluster = {
        .ioapic_phys_id_map             = es7000_ioapic_phys_id_map,
        .setup_apic_routing             = es7000_setup_apic_routing,
        .multi_timer_check              = NULL,
-       .apicid_to_node                 = es7000_apicid_to_node,
-       .cpu_to_logical_apicid          = es7000_cpu_to_logical_apicid,
        .cpu_present_to_apicid          = es7000_cpu_present_to_apicid,
        .apicid_to_cpu_present          = es7000_apicid_to_cpu_present,
        .setup_portio_remap             = NULL,
@@ -695,6 +686,9 @@ struct apic __refdata apic_es7000_cluster = {
        .icr_write                      = native_apic_icr_write,
        .wait_icr_idle                  = native_apic_wait_icr_idle,
        .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 = {
@@ -720,8 +714,6 @@ struct apic __refdata apic_es7000 = {
        .ioapic_phys_id_map             = es7000_ioapic_phys_id_map,
        .setup_apic_routing             = es7000_setup_apic_routing,
        .multi_timer_check              = NULL,
-       .apicid_to_node                 = es7000_apicid_to_node,
-       .cpu_to_logical_apicid          = es7000_cpu_to_logical_apicid,
        .cpu_present_to_apicid          = es7000_cpu_present_to_apicid,
        .apicid_to_cpu_present          = es7000_apicid_to_cpu_present,
        .setup_portio_remap             = NULL,
@@ -758,4 +750,7 @@ struct apic __refdata apic_es7000 = {
        .icr_write                      = native_apic_icr_write,
        .wait_icr_idle                  = native_apic_wait_icr_idle,
        .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 79fd43c..c4e557a 100644 (file)
@@ -83,7 +83,6 @@ arch_trigger_all_cpu_backtrace_handler(struct notifier_block *self,
                arch_spin_lock(&lock);
                printk(KERN_WARNING "NMI backtrace for cpu %d\n", cpu);
                show_regs(regs);
-               dump_stack();
                arch_spin_unlock(&lock);
                cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
                return NOTIFY_STOP;
index 697dc34..4b5ebd2 100644 (file)
@@ -108,7 +108,10 @@ DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES);
 
 int skip_ioapic_setup;
 
-void arch_disable_smp_support(void)
+/**
+ * disable_ioapic_support() - disables ioapic support at runtime
+ */
+void disable_ioapic_support(void)
 {
 #ifdef CONFIG_PCI
        noioapicquirk = 1;
@@ -120,11 +123,14 @@ void arch_disable_smp_support(void)
 static int __init parse_noapic(char *str)
 {
        /* disable IO-APIC */
-       arch_disable_smp_support();
+       disable_ioapic_support();
        return 0;
 }
 early_param("noapic", parse_noapic);
 
+static int io_apic_setup_irq_pin_once(unsigned int irq, int node,
+                                     struct io_apic_irq_attr *attr);
+
 /* Will be called in mpparse/acpi/sfi codes for saving IRQ info */
 void mp_save_irq(struct mpc_intsrc *m)
 {
@@ -181,7 +187,7 @@ int __init arch_early_irq_init(void)
        irq_reserve_irqs(0, legacy_pic->nr_legacy_irqs);
 
        for (i = 0; i < count; i++) {
-               set_irq_chip_data(i, &cfg[i]);
+               irq_set_chip_data(i, &cfg[i]);
                zalloc_cpumask_var_node(&cfg[i].domain, GFP_KERNEL, node);
                zalloc_cpumask_var_node(&cfg[i].old_domain, GFP_KERNEL, node);
                /*
@@ -200,7 +206,7 @@ int __init arch_early_irq_init(void)
 #ifdef CONFIG_SPARSE_IRQ
 static struct irq_cfg *irq_cfg(unsigned int irq)
 {
-       return get_irq_chip_data(irq);
+       return irq_get_chip_data(irq);
 }
 
 static struct irq_cfg *alloc_irq_cfg(unsigned int irq, int node)
@@ -226,7 +232,7 @@ static void free_irq_cfg(unsigned int at, struct irq_cfg *cfg)
 {
        if (!cfg)
                return;
-       set_irq_chip_data(at, NULL);
+       irq_set_chip_data(at, NULL);
        free_cpumask_var(cfg->domain);
        free_cpumask_var(cfg->old_domain);
        kfree(cfg);
@@ -256,14 +262,14 @@ static struct irq_cfg *alloc_irq_and_cfg_at(unsigned int at, int node)
        if (res < 0) {
                if (res != -EEXIST)
                        return NULL;
-               cfg = get_irq_chip_data(at);
+               cfg = irq_get_chip_data(at);
                if (cfg)
                        return cfg;
        }
 
        cfg = alloc_irq_cfg(at, node);
        if (cfg)
-               set_irq_chip_data(at, cfg);
+               irq_set_chip_data(at, cfg);
        else
                irq_free_desc(at);
        return cfg;
@@ -818,7 +824,7 @@ static int EISA_ELCR(unsigned int irq)
 #define default_MCA_trigger(idx)       (1)
 #define default_MCA_polarity(idx)      default_ISA_polarity(idx)
 
-static int MPBIOS_polarity(int idx)
+static int irq_polarity(int idx)
 {
        int bus = mp_irqs[idx].srcbus;
        int polarity;
@@ -860,7 +866,7 @@ static int MPBIOS_polarity(int idx)
        return polarity;
 }
 
-static int MPBIOS_trigger(int idx)
+static int irq_trigger(int idx)
 {
        int bus = mp_irqs[idx].srcbus;
        int trigger;
@@ -932,16 +938,6 @@ static int MPBIOS_trigger(int idx)
        return trigger;
 }
 
-static inline int irq_polarity(int idx)
-{
-       return MPBIOS_polarity(idx);
-}
-
-static inline int irq_trigger(int idx)
-{
-       return MPBIOS_trigger(idx);
-}
-
 static int pin_2_irq(int idx, int apic, int pin)
 {
        int irq;
@@ -1189,7 +1185,7 @@ void __setup_vector_irq(int cpu)
        raw_spin_lock(&vector_lock);
        /* Mark the inuse vectors */
        for_each_active_irq(irq) {
-               cfg = get_irq_chip_data(irq);
+               cfg = irq_get_chip_data(irq);
                if (!cfg)
                        continue;
                /*
@@ -1220,10 +1216,6 @@ void __setup_vector_irq(int cpu)
 static struct irq_chip ioapic_chip;
 static struct irq_chip ir_ioapic_chip;
 
-#define IOAPIC_AUTO     -1
-#define IOAPIC_EDGE     0
-#define IOAPIC_LEVEL    1
-
 #ifdef CONFIG_X86_32
 static inline int IO_APIC_irq_trigger(int irq)
 {
@@ -1248,35 +1240,31 @@ static inline int IO_APIC_irq_trigger(int irq)
 }
 #endif
 
-static void ioapic_register_intr(unsigned int irq, unsigned long trigger)
+static void ioapic_register_intr(unsigned int irq, struct irq_cfg *cfg,
+                                unsigned long trigger)
 {
+       struct irq_chip *chip = &ioapic_chip;
+       irq_flow_handler_t hdl;
+       bool fasteoi;
 
        if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
-           trigger == IOAPIC_LEVEL)
+           trigger == IOAPIC_LEVEL) {
                irq_set_status_flags(irq, IRQ_LEVEL);
-       else
+               fasteoi = true;
+       } else {
                irq_clear_status_flags(irq, IRQ_LEVEL);
+               fasteoi = false;
+       }
 
-       if (irq_remapped(get_irq_chip_data(irq))) {
+       if (irq_remapped(cfg)) {
                irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
-               if (trigger)
-                       set_irq_chip_and_handler_name(irq, &ir_ioapic_chip,
-                                                     handle_fasteoi_irq,
-                                                    "fasteoi");
-               else
-                       set_irq_chip_and_handler_name(irq, &ir_ioapic_chip,
-                                                     handle_edge_irq, "edge");
-               return;
+               chip = &ir_ioapic_chip;
+               fasteoi = trigger != 0;
        }
 
-       if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
-           trigger == IOAPIC_LEVEL)
-               set_irq_chip_and_handler_name(irq, &ioapic_chip,
-                                             handle_fasteoi_irq,
-                                             "fasteoi");
-       else
-               set_irq_chip_and_handler_name(irq, &ioapic_chip,
-                                             handle_edge_irq, "edge");
+       hdl = fasteoi ? handle_fasteoi_irq : handle_edge_irq;
+       irq_set_chip_and_handler_name(irq, chip, hdl,
+                                     fasteoi ? "fasteoi" : "edge");
 }
 
 static int setup_ioapic_entry(int apic_id, int irq,
@@ -1374,7 +1362,7 @@ static void setup_ioapic_irq(int apic_id, int pin, unsigned int irq,
                return;
        }
 
-       ioapic_register_intr(irq, trigger);
+       ioapic_register_intr(irq, cfg, trigger);
        if (irq < legacy_pic->nr_legacy_irqs)
                legacy_pic->mask(irq);
 
@@ -1385,33 +1373,26 @@ static struct {
        DECLARE_BITMAP(pin_programmed, MP_MAX_IOAPIC_PIN + 1);
 } mp_ioapic_routing[MAX_IO_APICS];
 
-static void __init setup_IO_APIC_irqs(void)
+static bool __init io_apic_pin_not_connected(int idx, int apic_id, int pin)
 {
-       int apic_id, pin, idx, irq, notcon = 0;
-       int node = cpu_to_node(0);
-       struct irq_cfg *cfg;
+       if (idx != -1)
+               return false;
 
-       apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n");
+       apic_printk(APIC_VERBOSE, KERN_DEBUG " apic %d pin %d not connected\n",
+                   mp_ioapics[apic_id].apicid, pin);
+       return true;
+}
+
+static void __init __io_apic_setup_irqs(unsigned int apic_id)
+{
+       int idx, node = cpu_to_node(0);
+       struct io_apic_irq_attr attr;
+       unsigned int pin, irq;
 
-       for (apic_id = 0; apic_id < nr_ioapics; apic_id++)
        for (pin = 0; pin < nr_ioapic_registers[apic_id]; pin++) {
                idx = find_irq_entry(apic_id, pin, mp_INT);
-               if (idx == -1) {
-                       if (!notcon) {
-                               notcon = 1;
-                               apic_printk(APIC_VERBOSE,
-                                       KERN_DEBUG " %d-%d",
-                                       mp_ioapics[apic_id].apicid, pin);
-                       } else
-                               apic_printk(APIC_VERBOSE, " %d-%d",
-                                       mp_ioapics[apic_id].apicid, pin);
+               if (io_apic_pin_not_connected(idx, apic_id, pin))
                        continue;
-               }
-               if (notcon) {
-                       apic_printk(APIC_VERBOSE,
-                               " (apicid-pin) not connected\n");
-                       notcon = 0;
-               }
 
                irq = pin_2_irq(idx, apic_id, pin);
 
@@ -1423,25 +1404,24 @@ static void __init setup_IO_APIC_irqs(void)
                 * installed and if it returns 1:
                 */
                if (apic->multi_timer_check &&
-                               apic->multi_timer_check(apic_id, irq))
+                   apic->multi_timer_check(apic_id, irq))
                        continue;
 
-               cfg = alloc_irq_and_cfg_at(irq, node);
-               if (!cfg)
-                       continue;
+               set_io_apic_irq_attr(&attr, apic_id, pin, irq_trigger(idx),
+                                    irq_polarity(idx));
 
-               add_pin_to_irq_node(cfg, node, apic_id, pin);
-               /*
-                * don't mark it in pin_programmed, so later acpi could
-                * set it correctly when irq < 16
-                */
-               setup_ioapic_irq(apic_id, pin, irq, cfg, irq_trigger(idx),
-                                 irq_polarity(idx));
+               io_apic_setup_irq_pin(irq, node, &attr);
        }
+}
 
-       if (notcon)
-               apic_printk(APIC_VERBOSE,
-                       " (apicid-pin) not connected\n");
+static void __init setup_IO_APIC_irqs(void)
+{
+       unsigned int apic_id;
+
+       apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n");
+
+       for (apic_id = 0; apic_id < nr_ioapics; apic_id++)
+               __io_apic_setup_irqs(apic_id);
 }
 
 /*
@@ -1452,7 +1432,7 @@ static void __init setup_IO_APIC_irqs(void)
 void setup_IO_APIC_irq_extra(u32 gsi)
 {
        int apic_id = 0, pin, idx, irq, node = cpu_to_node(0);
-       struct irq_cfg *cfg;
+       struct io_apic_irq_attr attr;
 
        /*
         * Convert 'gsi' to 'ioapic.pin'.
@@ -1472,21 +1452,10 @@ void setup_IO_APIC_irq_extra(u32 gsi)
        if (apic_id == 0 || irq < NR_IRQS_LEGACY)
                return;
 
-       cfg = alloc_irq_and_cfg_at(irq, node);
-       if (!cfg)
-               return;
-
-       add_pin_to_irq_node(cfg, node, apic_id, pin);
+       set_io_apic_irq_attr(&attr, apic_id, pin, irq_trigger(idx),
+                            irq_polarity(idx));
 
-       if (test_bit(pin, mp_ioapic_routing[apic_id].pin_programmed)) {
-               pr_debug("Pin %d-%d already programmed\n",
-                        mp_ioapics[apic_id].apicid, pin);
-               return;
-       }
-       set_bit(pin, mp_ioapic_routing[apic_id].pin_programmed);
-
-       setup_ioapic_irq(apic_id, pin, irq, cfg,
-                       irq_trigger(idx), irq_polarity(idx));
+       io_apic_setup_irq_pin_once(irq, node, &attr);
 }
 
 /*
@@ -1518,7 +1487,8 @@ static void __init setup_timer_IRQ0_pin(unsigned int apic_id, unsigned int pin,
         * The timer IRQ doesn't have to know that behind the
         * scene we may have a 8259A-master in AEOI mode ...
         */
-       set_irq_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq, "edge");
+       irq_set_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq,
+                                     "edge");
 
        /*
         * Add it to the IO-APIC irq-routing table:
@@ -1625,7 +1595,7 @@ __apicdebuginit(void) print_IO_APIC(void)
        for_each_active_irq(irq) {
                struct irq_pin_list *entry;
 
-               cfg = get_irq_chip_data(irq);
+               cfg = irq_get_chip_data(irq);
                if (!cfg)
                        continue;
                entry = cfg->irq_2_pin;
@@ -2391,7 +2361,7 @@ static void irq_complete_move(struct irq_cfg *cfg)
 
 void irq_force_complete_move(int irq)
 {
-       struct irq_cfg *cfg = get_irq_chip_data(irq);
+       struct irq_cfg *cfg = irq_get_chip_data(irq);
 
        if (!cfg)
                return;
@@ -2405,7 +2375,7 @@ static inline void irq_complete_move(struct irq_cfg *cfg) { }
 static void ack_apic_edge(struct irq_data *data)
 {
        irq_complete_move(data->chip_data);
-       move_native_irq(data->irq);
+       irq_move_irq(data);
        ack_APIC_irq();
 }
 
@@ -2462,7 +2432,7 @@ static void ack_apic_level(struct irq_data *data)
        irq_complete_move(cfg);
 #ifdef CONFIG_GENERIC_PENDING_IRQ
        /* If we are moving the irq we need to mask it */
-       if (unlikely(irq_to_desc(irq)->status & IRQ_MOVE_PENDING)) {
+       if (unlikely(irqd_is_setaffinity_pending(data))) {
                do_unmask_irq = 1;
                mask_ioapic(cfg);
        }
@@ -2551,7 +2521,7 @@ static void ack_apic_level(struct irq_data *data)
                 * and you can go talk to the chipset vendor about it.
                 */
                if (!io_apic_level_ack_pending(cfg))
-                       move_masked_irq(irq);
+                       irq_move_masked_irq(data);
                unmask_ioapic(cfg);
        }
 }
@@ -2614,7 +2584,7 @@ static inline void init_IO_APIC_traps(void)
         * 0x80, because int 0x80 is hm, kind of importantish. ;)
         */
        for_each_active_irq(irq) {
-               cfg = get_irq_chip_data(irq);
+               cfg = irq_get_chip_data(irq);
                if (IO_APIC_IRQ(irq) && cfg && !cfg->vector) {
                        /*
                         * Hmm.. We don't have an entry for this,
@@ -2625,7 +2595,7 @@ static inline void init_IO_APIC_traps(void)
                                legacy_pic->make_irq(irq);
                        else
                                /* Strange. Oh, well.. */
-                               set_irq_chip(irq, &no_irq_chip);
+                               irq_set_chip(irq, &no_irq_chip);
                }
        }
 }
@@ -2665,7 +2635,7 @@ static struct irq_chip lapic_chip __read_mostly = {
 static void lapic_register_intr(int irq)
 {
        irq_clear_status_flags(irq, IRQ_LEVEL);
-       set_irq_chip_and_handler_name(irq, &lapic_chip, handle_edge_irq,
+       irq_set_chip_and_handler_name(irq, &lapic_chip, handle_edge_irq,
                                      "edge");
 }
 
@@ -2749,7 +2719,7 @@ int timer_through_8259 __initdata;
  */
 static inline void __init check_timer(void)
 {
-       struct irq_cfg *cfg = get_irq_chip_data(0);
+       struct irq_cfg *cfg = irq_get_chip_data(0);
        int node = cpu_to_node(0);
        int apic1, pin1, apic2, pin2;
        unsigned long flags;
@@ -3060,7 +3030,7 @@ unsigned int create_irq_nr(unsigned int from, int node)
        raw_spin_unlock_irqrestore(&vector_lock, flags);
 
        if (ret) {
-               set_irq_chip_data(irq, cfg);
+               irq_set_chip_data(irq, cfg);
                irq_clear_status_flags(irq, IRQ_NOREQUEST);
        } else {
                free_irq_at(irq, cfg);
@@ -3085,7 +3055,7 @@ int create_irq(void)
 
 void destroy_irq(unsigned int irq)
 {
-       struct irq_cfg *cfg = get_irq_chip_data(irq);
+       struct irq_cfg *cfg = irq_get_chip_data(irq);
        unsigned long flags;
 
        irq_set_status_flags(irq, IRQ_NOREQUEST|IRQ_NOPROBE);
@@ -3119,7 +3089,7 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
 
        dest = apic->cpu_mask_to_apicid_and(cfg->domain, apic->target_cpus());
 
-       if (irq_remapped(get_irq_chip_data(irq))) {
+       if (irq_remapped(cfg)) {
                struct irte irte;
                int ir_index;
                u16 sub_handle;
@@ -3291,6 +3261,7 @@ static int msi_alloc_irte(struct pci_dev *dev, int irq, int nvec)
 
 static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
 {
+       struct irq_chip *chip = &msi_chip;
        struct msi_msg msg;
        int ret;
 
@@ -3298,14 +3269,15 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
        if (ret < 0)
                return ret;
 
-       set_irq_msi(irq, msidesc);
+       irq_set_msi_desc(irq, msidesc);
        write_msi_msg(irq, &msg);
 
-       if (irq_remapped(get_irq_chip_data(irq))) {
+       if (irq_remapped(irq_get_chip_data(irq))) {
                irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
-               set_irq_chip_and_handler_name(irq, &msi_ir_chip, handle_edge_irq, "edge");
-       } else
-               set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
+               chip = &msi_ir_chip;
+       }
+
+       irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
 
        dev_printk(KERN_DEBUG, &dev->dev, "irq %d for MSI/MSI-X\n", irq);
 
@@ -3423,8 +3395,8 @@ int arch_setup_dmar_msi(unsigned int irq)
        if (ret < 0)
                return ret;
        dmar_msi_write(irq, &msg);
-       set_irq_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq,
-               "edge");
+       irq_set_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq,
+                                     "edge");
        return 0;
 }
 #endif
@@ -3482,6 +3454,7 @@ static struct irq_chip hpet_msi_type = {
 
 int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
 {
+       struct irq_chip *chip = &hpet_msi_type;
        struct msi_msg msg;
        int ret;
 
@@ -3501,15 +3474,12 @@ int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
        if (ret < 0)
                return ret;
 
-       hpet_msi_write(get_irq_data(irq), &msg);
+       hpet_msi_write(irq_get_handler_data(irq), &msg);
        irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
-       if (irq_remapped(get_irq_chip_data(irq)))
-               set_irq_chip_and_handler_name(irq, &ir_hpet_msi_type,
-                                             handle_edge_irq, "edge");
-       else
-               set_irq_chip_and_handler_name(irq, &hpet_msi_type,
-                                             handle_edge_irq, "edge");
+       if (irq_remapped(irq_get_chip_data(irq)))
+               chip = &ir_hpet_msi_type;
 
+       irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
        return 0;
 }
 #endif
@@ -3596,7 +3566,7 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
 
                write_ht_irq_msg(irq, &msg);
 
-               set_irq_chip_and_handler_name(irq, &ht_irq_chip,
+               irq_set_chip_and_handler_name(irq, &ht_irq_chip,
                                              handle_edge_irq, "edge");
 
                dev_printk(KERN_DEBUG, &dev->dev, "irq %d for HT\n", irq);
@@ -3605,7 +3575,40 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
 }
 #endif /* CONFIG_HT_IRQ */
 
-int __init io_apic_get_redir_entries (int ioapic)
+int
+io_apic_setup_irq_pin(unsigned int irq, int node, struct io_apic_irq_attr *attr)
+{
+       struct irq_cfg *cfg = alloc_irq_and_cfg_at(irq, node);
+       int ret;
+
+       if (!cfg)
+               return -EINVAL;
+       ret = __add_pin_to_irq_node(cfg, node, attr->ioapic, attr->ioapic_pin);
+       if (!ret)
+               setup_ioapic_irq(attr->ioapic, attr->ioapic_pin, irq, cfg,
+                                attr->trigger, attr->polarity);
+       return ret;
+}
+
+static int io_apic_setup_irq_pin_once(unsigned int irq, int node,
+                                     struct io_apic_irq_attr *attr)
+{
+       unsigned int id = attr->ioapic, pin = attr->ioapic_pin;
+       int ret;
+
+       /* Avoid redundant programming */
+       if (test_bit(pin, mp_ioapic_routing[id].pin_programmed)) {
+               pr_debug("Pin %d-%d already programmed\n",
+                        mp_ioapics[id].apicid, pin);
+               return 0;
+       }
+       ret = io_apic_setup_irq_pin(irq, node, attr);
+       if (!ret)
+               set_bit(pin, mp_ioapic_routing[id].pin_programmed);
+       return ret;
+}
+
+static int __init io_apic_get_redir_entries(int ioapic)
 {
        union IO_APIC_reg_01    reg_01;
        unsigned long flags;
@@ -3659,96 +3662,24 @@ int __init arch_probe_nr_irqs(void)
 }
 #endif
 
-static int __io_apic_set_pci_routing(struct device *dev, int irq,
-                               struct io_apic_irq_attr *irq_attr)
+int io_apic_set_pci_routing(struct device *dev, int irq,
+                           struct io_apic_irq_attr *irq_attr)
 {
-       struct irq_cfg *cfg;
        int node;
-       int ioapic, pin;
-       int trigger, polarity;
 
-       ioapic = irq_attr->ioapic;
        if (!IO_APIC_IRQ(irq)) {
                apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n",
-                       ioapic);
+                           irq_attr->ioapic);
                return -EINVAL;
        }
 
-       if (dev)
-               node = dev_to_node(dev);
-       else
-               node = cpu_to_node(0);
+       node = dev ? dev_to_node(dev) : cpu_to_node(0);
 
-       cfg = alloc_irq_and_cfg_at(irq, node);
-       if (!cfg)
-               return 0;
-
-       pin = irq_attr->ioapic_pin;
-       trigger = irq_attr->trigger;
-       polarity = irq_attr->polarity;
-
-       /*
-        * IRQs < 16 are already in the irq_2_pin[] map
-        */
-       if (irq >= legacy_pic->nr_legacy_irqs) {
-               if (__add_pin_to_irq_node(cfg, node, ioapic, pin)) {
-                       printk(KERN_INFO "can not add pin %d for irq %d\n",
-                               pin, irq);
-                       return 0;
-               }
-       }
-
-       setup_ioapic_irq(ioapic, pin, irq, cfg, trigger, polarity);
-
-       return 0;
-}
-
-int io_apic_set_pci_routing(struct device *dev, int irq,
-                               struct io_apic_irq_attr *irq_attr)
-{
-       int ioapic, pin;
-       /*
-        * Avoid pin reprogramming.  PRTs typically include entries
-        * with redundant pin->gsi mappings (but unique PCI devices);
-        * we only program the IOAPIC on the first.
-        */
-       ioapic = irq_attr->ioapic;
-       pin = irq_attr->ioapic_pin;
-       if (test_bit(pin, mp_ioapic_routing[ioapic].pin_programmed)) {
-               pr_debug("Pin %d-%d already programmed\n",
-                        mp_ioapics[ioapic].apicid, pin);
-               return 0;
-       }
-       set_bit(pin, mp_ioapic_routing[ioapic].pin_programmed);
-
-       return __io_apic_set_pci_routing(dev, irq, irq_attr);
-}
-
-u8 __init io_apic_unique_id(u8 id)
-{
-#ifdef CONFIG_X86_32
-       if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
-           !APIC_XAPIC(apic_version[boot_cpu_physical_apicid]))
-               return io_apic_get_unique_id(nr_ioapics, id);
-       else
-               return id;
-#else
-       int i;
-       DECLARE_BITMAP(used, 256);
-
-       bitmap_zero(used, 256);
-       for (i = 0; i < nr_ioapics; i++) {
-               struct mpc_ioapic *ia = &mp_ioapics[i];
-               __set_bit(ia->apicid, used);
-       }
-       if (!test_bit(id, used))
-               return id;
-       return find_first_zero_bit(used, 256);
-#endif
+       return io_apic_setup_irq_pin_once(irq, node, irq_attr);
 }
 
 #ifdef CONFIG_X86_32
-int __init io_apic_get_unique_id(int ioapic, int apic_id)
+static int __init io_apic_get_unique_id(int ioapic, int apic_id)
 {
        union IO_APIC_reg_00 reg_00;
        static physid_mask_t apic_id_map = PHYSID_MASK_NONE;
@@ -3821,9 +3752,33 @@ int __init io_apic_get_unique_id(int ioapic, int apic_id)
 
        return apic_id;
 }
+
+static u8 __init io_apic_unique_id(u8 id)
+{
+       if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
+           !APIC_XAPIC(apic_version[boot_cpu_physical_apicid]))
+               return io_apic_get_unique_id(nr_ioapics, id);
+       else
+               return id;
+}
+#else
+static u8 __init io_apic_unique_id(u8 id)
+{
+       int i;
+       DECLARE_BITMAP(used, 256);
+
+       bitmap_zero(used, 256);
+       for (i = 0; i < nr_ioapics; i++) {
+               struct mpc_ioapic *ia = &mp_ioapics[i];
+               __set_bit(ia->apicid, used);
+       }
+       if (!test_bit(id, used))
+               return id;
+       return find_first_zero_bit(used, 256);
+}
 #endif
 
-int __init io_apic_get_version(int ioapic)
+static int __init io_apic_get_version(int ioapic)
 {
        union IO_APIC_reg_01    reg_01;
        unsigned long flags;
@@ -3868,8 +3823,8 @@ int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity)
 void __init setup_ioapic_dest(void)
 {
        int pin, ioapic, irq, irq_entry;
-       struct irq_desc *desc;
        const struct cpumask *mask;
+       struct irq_data *idata;
 
        if (skip_ioapic_setup == 1)
                return;
@@ -3884,21 +3839,20 @@ void __init setup_ioapic_dest(void)
                if ((ioapic > 0) && (irq > 16))
                        continue;
 
-               desc = irq_to_desc(irq);
+               idata = irq_get_irq_data(irq);
 
                /*
                 * Honour affinities which have been set in early boot
                 */
-               if (desc->status &
-                   (IRQ_NO_BALANCING | IRQ_AFFINITY_SET))
-                       mask = desc->irq_data.affinity;
+               if (!irqd_can_balance(idata) || irqd_affinity_was_set(idata))
+                       mask = idata->affinity;
                else
                        mask = apic->target_cpus();
 
                if (intr_remapping_enabled)
-                       ir_ioapic_set_affinity(&desc->irq_data, mask, false);
+                       ir_ioapic_set_affinity(idata, mask, false);
                else
-                       ioapic_set_affinity(&desc->irq_data, mask, false);
+                       ioapic_set_affinity(idata, mask, false);
        }
 
 }
@@ -4002,6 +3956,9 @@ int mp_find_ioapic(u32 gsi)
 {
        int i = 0;
 
+       if (nr_ioapics == 0)
+               return -1;
+
        /* Find the IOAPIC that manages this GSI. */
        for (i = 0; i < nr_ioapics; i++) {
                if ((gsi >= mp_gsi_routing[i].gsi_base)
@@ -4023,7 +3980,7 @@ int mp_find_ioapic_pin(int ioapic, u32 gsi)
        return gsi - mp_gsi_routing[ioapic].gsi_base;
 }
 
-static int bad_ioapic(unsigned long address)
+static __init int bad_ioapic(unsigned long address)
 {
        if (nr_ioapics >= MAX_IO_APICS) {
                printk(KERN_WARNING "WARING: Max # of I/O APICs (%d) exceeded "
@@ -4083,20 +4040,16 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)
 /* Enable IOAPIC early just for system timer */
 void __init pre_init_apic_IRQ0(void)
 {
-       struct irq_cfg *cfg;
+       struct io_apic_irq_attr attr = { 0, 0, 0, 0 };
 
        printk(KERN_INFO "Early APIC setup for system timer0\n");
 #ifndef CONFIG_SMP
        physid_set_mask_of_physid(boot_cpu_physical_apicid,
                                         &phys_cpu_present_map);
 #endif
-       /* Make sure the irq descriptor is set up */
-       cfg = alloc_irq_and_cfg_at(0, 0);
-
        setup_local_APIC();
 
-       add_pin_to_irq_node(cfg, 0, 0, 0);
-       set_irq_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq, "edge");
-
-       setup_ioapic_irq(0, 0, 0, cfg, 0, 0);
+       io_apic_setup_irq_pin(0, 0, &attr);
+       irq_set_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq,
+                                     "edge");
 }
index 08385e0..cce91bf 100644 (file)
@@ -56,6 +56,8 @@ void default_send_IPI_mask_allbutself_phys(const struct cpumask *mask,
        local_irq_restore(flags);
 }
 
+#ifdef CONFIG_X86_32
+
 void default_send_IPI_mask_sequence_logical(const struct cpumask *mask,
                                                 int vector)
 {
@@ -71,8 +73,8 @@ void default_send_IPI_mask_sequence_logical(const struct cpumask *mask,
        local_irq_save(flags);
        for_each_cpu(query_cpu, mask)
                __default_send_IPI_dest_field(
-                       apic->cpu_to_logical_apicid(query_cpu), vector,
-                       apic->dest_logical);
+                       early_per_cpu(x86_cpu_to_logical_apicid, query_cpu),
+                       vector, apic->dest_logical);
        local_irq_restore(flags);
 }
 
@@ -90,14 +92,12 @@ void default_send_IPI_mask_allbutself_logical(const struct cpumask *mask,
                if (query_cpu == this_cpu)
                        continue;
                __default_send_IPI_dest_field(
-                       apic->cpu_to_logical_apicid(query_cpu), vector,
-                       apic->dest_logical);
+                       early_per_cpu(x86_cpu_to_logical_apicid, query_cpu),
+                       vector, apic->dest_logical);
                }
        local_irq_restore(flags);
 }
 
-#ifdef CONFIG_X86_32
-
 /*
  * This is only used on smaller machines.
  */
index 960f26a..6273eee 100644 (file)
@@ -373,13 +373,6 @@ static inline void numaq_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask
        return physids_promote(0xFUL, retmap);
 }
 
-static inline int numaq_cpu_to_logical_apicid(int cpu)
-{
-       if (cpu >= nr_cpu_ids)
-               return BAD_APICID;
-       return cpu_2_logical_apicid[cpu];
-}
-
 /*
  * Supporting over 60 cpus on NUMA-Q requires a locality-dependent
  * cpu to APIC ID relation to properly interact with the intelligent
@@ -398,6 +391,15 @@ static inline int numaq_apicid_to_node(int logical_apicid)
        return logical_apicid >> 4;
 }
 
+static int numaq_numa_cpu_node(int cpu)
+{
+       int logical_apicid = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
+
+       if (logical_apicid != BAD_APICID)
+               return numaq_apicid_to_node(logical_apicid);
+       return NUMA_NO_NODE;
+}
+
 static void numaq_apicid_to_cpu_present(int logical_apicid, physid_mask_t *retmap)
 {
        int node = numaq_apicid_to_node(logical_apicid);
@@ -508,8 +510,6 @@ struct apic __refdata apic_numaq = {
        .ioapic_phys_id_map             = numaq_ioapic_phys_id_map,
        .setup_apic_routing             = numaq_setup_apic_routing,
        .multi_timer_check              = numaq_multi_timer_check,
-       .apicid_to_node                 = numaq_apicid_to_node,
-       .cpu_to_logical_apicid          = numaq_cpu_to_logical_apicid,
        .cpu_present_to_apicid          = numaq_cpu_present_to_apicid,
        .apicid_to_cpu_present          = numaq_apicid_to_cpu_present,
        .setup_portio_remap             = numaq_setup_portio_remap,
@@ -547,4 +547,7 @@ struct apic __refdata apic_numaq = {
        .icr_write                      = native_apic_icr_write,
        .wait_icr_idle                  = native_apic_wait_icr_idle,
        .safe_wait_icr_idle             = native_safe_apic_wait_icr_idle,
+
+       .x86_32_early_logical_apicid    = noop_x86_32_early_logical_apicid,
+       .x86_32_numa_cpu_node           = numaq_numa_cpu_node,
 };
index 99d2fe0..fc84c7b 100644 (file)
@@ -77,6 +77,11 @@ void __init default_setup_apic_routing(void)
                apic->setup_apic_routing();
 }
 
+static int default_x86_32_early_logical_apicid(int cpu)
+{
+       return 1 << cpu;
+}
+
 static void setup_apic_flat_routing(void)
 {
 #ifdef CONFIG_X86_IO_APIC
@@ -130,8 +135,6 @@ struct apic apic_default = {
        .ioapic_phys_id_map             = default_ioapic_phys_id_map,
        .setup_apic_routing             = setup_apic_flat_routing,
        .multi_timer_check              = NULL,
-       .apicid_to_node                 = default_apicid_to_node,
-       .cpu_to_logical_apicid          = default_cpu_to_logical_apicid,
        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
        .apicid_to_cpu_present          = physid_set_mask_of_physid,
        .setup_portio_remap             = NULL,
@@ -167,6 +170,9 @@ struct apic apic_default = {
        .icr_write                      = native_apic_icr_write,
        .wait_icr_idle                  = native_apic_wait_icr_idle,
        .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 9b41926..e4b8059 100644 (file)
@@ -194,11 +194,10 @@ static unsigned long summit_check_apicid_present(int bit)
        return 1;
 }
 
-static void summit_init_apic_ldr(void)
+static int summit_early_logical_apicid(int cpu)
 {
-       unsigned long val, id;
        int count = 0;
-       u8 my_id = (u8)hard_smp_processor_id();
+       u8 my_id = early_per_cpu(x86_cpu_to_apicid, cpu);
        u8 my_cluster = APIC_CLUSTER(my_id);
 #ifdef CONFIG_SMP
        u8 lid;
@@ -206,7 +205,7 @@ static void summit_init_apic_ldr(void)
 
        /* Create logical APIC IDs by counting CPUs already in cluster. */
        for (count = 0, i = nr_cpu_ids; --i >= 0; ) {
-               lid = cpu_2_logical_apicid[i];
+               lid = early_per_cpu(x86_cpu_to_logical_apicid, i);
                if (lid != BAD_APICID && APIC_CLUSTER(lid) == my_cluster)
                        ++count;
        }
@@ -214,7 +213,15 @@ static void summit_init_apic_ldr(void)
        /* We only have a 4 wide bitmap in cluster mode.  If a deranged
         * BIOS puts 5 CPUs in one APIC cluster, we're hosed. */
        BUG_ON(count >= XAPIC_DEST_CPUS_SHIFT);
-       id = my_cluster | (1UL << count);
+       return my_cluster | (1UL << count);
+}
+
+static void summit_init_apic_ldr(void)
+{
+       int cpu = smp_processor_id();
+       unsigned long id = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
+       unsigned long val;
+
        apic_write(APIC_DFR, SUMMIT_APIC_DFR_VALUE);
        val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
        val |= SET_APIC_LOGICAL_ID(id);
@@ -232,27 +239,6 @@ static void summit_setup_apic_routing(void)
                                                nr_ioapics);
 }
 
-static int summit_apicid_to_node(int logical_apicid)
-{
-#ifdef CONFIG_SMP
-       return apicid_2_node[hard_smp_processor_id()];
-#else
-       return 0;
-#endif
-}
-
-/* Mapping from cpu number to logical apicid */
-static inline int summit_cpu_to_logical_apicid(int cpu)
-{
-#ifdef CONFIG_SMP
-       if (cpu >= nr_cpu_ids)
-               return BAD_APICID;
-       return cpu_2_logical_apicid[cpu];
-#else
-       return logical_smp_processor_id();
-#endif
-}
-
 static int summit_cpu_present_to_apicid(int mps_cpu)
 {
        if (mps_cpu < nr_cpu_ids)
@@ -286,7 +272,7 @@ static unsigned int summit_cpu_mask_to_apicid(const struct cpumask *cpumask)
         * The cpus in the mask must all be on the apic cluster.
         */
        for_each_cpu(cpu, cpumask) {
-               int new_apicid = summit_cpu_to_logical_apicid(cpu);
+               int new_apicid = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
 
                if (round && APIC_CLUSTER(apicid) != APIC_CLUSTER(new_apicid)) {
                        printk("%s: Not a valid mask!\n", __func__);
@@ -301,7 +287,7 @@ static unsigned int summit_cpu_mask_to_apicid(const struct cpumask *cpumask)
 static unsigned int summit_cpu_mask_to_apicid_and(const struct cpumask *inmask,
                              const struct cpumask *andmask)
 {
-       int apicid = summit_cpu_to_logical_apicid(0);
+       int apicid = early_per_cpu(x86_cpu_to_logical_apicid, 0);
        cpumask_var_t cpumask;
 
        if (!alloc_cpumask_var(&cpumask, GFP_ATOMIC))
@@ -528,8 +514,6 @@ struct apic apic_summit = {
        .ioapic_phys_id_map             = summit_ioapic_phys_id_map,
        .setup_apic_routing             = summit_setup_apic_routing,
        .multi_timer_check              = NULL,
-       .apicid_to_node                 = summit_apicid_to_node,
-       .cpu_to_logical_apicid          = summit_cpu_to_logical_apicid,
        .cpu_present_to_apicid          = summit_cpu_present_to_apicid,
        .apicid_to_cpu_present          = summit_apicid_to_cpu_present,
        .setup_portio_remap             = NULL,
@@ -565,4 +549,7 @@ struct apic apic_summit = {
        .icr_write                      = native_apic_icr_write,
        .wait_icr_idle                  = native_apic_wait_icr_idle,
        .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 cf69c59..90949bb 100644 (file)
@@ -206,8 +206,6 @@ struct apic apic_x2apic_cluster = {
        .ioapic_phys_id_map             = NULL,
        .setup_apic_routing             = NULL,
        .multi_timer_check              = NULL,
-       .apicid_to_node                 = NULL,
-       .cpu_to_logical_apicid          = NULL,
        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
        .apicid_to_cpu_present          = NULL,
        .setup_portio_remap             = NULL,
index 8972f38..c7e6d66 100644 (file)
@@ -195,8 +195,6 @@ struct apic apic_x2apic_phys = {
        .ioapic_phys_id_map             = NULL,
        .setup_apic_routing             = NULL,
        .multi_timer_check              = NULL,
-       .apicid_to_node                 = NULL,
-       .cpu_to_logical_apicid          = NULL,
        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
        .apicid_to_cpu_present          = NULL,
        .setup_portio_remap             = NULL,
index bd16b58..3c28928 100644 (file)
@@ -338,8 +338,6 @@ struct apic __refdata apic_x2apic_uv_x = {
        .ioapic_phys_id_map             = NULL,
        .setup_apic_routing             = NULL,
        .multi_timer_check              = NULL,
-       .apicid_to_node                 = NULL,
-       .cpu_to_logical_apicid          = NULL,
        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
        .apicid_to_cpu_present          = NULL,
        .setup_portio_remap             = NULL,
index cfa82c8..4f13faf 100644 (file)
@@ -1,5 +1,70 @@
+/*
+ * Generate definitions needed by assembly language modules.
+ * This code generates raw asm output which is post-processed to extract
+ * and format the required data.
+ */
+#define COMPILE_OFFSETS
+
+#include <linux/crypto.h>
+#include <linux/sched.h>
+#include <linux/stddef.h>
+#include <linux/hardirq.h>
+#include <linux/suspend.h>
+#include <linux/kbuild.h>
+#include <asm/processor.h>
+#include <asm/thread_info.h>
+#include <asm/sigframe.h>
+#include <asm/bootparam.h>
+#include <asm/suspend.h>
+
+#ifdef CONFIG_XEN
+#include <xen/interface/xen.h>
+#endif
+
 #ifdef CONFIG_X86_32
 # include "asm-offsets_32.c"
 #else
 # include "asm-offsets_64.c"
 #endif
+
+void common(void) {
+       BLANK();
+       OFFSET(TI_flags, thread_info, flags);
+       OFFSET(TI_status, thread_info, status);
+       OFFSET(TI_addr_limit, thread_info, addr_limit);
+       OFFSET(TI_preempt_count, thread_info, preempt_count);
+
+       BLANK();
+       OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx);
+
+       BLANK();
+       OFFSET(pbe_address, pbe, address);
+       OFFSET(pbe_orig_address, pbe, orig_address);
+       OFFSET(pbe_next, pbe, next);
+
+#ifdef CONFIG_PARAVIRT
+       BLANK();
+       OFFSET(PARAVIRT_enabled, pv_info, paravirt_enabled);
+       OFFSET(PARAVIRT_PATCH_pv_cpu_ops, paravirt_patch_template, pv_cpu_ops);
+       OFFSET(PARAVIRT_PATCH_pv_irq_ops, paravirt_patch_template, pv_irq_ops);
+       OFFSET(PV_IRQ_irq_disable, pv_irq_ops, irq_disable);
+       OFFSET(PV_IRQ_irq_enable, pv_irq_ops, irq_enable);
+       OFFSET(PV_CPU_iret, pv_cpu_ops, iret);
+       OFFSET(PV_CPU_irq_enable_sysexit, pv_cpu_ops, irq_enable_sysexit);
+       OFFSET(PV_CPU_read_cr0, pv_cpu_ops, read_cr0);
+       OFFSET(PV_MMU_read_cr2, pv_mmu_ops, read_cr2);
+#endif
+
+#ifdef CONFIG_XEN
+       BLANK();
+       OFFSET(XEN_vcpu_info_mask, vcpu_info, evtchn_upcall_mask);
+       OFFSET(XEN_vcpu_info_pending, vcpu_info, evtchn_upcall_pending);
+#endif
+
+       BLANK();
+       OFFSET(BP_scratch, boot_params, scratch);
+       OFFSET(BP_loadflags, boot_params, hdr.loadflags);
+       OFFSET(BP_hardware_subarch, boot_params, hdr.hardware_subarch);
+       OFFSET(BP_version, boot_params, hdr.version);
+       OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment);
+}
index 1a4088d..c29d631 100644 (file)
@@ -1,26 +1,4 @@
-/*
- * Generate definitions needed by assembly language modules.
- * This code generates raw asm output which is post-processed
- * to extract and format the required data.
- */
-
-#include <linux/crypto.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/personality.h>
-#include <linux/suspend.h>
-#include <linux/kbuild.h>
 #include <asm/ucontext.h>
-#include <asm/sigframe.h>
-#include <asm/pgtable.h>
-#include <asm/fixmap.h>
-#include <asm/processor.h>
-#include <asm/thread_info.h>
-#include <asm/bootparam.h>
-#include <asm/elf.h>
-#include <asm/suspend.h>
-
-#include <xen/interface/xen.h>
 
 #include <linux/lguest.h>
 #include "../../../drivers/lguest/lg.h"
@@ -51,21 +29,10 @@ void foo(void)
        OFFSET(CPUINFO_x86_vendor_id, cpuinfo_x86, x86_vendor_id);
        BLANK();
 
-       OFFSET(TI_task, thread_info, task);
-       OFFSET(TI_exec_domain, thread_info, exec_domain);
-       OFFSET(TI_flags, thread_info, flags);
-       OFFSET(TI_status, thread_info, status);
-       OFFSET(TI_preempt_count, thread_info, preempt_count);
-       OFFSET(TI_addr_limit, thread_info, addr_limit);
-       OFFSET(TI_restart_block, thread_info, restart_block);
        OFFSET(TI_sysenter_return, thread_info, sysenter_return);
        OFFSET(TI_cpu, thread_info, cpu);
        BLANK();
 
-       OFFSET(GDS_size, desc_ptr, size);
-       OFFSET(GDS_address, desc_ptr, address);
-       BLANK();
-
        OFFSET(PT_EBX, pt_regs, bx);
        OFFSET(PT_ECX, pt_regs, cx);
        OFFSET(PT_EDX, pt_regs, dx);
@@ -85,42 +52,13 @@ void foo(void)
        OFFSET(PT_OLDSS,  pt_regs, ss);
        BLANK();
 
-       OFFSET(EXEC_DOMAIN_handler, exec_domain, handler);
        OFFSET(IA32_RT_SIGFRAME_sigcontext, rt_sigframe, uc.uc_mcontext);
        BLANK();
 
-       OFFSET(pbe_address, pbe, address);
-       OFFSET(pbe_orig_address, pbe, orig_address);
-       OFFSET(pbe_next, pbe, next);
-
        /* Offset from the sysenter stack to tss.sp0 */
        DEFINE(TSS_sysenter_sp0, offsetof(struct tss_struct, x86_tss.sp0) -
                 sizeof(struct tss_struct));
 
-       DEFINE(PAGE_SIZE_asm, PAGE_SIZE);
-       DEFINE(PAGE_SHIFT_asm, PAGE_SHIFT);
-       DEFINE(THREAD_SIZE_asm, THREAD_SIZE);
-
-       OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx);
-
-#ifdef CONFIG_PARAVIRT
-       BLANK();
-       OFFSET(PARAVIRT_enabled, pv_info, paravirt_enabled);
-       OFFSET(PARAVIRT_PATCH_pv_cpu_ops, paravirt_patch_template, pv_cpu_ops);
-       OFFSET(PARAVIRT_PATCH_pv_irq_ops, paravirt_patch_template, pv_irq_ops);
-       OFFSET(PV_IRQ_irq_disable, pv_irq_ops, irq_disable);
-       OFFSET(PV_IRQ_irq_enable, pv_irq_ops, irq_enable);
-       OFFSET(PV_CPU_iret, pv_cpu_ops, iret);
-       OFFSET(PV_CPU_irq_enable_sysexit, pv_cpu_ops, irq_enable_sysexit);
-       OFFSET(PV_CPU_read_cr0, pv_cpu_ops, read_cr0);
-#endif
-
-#ifdef CONFIG_XEN
-       BLANK();
-       OFFSET(XEN_vcpu_info_mask, vcpu_info, evtchn_upcall_mask);
-       OFFSET(XEN_vcpu_info_pending, vcpu_info, evtchn_upcall_pending);
-#endif
-
 #if defined(CONFIG_LGUEST) || defined(CONFIG_LGUEST_GUEST) || defined(CONFIG_LGUEST_MODULE)
        BLANK();
        OFFSET(LGUEST_DATA_irq_enabled, lguest_data, irq_enabled);
@@ -139,11 +77,4 @@ void foo(void)
        OFFSET(LGUEST_PAGES_regs_errcode, lguest_pages, regs.errcode);
        OFFSET(LGUEST_PAGES_regs, lguest_pages, regs);
 #endif
-
-       BLANK();
-       OFFSET(BP_scratch, boot_params, scratch);
-       OFFSET(BP_loadflags, boot_params, hdr.loadflags);
-       OFFSET(BP_hardware_subarch, boot_params, hdr.hardware_subarch);
-       OFFSET(BP_version, boot_params, hdr.version);
-       OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment);
 }
index 4a6aeed..e72a119 100644 (file)
@@ -1,27 +1,4 @@
-/*
- * Generate definitions needed by assembly language modules.
- * This code generates raw asm output which is post-processed to extract
- * and format the required data.
- */
-#define COMPILE_OFFSETS
-
-#include <linux/crypto.h>
-#include <linux/sched.h> 
-#include <linux/stddef.h>
-#include <linux/errno.h> 
-#include <linux/hardirq.h>
-#include <linux/suspend.h>
-#include <linux/kbuild.h>
-#include <asm/processor.h>
-#include <asm/segment.h>
-#include <asm/thread_info.h>
 #include <asm/ia32.h>
-#include <asm/bootparam.h>
-#include <asm/suspend.h>
-
-#include <xen/interface/xen.h>
-
-#include <asm/sigframe.h>
 
 #define __NO_STUBS 1
 #undef __SYSCALL
@@ -33,41 +10,19 @@ static char syscalls[] = {
 
 int main(void)
 {
-#define ENTRY(entry) DEFINE(tsk_ ## entry, offsetof(struct task_struct, entry))
-       ENTRY(state);
-       ENTRY(flags); 
-       ENTRY(pid);
-       BLANK();
-#undef ENTRY
-#define ENTRY(entry) DEFINE(TI_ ## entry, offsetof(struct thread_info, entry))
-       ENTRY(flags);
-       ENTRY(addr_limit);
-       ENTRY(preempt_count);
-       ENTRY(status);
-#ifdef CONFIG_IA32_EMULATION
-       ENTRY(sysenter_return);
-#endif
-       BLANK();
-#undef ENTRY
 #ifdef CONFIG_PARAVIRT
-       BLANK();
-       OFFSET(PARAVIRT_enabled, pv_info, paravirt_enabled);
-       OFFSET(PARAVIRT_PATCH_pv_cpu_ops, paravirt_patch_template, pv_cpu_ops);
-       OFFSET(PARAVIRT_PATCH_pv_irq_ops, paravirt_patch_template, pv_irq_ops);
-       OFFSET(PV_IRQ_irq_disable, pv_irq_ops, irq_disable);
-       OFFSET(PV_IRQ_irq_enable, pv_irq_ops, irq_enable);
        OFFSET(PV_IRQ_adjust_exception_frame, pv_irq_ops, adjust_exception_frame);
-       OFFSET(PV_CPU_iret, pv_cpu_ops, iret);
        OFFSET(PV_CPU_usergs_sysret32, pv_cpu_ops, usergs_sysret32);
        OFFSET(PV_CPU_usergs_sysret64, pv_cpu_ops, usergs_sysret64);
-       OFFSET(PV_CPU_irq_enable_sysexit, pv_cpu_ops, irq_enable_sysexit);
        OFFSET(PV_CPU_swapgs, pv_cpu_ops, swapgs);
-       OFFSET(PV_MMU_read_cr2, pv_mmu_ops, read_cr2);
+       BLANK();
 #endif
 
-
 #ifdef CONFIG_IA32_EMULATION
-#define ENTRY(entry) DEFINE(IA32_SIGCONTEXT_ ## entry, offsetof(struct sigcontext_ia32, entry))
+       OFFSET(TI_sysenter_return, thread_info, sysenter_return);
+       BLANK();
+
+#define ENTRY(entry) OFFSET(IA32_SIGCONTEXT_ ## entry, sigcontext_ia32, entry)
        ENTRY(ax);
        ENTRY(bx);
        ENTRY(cx);
@@ -79,15 +34,12 @@ int main(void)
        ENTRY(ip);
        BLANK();
 #undef ENTRY
-       DEFINE(IA32_RT_SIGFRAME_sigcontext,
-              offsetof (struct rt_sigframe_ia32, uc.uc_mcontext));
+
+       OFFSET(IA32_RT_SIGFRAME_sigcontext, rt_sigframe_ia32, uc.uc_mcontext);
        BLANK();
 #endif
-       DEFINE(pbe_address, offsetof(struct pbe, address));
-       DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address));
-       DEFINE(pbe_next, offsetof(struct pbe, next));
-       BLANK();
-#define ENTRY(entry) DEFINE(pt_regs_ ## entry, offsetof(struct pt_regs, entry))
+
+#define ENTRY(entry) OFFSET(pt_regs_ ## entry, pt_regs, entry)
        ENTRY(bx);
        ENTRY(bx);
        ENTRY(cx);
@@ -107,7 +59,8 @@ int main(void)
        ENTRY(flags);
        BLANK();
 #undef ENTRY
-#define ENTRY(entry) DEFINE(saved_context_ ## entry, offsetof(struct saved_context, entry))
+
+#define ENTRY(entry) OFFSET(saved_context_ ## entry, saved_context, entry)
        ENTRY(cr0);
        ENTRY(cr2);
        ENTRY(cr3);
@@ -115,26 +68,11 @@ int main(void)
        ENTRY(cr8);
        BLANK();
 #undef ENTRY
-       DEFINE(TSS_ist, offsetof(struct tss_struct, x86_tss.ist));
-       BLANK();
-       DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx));
-       BLANK();
-       DEFINE(__NR_syscall_max, sizeof(syscalls) - 1);
 
+       OFFSET(TSS_ist, tss_struct, x86_tss.ist);
        BLANK();
-       OFFSET(BP_scratch, boot_params, scratch);
-       OFFSET(BP_loadflags, boot_params, hdr.loadflags);
-       OFFSET(BP_hardware_subarch, boot_params, hdr.hardware_subarch);
-       OFFSET(BP_version, boot_params, hdr.version);
-       OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment);
 
-       BLANK();
-       DEFINE(PAGE_SIZE_asm, PAGE_SIZE);
-#ifdef CONFIG_XEN
-       BLANK();
-       OFFSET(XEN_vcpu_info_mask, vcpu_info, evtchn_upcall_mask);
-       OFFSET(XEN_vcpu_info_pending, vcpu_info, evtchn_upcall_pending);
-#undef ENTRY
-#endif
+       DEFINE(__NR_syscall_max, sizeof(syscalls) - 1);
+
        return 0;
 }
index 13a3891..452932d 100644 (file)
@@ -106,8 +106,8 @@ void __init setup_bios_corruption_check(void)
                addr += size;
        }
 
-       printk(KERN_INFO "Scanning %d areas for low memory corruption\n",
-              num_scan_areas);
+       if (num_scan_areas)
+               printk(KERN_INFO "Scanning %d areas for low memory corruption\n", num_scan_areas);
 }
 
 
@@ -143,12 +143,12 @@ static void check_corruption(struct work_struct *dummy)
 {
        check_for_bios_corruption();
        schedule_delayed_work(&bios_check_work,
-               round_jiffies_relative(corruption_check_period*HZ)); 
+               round_jiffies_relative(corruption_check_period*HZ));
 }
 
 static int start_periodic_check_for_corruption(void)
 {
-       if (!memory_corruption_check || corruption_check_period == 0)
+       if (!num_scan_areas || !memory_corruption_check || corruption_check_period == 0)
                return 0;
 
        printk(KERN_INFO "Scanning for low memory corruption every %d seconds\n",
index 7c7bedb..f771ab6 100644 (file)
@@ -233,18 +233,22 @@ static void __cpuinit init_amd_k7(struct cpuinfo_x86 *c)
 }
 #endif
 
-#if defined(CONFIG_NUMA) && defined(CONFIG_X86_64)
+#ifdef CONFIG_NUMA
+/*
+ * To workaround broken NUMA config.  Read the comment in
+ * srat_detect_node().
+ */
 static int __cpuinit nearby_node(int apicid)
 {
        int i, node;
 
        for (i = apicid - 1; i >= 0; i--) {
-               node = apicid_to_node[i];
+               node = __apicid_to_node[i];
                if (node != NUMA_NO_NODE && node_online(node))
                        return node;
        }
        for (i = apicid + 1; i < MAX_LOCAL_APIC; i++) {
-               node = apicid_to_node[i];
+               node = __apicid_to_node[i];
                if (node != NUMA_NO_NODE && node_online(node))
                        return node;
        }
@@ -261,7 +265,7 @@ static int __cpuinit nearby_node(int apicid)
 #ifdef CONFIG_X86_HT
 static void __cpuinit amd_get_topology(struct cpuinfo_x86 *c)
 {
-       u32 nodes;
+       u32 nodes, cores_per_cu = 1;
        u8 node_id;
        int cpu = smp_processor_id();
 
@@ -276,6 +280,7 @@ static void __cpuinit amd_get_topology(struct cpuinfo_x86 *c)
                /* get compute unit information */
                smp_num_siblings = ((ebx >> 8) & 3) + 1;
                c->compute_unit_id = ebx & 0xff;
+               cores_per_cu += ((ebx >> 8) & 3);
        } else if (cpu_has(c, X86_FEATURE_NODEID_MSR)) {
                u64 value;
 
@@ -288,15 +293,18 @@ static void __cpuinit amd_get_topology(struct cpuinfo_x86 *c)
        /* fixup multi-node processor information */
        if (nodes > 1) {
                u32 cores_per_node;
+               u32 cus_per_node;
 
                set_cpu_cap(c, X86_FEATURE_AMD_DCM);
                cores_per_node = c->x86_max_cores / nodes;
+               cus_per_node = cores_per_node / cores_per_cu;
 
                /* store NodeID, use llc_shared_map to store sibling info */
                per_cpu(cpu_llc_id, cpu) = node_id;
 
-               /* core id to be in range from 0 to (cores_per_node - 1) */
-               c->cpu_core_id = c->cpu_core_id % cores_per_node;
+               /* core id has to be in the [0 .. cores_per_node - 1] range */
+               c->cpu_core_id %= cores_per_node;
+               c->compute_unit_id %= cus_per_node;
        }
 }
 #endif
@@ -334,31 +342,40 @@ EXPORT_SYMBOL_GPL(amd_get_nb_id);
 
 static void __cpuinit srat_detect_node(struct cpuinfo_x86 *c)
 {
-#if defined(CONFIG_NUMA) && defined(CONFIG_X86_64)
+#ifdef CONFIG_NUMA
        int cpu = smp_processor_id();
        int node;
        unsigned apicid = c->apicid;
 
-       node = per_cpu(cpu_llc_id, cpu);
+       node = numa_cpu_node(cpu);
+       if (node == NUMA_NO_NODE)
+               node = per_cpu(cpu_llc_id, cpu);
 
-       if (apicid_to_node[apicid] != NUMA_NO_NODE)
-               node = apicid_to_node[apicid];
        if (!node_online(node)) {
-               /* Two possibilities here:
-                  - The CPU is missing memory and no node was created.
-                  In that case try picking one from a nearby CPU
-                  - The APIC IDs differ from the HyperTransport node IDs
-                  which the K8 northbridge parsing fills in.
-                  Assume they are all increased by a constant offset,
-                  but in the same order as the HT nodeids.
-                  If that doesn't result in a usable node fall back to the
-                  path for the previous case.  */
-
+               /*
+                * Two possibilities here:
+                *
+                * - The CPU is missing memory and no node was created.  In
+                *   that case try picking one from a nearby CPU.
+                *
+                * - The APIC IDs differ from the HyperTransport node IDs
+                *   which the K8 northbridge parsing fills in.  Assume
+                *   they are all increased by a constant offset, but in
+                *   the same order as the HT nodeids.  If that doesn't
+                *   result in a usable node fall back to the path for the
+                *   previous case.
+                *
+                * This workaround operates directly on the mapping between
+                * APIC ID and NUMA node, assuming certain relationship
+                * between APIC ID, HT node ID and NUMA topology.  As going
+                * through CPU mapping may alter the outcome, directly
+                * access __apicid_to_node[].
+                */
                int ht_nodeid = c->initial_apicid;
 
                if (ht_nodeid >= 0 &&
-                   apicid_to_node[ht_nodeid] != NUMA_NO_NODE)
-                       node = apicid_to_node[ht_nodeid];
+                   __apicid_to_node[ht_nodeid] != NUMA_NO_NODE)
+                       node = __apicid_to_node[ht_nodeid];
                /* Pick a nearby node */
                if (!node_online(node))
                        node = nearby_node(apicid);
index 1d59834..e2ced00 100644 (file)
@@ -675,7 +675,7 @@ void __init early_cpu_init(void)
        const struct cpu_dev *const *cdev;
        int count = 0;
 
-#ifdef PROCESSOR_SELECT
+#ifdef CONFIG_PROCESSOR_SELECT
        printk(KERN_INFO "KERNEL supported cpus:\n");
 #endif
 
@@ -687,7 +687,7 @@ void __init early_cpu_init(void)
                cpu_devs[count] = cpudev;
                count++;
 
-#ifdef PROCESSOR_SELECT
+#ifdef CONFIG_PROCESSOR_SELECT
                {
                        unsigned int j;
 
@@ -869,7 +869,7 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
 
        select_idle_routine(c);
 
-#if defined(CONFIG_NUMA) && defined(CONFIG_X86_64)
+#ifdef CONFIG_NUMA
        numa_add_cpu(smp_processor_id());
 #endif
 }
index bd1cac7..52c9364 100644 (file)
@@ -158,9 +158,9 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c)
 {
        if (c->x86 == 0x06) {
                if (cpu_has(c, X86_FEATURE_EST))
-                       printk(KERN_WARNING PFX "Warning: EST-capable CPU "
-                              "detected. The acpi-cpufreq module offers "
-                              "voltage scaling in addition of frequency "
+                       printk_once(KERN_WARNING PFX "Warning: EST-capable "
+                              "CPU detected. The acpi-cpufreq module offers "
+                              "voltage scaling in addition to frequency "
                               "scaling. You should use that instead of "
                               "p4-clockmod, if possible.\n");
                switch (c->x86_model) {
index 4f6f679..4a5a42b 100644 (file)
@@ -195,7 +195,7 @@ static unsigned int pcc_get_freq(unsigned int cpu)
 cmd_incomplete:
        iowrite16(0, &pcch_hdr->status);
        spin_unlock(&pcc_lock);
-       return -EINVAL;
+       return 0;
 }
 
 static int pcc_cpufreq_target(struct cpufreq_policy *policy,
index 35c7e65..c567dec 100644 (file)
@@ -1537,6 +1537,7 @@ static struct notifier_block cpb_nb = {
 static int __cpuinit powernowk8_init(void)
 {
        unsigned int i, supported_cpus = 0, cpu;
+       int rv;
 
        for_each_online_cpu(i) {
                int rc;
@@ -1555,14 +1556,14 @@ static int __cpuinit powernowk8_init(void)
 
                cpb_capable = true;
 
-               register_cpu_notifier(&cpb_nb);
-
                msrs = msrs_alloc();
                if (!msrs) {
                        printk(KERN_ERR "%s: Error allocating msrs!\n", __func__);
                        return -ENOMEM;
                }
 
+               register_cpu_notifier(&cpb_nb);
+
                rdmsr_on_cpus(cpu_online_mask, MSR_K7_HWCR, msrs);
 
                for_each_cpu(cpu, cpu_online_mask) {
@@ -1574,7 +1575,13 @@ static int __cpuinit powernowk8_init(void)
                        (cpb_enabled ? "on" : "off"));
        }
 
-       return cpufreq_register_driver(&cpufreq_amd64_driver);
+       rv = cpufreq_register_driver(&cpufreq_amd64_driver);
+       if (rv < 0 && boot_cpu_has(X86_FEATURE_CPB)) {
+               unregister_cpu_notifier(&cpb_nb);
+               msrs_free(msrs);
+               msrs = NULL;
+       }
+       return rv;
 }
 
 /* driver entry point for term */
index d16c2c5..df86bc8 100644 (file)
@@ -276,14 +276,13 @@ static void __cpuinit intel_workarounds(struct cpuinfo_x86 *c)
 
 static void __cpuinit srat_detect_node(struct cpuinfo_x86 *c)
 {
-#if defined(CONFIG_NUMA) && defined(CONFIG_X86_64)
+#ifdef CONFIG_NUMA
        unsigned node;
        int cpu = smp_processor_id();
-       int apicid = cpu_has_apic ? hard_smp_processor_id() : c->apicid;
 
        /* Don't do the funky fallback heuristics the AMD version employs
           for now. */
-       node = apicid_to_node[apicid];
+       node = numa_cpu_node(cpu);
        if (node == NUMA_NO_NODE || !node_online(node)) {
                /* reuse the value from init_cpu_to_node() */
                node = cpu_to_node(cpu);
index ec2c19a..1ce1af2 100644 (file)
@@ -304,8 +304,9 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
 
 struct _cache_attr {
        struct attribute attr;
-       ssize_t (*show)(struct _cpuid4_info *, char *);
-       ssize_t (*store)(struct _cpuid4_info *, const char *, size_t count);
+       ssize_t (*show)(struct _cpuid4_info *, char *, unsigned int);
+       ssize_t (*store)(struct _cpuid4_info *, const char *, size_t count,
+                        unsigned int);
 };
 
 #ifdef CONFIG_AMD_NB
@@ -400,7 +401,8 @@ static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf,
 
 #define SHOW_CACHE_DISABLE(slot)                                       \
 static ssize_t                                                         \
-show_cache_disable_##slot(struct _cpuid4_info *this_leaf, char *buf)   \
+show_cache_disable_##slot(struct _cpuid4_info *this_leaf, char *buf,   \
+                         unsigned int cpu)                             \
 {                                                                      \
        return show_cache_disable(this_leaf, buf, slot);                \
 }
@@ -512,7 +514,8 @@ static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
 #define STORE_CACHE_DISABLE(slot)                                      \
 static ssize_t                                                         \
 store_cache_disable_##slot(struct _cpuid4_info *this_leaf,             \
-                          const char *buf, size_t count)               \
+                          const char *buf, size_t count,               \
+                          unsigned int cpu)                            \
 {                                                                      \
        return store_cache_disable(this_leaf, buf, count, slot);        \
 }
@@ -524,6 +527,39 @@ static struct _cache_attr cache_disable_0 = __ATTR(cache_disable_0, 0644,
 static struct _cache_attr cache_disable_1 = __ATTR(cache_disable_1, 0644,
                show_cache_disable_1, store_cache_disable_1);
 
+static ssize_t
+show_subcaches(struct _cpuid4_info *this_leaf, char *buf, unsigned int cpu)
+{
+       if (!this_leaf->l3 || !amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
+               return -EINVAL;
+
+       return sprintf(buf, "%x\n", amd_get_subcaches(cpu));
+}
+
+static ssize_t
+store_subcaches(struct _cpuid4_info *this_leaf, const char *buf, size_t count,
+               unsigned int cpu)
+{
+       unsigned long val;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (!this_leaf->l3 || !amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
+               return -EINVAL;
+
+       if (strict_strtoul(buf, 16, &val) < 0)
+               return -EINVAL;
+
+       if (amd_set_subcaches(cpu, val))
+               return -EINVAL;
+
+       return count;
+}
+
+static struct _cache_attr subcaches =
+       __ATTR(subcaches, 0644, show_subcaches, store_subcaches);
+
 #else  /* CONFIG_AMD_NB */
 #define amd_init_l3_cache(x, y)
 #endif /* CONFIG_AMD_NB */
@@ -532,9 +568,9 @@ static int
 __cpuinit cpuid4_cache_lookup_regs(int index,
                                   struct _cpuid4_info_regs *this_leaf)
 {
-       union _cpuid4_leaf_eax  eax;
-       union _cpuid4_leaf_ebx  ebx;
-       union _cpuid4_leaf_ecx  ecx;
+       union _cpuid4_leaf_eax  eax;
+       union _cpuid4_leaf_ebx  ebx;
+       union _cpuid4_leaf_ecx  ecx;
        unsigned                edx;
 
        if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
@@ -732,11 +768,11 @@ static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index)
        struct cpuinfo_x86 *c = &cpu_data(cpu);
 
        if ((index == 3) && (c->x86_vendor == X86_VENDOR_AMD)) {
-               for_each_cpu(i, c->llc_shared_map) {
+               for_each_cpu(i, cpu_llc_shared_mask(cpu)) {
                        if (!per_cpu(ici_cpuid4_info, i))
                                continue;
                        this_leaf = CPUID4_INFO_IDX(i, index);
-                       for_each_cpu(sibling, c->llc_shared_map) {
+                       for_each_cpu(sibling, cpu_llc_shared_mask(cpu)) {
                                if (!cpu_online(sibling))
                                        continue;
                                set_bit(sibling, this_leaf->shared_cpu_map);
@@ -870,8 +906,8 @@ static DEFINE_PER_CPU(struct _index_kobject *, ici_index_kobject);
 #define INDEX_KOBJECT_PTR(x, y)                (&((per_cpu(ici_index_kobject, x))[y]))
 
 #define show_one_plus(file_name, object, val)                          \
-static ssize_t show_##file_name                                                \
-                       (struct _cpuid4_info *this_leaf, char *buf)     \
+static ssize_t show_##file_name(struct _cpuid4_info *this_leaf, char *buf, \
+                               unsigned int cpu)                       \
 {                                                                      \
        return sprintf(buf, "%lu\n", (unsigned long)this_leaf->object + val); \
 }
@@ -882,7 +918,8 @@ show_one_plus(physical_line_partition, ebx.split.physical_line_partition, 1);
 show_one_plus(ways_of_associativity, ebx.split.ways_of_associativity, 1);
 show_one_plus(number_of_sets, ecx.split.number_of_sets, 1);
 
-static ssize_t show_size(struct _cpuid4_info *this_leaf, char *buf)
+static ssize_t show_size(struct _cpuid4_info *this_leaf, char *buf,
+                        unsigned int cpu)
 {
        return sprintf(buf, "%luK\n", this_leaf->size / 1024);
 }
@@ -906,17 +943,20 @@ static ssize_t show_shared_cpu_map_func(struct _cpuid4_info *this_leaf,
        return n;
 }
 
-static inline ssize_t show_shared_cpu_map(struct _cpuid4_info *leaf, char *buf)
+static inline ssize_t show_shared_cpu_map(struct _cpuid4_info *leaf, char *buf,
+                                         unsigned int cpu)
 {
        return show_shared_cpu_map_func(leaf, 0, buf);
 }
 
-static inline ssize_t show_shared_cpu_list(struct _cpuid4_info *leaf, char *buf)
+static inline ssize_t show_shared_cpu_list(struct _cpuid4_info *leaf, char *buf,
+                                          unsigned int cpu)
 {
        return show_shared_cpu_map_func(leaf, 1, buf);
 }
 
-static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf)
+static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf,
+                        unsigned int cpu)
 {
        switch (this_leaf->eax.split.type) {
        case CACHE_TYPE_DATA:
@@ -974,6 +1014,9 @@ static struct attribute ** __cpuinit amd_l3_attrs(void)
        if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
                n += 2;
 
+       if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
+               n += 1;
+
        attrs = kzalloc(n * sizeof (struct attribute *), GFP_KERNEL);
        if (attrs == NULL)
                return attrs = default_attrs;
@@ -986,6 +1029,9 @@ static struct attribute ** __cpuinit amd_l3_attrs(void)
                attrs[n++] = &cache_disable_1.attr;
        }
 
+       if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
+               attrs[n++] = &subcaches.attr;
+
        return attrs;
 }
 #endif
@@ -998,7 +1044,7 @@ static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
 
        ret = fattr->show ?
                fattr->show(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
-                       buf) :
+                       buf, this_leaf->cpu) :
                0;
        return ret;
 }
@@ -1012,7 +1058,7 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
 
        ret = fattr->store ?
                fattr->store(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
-                       buf, count) :
+                       buf, count, this_leaf->cpu) :
                0;
        return ret;
 }
index 5bf2fac..167f97b 100644 (file)
@@ -527,15 +527,12 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
        int i, err = 0;
        struct threshold_bank *b = NULL;
        char name[32];
-#ifdef CONFIG_SMP
-       struct cpuinfo_x86 *c = &cpu_data(cpu);
-#endif
 
        sprintf(name, "threshold_bank%i", bank);
 
 #ifdef CONFIG_SMP
        if (cpu_data(cpu).cpu_core_id && shared_bank[bank]) {   /* symlink */
-               i = cpumask_first(c->llc_shared_map);
+               i = cpumask_first(cpu_llc_shared_mask(cpu));
 
                /* first core not up yet */
                if (cpu_data(i).cpu_core_id)
@@ -555,7 +552,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
                if (err)
                        goto out;
 
-               cpumask_copy(b->cpus, c->llc_shared_map);
+               cpumask_copy(b->cpus, cpu_llc_shared_mask(cpu));
                per_cpu(threshold_banks, cpu)[bank] = b;
 
                goto out;
index 01c0f3e..bebabec 100644 (file)
@@ -793,13 +793,21 @@ void set_mtrr_aps_delayed_init(void)
 }
 
 /*
- * MTRR initialization for all AP's
+ * Delayed MTRR initialization for all AP's
  */
 void mtrr_aps_init(void)
 {
        if (!use_intel())
                return;
 
+       /*
+        * Check if someone has requested the delay of AP MTRR initialization,
+        * by doing set_mtrr_aps_delayed_init(), prior to this point. If not,
+        * then we are done.
+        */
+       if (!mtrr_aps_delayed_init)
+               return;
+
        set_mtrr(~0U, 0, 0, 0);
        mtrr_aps_delayed_init = false;
 }
index 9d977a2..2660418 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/stacktrace.h>
 #include <asm/nmi.h>
 #include <asm/compat.h>
+#include <asm/smp.h>
 
 #if 0
 #undef wrmsrl
@@ -93,6 +94,8 @@ struct amd_nb {
        struct event_constraint event_constraints[X86_PMC_IDX_MAX];
 };
 
+struct intel_percore;
+
 #define MAX_LBR_ENTRIES                16
 
 struct cpu_hw_events {
@@ -127,6 +130,13 @@ struct cpu_hw_events {
        struct perf_branch_stack        lbr_stack;
        struct perf_branch_entry        lbr_entries[MAX_LBR_ENTRIES];
 
+       /*
+        * Intel percore register state.
+        * Coordinate shared resources between HT threads.
+        */
+       int                             percore_used; /* Used by this CPU? */
+       struct intel_percore            *per_core;
+
        /*
         * AMD specific bits
         */
@@ -166,8 +176,10 @@ struct cpu_hw_events {
 /*
  * Constraint on the Event code + UMask
  */
-#define PEBS_EVENT_CONSTRAINT(c, n)    \
+#define INTEL_UEVENT_CONSTRAINT(c, n)  \
        EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK)
+#define PEBS_EVENT_CONSTRAINT(c, n)    \
+       INTEL_UEVENT_CONSTRAINT(c, n)
 
 #define EVENT_CONSTRAINT_END           \
        EVENT_CONSTRAINT(0, 0, 0)
@@ -175,6 +187,28 @@ struct cpu_hw_events {
 #define for_each_event_constraint(e, c)        \
        for ((e) = (c); (e)->weight; (e)++)
 
+/*
+ * Extra registers for specific events.
+ * Some events need large masks and require external MSRs.
+ * Define a mapping to these extra registers.
+ */
+struct extra_reg {
+       unsigned int            event;
+       unsigned int            msr;
+       u64                     config_mask;
+       u64                     valid_mask;
+};
+
+#define EVENT_EXTRA_REG(e, ms, m, vm) {        \
+       .event = (e),           \
+       .msr = (ms),            \
+       .config_mask = (m),     \
+       .valid_mask = (vm),     \
+       }
+#define INTEL_EVENT_EXTRA_REG(event, msr, vm)  \
+       EVENT_EXTRA_REG(event, msr, ARCH_PERFMON_EVENTSEL_EVENT, vm)
+#define EVENT_EXTRA_END EVENT_EXTRA_REG(0, 0, 0, 0)
+
 union perf_capabilities {
        struct {
                u64     lbr_format    : 6;
@@ -219,6 +253,7 @@ struct x86_pmu {
        void            (*put_event_constraints)(struct cpu_hw_events *cpuc,
                                                 struct perf_event *event);
        struct event_constraint *event_constraints;
+       struct event_constraint *percore_constraints;
        void            (*quirks)(void);
        int             perfctr_second_write;
 
@@ -247,6 +282,11 @@ struct x86_pmu {
         */
        unsigned long   lbr_tos, lbr_from, lbr_to; /* MSR base regs       */
        int             lbr_nr;                    /* hardware stack size */
+
+       /*
+        * Extra registers for events
+        */
+       struct extra_reg *extra_regs;
 };
 
 static struct x86_pmu x86_pmu __read_mostly;
@@ -271,6 +311,10 @@ static u64 __read_mostly hw_cache_event_ids
                                [PERF_COUNT_HW_CACHE_MAX]
                                [PERF_COUNT_HW_CACHE_OP_MAX]
                                [PERF_COUNT_HW_CACHE_RESULT_MAX];
+static u64 __read_mostly hw_cache_extra_regs
+                               [PERF_COUNT_HW_CACHE_MAX]
+                               [PERF_COUNT_HW_CACHE_OP_MAX]
+                               [PERF_COUNT_HW_CACHE_RESULT_MAX];
 
 /*
  * Propagate event elapsed time into the generic event.
@@ -298,7 +342,7 @@ x86_perf_event_update(struct perf_event *event)
         */
 again:
        prev_raw_count = local64_read(&hwc->prev_count);
-       rdmsrl(hwc->event_base + idx, new_raw_count);
+       rdmsrl(hwc->event_base, new_raw_count);
 
        if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
                                        new_raw_count) != prev_raw_count)
@@ -321,6 +365,49 @@ again:
        return new_raw_count;
 }
 
+/* using X86_FEATURE_PERFCTR_CORE to later implement ALTERNATIVE() here */
+static inline int x86_pmu_addr_offset(int index)
+{
+       if (boot_cpu_has(X86_FEATURE_PERFCTR_CORE))
+               return index << 1;
+       return index;
+}
+
+static inline unsigned int x86_pmu_config_addr(int index)
+{
+       return x86_pmu.eventsel + x86_pmu_addr_offset(index);
+}
+
+static inline unsigned int x86_pmu_event_addr(int index)
+{
+       return x86_pmu.perfctr + x86_pmu_addr_offset(index);
+}
+
+/*
+ * Find and validate any extra registers to set up.
+ */
+static int x86_pmu_extra_regs(u64 config, struct perf_event *event)
+{
+       struct extra_reg *er;
+
+       event->hw.extra_reg = 0;
+       event->hw.extra_config = 0;
+
+       if (!x86_pmu.extra_regs)
+               return 0;
+
+       for (er = x86_pmu.extra_regs; er->msr; er++) {
+               if (er->event != (config & er->config_mask))
+                       continue;
+               if (event->attr.config1 & ~er->valid_mask)
+                       return -EINVAL;
+               event->hw.extra_reg = er->msr;
+               event->hw.extra_config = event->attr.config1;
+               break;
+       }
+       return 0;
+}
+
 static atomic_t active_events;
 static DEFINE_MUTEX(pmc_reserve_mutex);
 
@@ -331,12 +418,12 @@ static bool reserve_pmc_hardware(void)
        int i;
 
        for (i = 0; i < x86_pmu.num_counters; i++) {
-               if (!reserve_perfctr_nmi(x86_pmu.perfctr + i))
+               if (!reserve_perfctr_nmi(x86_pmu_event_addr(i)))
                        goto perfctr_fail;
        }
 
        for (i = 0; i < x86_pmu.num_counters; i++) {
-               if (!reserve_evntsel_nmi(x86_pmu.eventsel + i))
+               if (!reserve_evntsel_nmi(x86_pmu_config_addr(i)))
                        goto eventsel_fail;
        }
 
@@ -344,13 +431,13 @@ static bool reserve_pmc_hardware(void)
 
 eventsel_fail:
        for (i--; i >= 0; i--)
-               release_evntsel_nmi(x86_pmu.eventsel + i);
+               release_evntsel_nmi(x86_pmu_config_addr(i));
 
        i = x86_pmu.num_counters;
 
 perfctr_fail:
        for (i--; i >= 0; i--)
-               release_perfctr_nmi(x86_pmu.perfctr + i);
+               release_perfctr_nmi(x86_pmu_event_addr(i));
 
        return false;
 }
@@ -360,8 +447,8 @@ static void release_pmc_hardware(void)
        int i;
 
        for (i = 0; i < x86_pmu.num_counters; i++) {
-               release_perfctr_nmi(x86_pmu.perfctr + i);
-               release_evntsel_nmi(x86_pmu.eventsel + i);
+               release_perfctr_nmi(x86_pmu_event_addr(i));
+               release_evntsel_nmi(x86_pmu_config_addr(i));
        }
 }
 
@@ -382,7 +469,7 @@ static bool check_hw_exists(void)
         * complain and bail.
         */
        for (i = 0; i < x86_pmu.num_counters; i++) {
-               reg = x86_pmu.eventsel + i;
+               reg = x86_pmu_config_addr(i);
                ret = rdmsrl_safe(reg, &val);
                if (ret)
                        goto msr_fail;
@@ -407,8 +494,8 @@ static bool check_hw_exists(void)
         * that don't trap on the MSR access and always return 0s.
         */
        val = 0xabcdUL;
-       ret = checking_wrmsrl(x86_pmu.perfctr, val);
-       ret |= rdmsrl_safe(x86_pmu.perfctr, &val_new);
+       ret = checking_wrmsrl(x86_pmu_event_addr(0), val);
+       ret |= rdmsrl_safe(x86_pmu_event_addr(0), &val_new);
        if (ret || val != val_new)
                goto msr_fail;
 
@@ -442,8 +529,9 @@ static inline int x86_pmu_initialized(void)
 }
 
 static inline int
-set_ext_hw_attr(struct hw_perf_event *hwc, struct perf_event_attr *attr)
+set_ext_hw_attr(struct hw_perf_event *hwc, struct perf_event *event)
 {
+       struct perf_event_attr *attr = &event->attr;
        unsigned int cache_type, cache_op, cache_result;
        u64 config, val;
 
@@ -470,8 +558,8 @@ set_ext_hw_attr(struct hw_perf_event *hwc, struct perf_event_attr *attr)
                return -EINVAL;
 
        hwc->config |= val;
-
-       return 0;
+       attr->config1 = hw_cache_extra_regs[cache_type][cache_op][cache_result];
+       return x86_pmu_extra_regs(val, event);
 }
 
 static int x86_setup_perfctr(struct perf_event *event)
@@ -496,10 +584,10 @@ static int x86_setup_perfctr(struct perf_event *event)
        }
 
        if (attr->type == PERF_TYPE_RAW)
-               return 0;
+               return x86_pmu_extra_regs(event->attr.config, event);
 
        if (attr->type == PERF_TYPE_HW_CACHE)
-               return set_ext_hw_attr(hwc, attr);
+               return set_ext_hw_attr(hwc, event);
 
        if (attr->config >= x86_pmu.max_events)
                return -EINVAL;
@@ -617,11 +705,11 @@ static void x86_pmu_disable_all(void)
 
                if (!test_bit(idx, cpuc->active_mask))
                        continue;
-               rdmsrl(x86_pmu.eventsel + idx, val);
+               rdmsrl(x86_pmu_config_addr(idx), val);
                if (!(val & ARCH_PERFMON_EVENTSEL_ENABLE))
                        continue;
                val &= ~ARCH_PERFMON_EVENTSEL_ENABLE;
-               wrmsrl(x86_pmu.eventsel + idx, val);
+               wrmsrl(x86_pmu_config_addr(idx), val);
        }
 }
 
@@ -642,21 +730,26 @@ static void x86_pmu_disable(struct pmu *pmu)
        x86_pmu.disable_all();
 }
 
+static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc,
+                                         u64 enable_mask)
+{
+       if (hwc->extra_reg)
+               wrmsrl(hwc->extra_reg, hwc->extra_config);
+       wrmsrl(hwc->config_base, hwc->config | enable_mask);
+}
+
 static void x86_pmu_enable_all(int added)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        int idx;
 
        for (idx = 0; idx < x86_pmu.num_counters; idx++) {
-               struct perf_event *event = cpuc->events[idx];
-               u64 val;
+               struct hw_perf_event *hwc = &cpuc->events[idx]->hw;
 
                if (!test_bit(idx, cpuc->active_mask))
                        continue;
 
-               val = event->hw.config;
-               val |= ARCH_PERFMON_EVENTSEL_ENABLE;
-               wrmsrl(x86_pmu.eventsel + idx, val);
+               __x86_pmu_enable_event(hwc, ARCH_PERFMON_EVENTSEL_ENABLE);
        }
 }
 
@@ -821,15 +914,10 @@ static inline void x86_assign_hw_event(struct perf_event *event,
                hwc->event_base = 0;
        } else if (hwc->idx >= X86_PMC_IDX_FIXED) {
                hwc->config_base = MSR_ARCH_PERFMON_FIXED_CTR_CTRL;
-               /*
-                * We set it so that event_base + idx in wrmsr/rdmsr maps to
-                * MSR_ARCH_PERFMON_FIXED_CTR0 ... CTR2:
-                */
-               hwc->event_base =
-                       MSR_ARCH_PERFMON_FIXED_CTR0 - X86_PMC_IDX_FIXED;
+               hwc->event_base = MSR_ARCH_PERFMON_FIXED_CTR0;
        } else {
-               hwc->config_base = x86_pmu.eventsel;
-               hwc->event_base  = x86_pmu.perfctr;
+               hwc->config_base = x86_pmu_config_addr(hwc->idx);
+               hwc->event_base  = x86_pmu_event_addr(hwc->idx);
        }
 }
 
@@ -915,17 +1003,11 @@ static void x86_pmu_enable(struct pmu *pmu)
        x86_pmu.enable_all(added);
 }
 
-static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc,
-                                         u64 enable_mask)
-{
-       wrmsrl(hwc->config_base + hwc->idx, hwc->config | enable_mask);
-}
-
 static inline void x86_pmu_disable_event(struct perf_event *event)
 {
        struct hw_perf_event *hwc = &event->hw;
 
-       wrmsrl(hwc->config_base + hwc->idx, hwc->config);
+       wrmsrl(hwc->config_base, hwc->config);
 }
 
 static DEFINE_PER_CPU(u64 [X86_PMC_IDX_MAX], pmc_prev_left);
@@ -978,7 +1060,7 @@ x86_perf_event_set_period(struct perf_event *event)
         */
        local64_set(&hwc->prev_count, (u64)-left);
 
-       wrmsrl(hwc->event_base + idx, (u64)(-left) & x86_pmu.cntval_mask);
+       wrmsrl(hwc->event_base, (u64)(-left) & x86_pmu.cntval_mask);
 
        /*
         * Due to erratum on certan cpu we need
@@ -986,7 +1068,7 @@ x86_perf_event_set_period(struct perf_event *event)
         * is updated properly
         */
        if (x86_pmu.perfctr_second_write) {
-               wrmsrl(hwc->event_base + idx,
+               wrmsrl(hwc->event_base,
                        (u64)(-left) & x86_pmu.cntval_mask);
        }
 
@@ -1113,8 +1195,8 @@ void perf_event_print_debug(void)
        pr_info("CPU#%d: active:     %016llx\n", cpu, *(u64 *)cpuc->active_mask);
 
        for (idx = 0; idx < x86_pmu.num_counters; idx++) {
-               rdmsrl(x86_pmu.eventsel + idx, pmc_ctrl);
-               rdmsrl(x86_pmu.perfctr  + idx, pmc_count);
+               rdmsrl(x86_pmu_config_addr(idx), pmc_ctrl);
+               rdmsrl(x86_pmu_event_addr(idx), pmc_count);
 
                prev_left = per_cpu(pmc_prev_left[idx], cpu);
 
@@ -1389,7 +1471,7 @@ static void __init pmu_check_apic(void)
        pr_info("no hardware sampling interrupt available.\n");
 }
 
-int __init init_hw_perf_events(void)
+static int __init init_hw_perf_events(void)
 {
        struct event_constraint *c;
        int err;
@@ -1608,7 +1690,7 @@ out:
        return ret;
 }
 
-int x86_pmu_event_init(struct perf_event *event)
+static int x86_pmu_event_init(struct perf_event *event)
 {
        struct pmu *tmp;
        int err;
index 67e2202..461f62b 100644 (file)
@@ -127,6 +127,11 @@ static int amd_pmu_hw_config(struct perf_event *event)
 /*
  * AMD64 events are detected based on their event codes.
  */
+static inline unsigned int amd_get_event_code(struct hw_perf_event *hwc)
+{
+       return ((hwc->config >> 24) & 0x0f00) | (hwc->config & 0x00ff);
+}
+
 static inline int amd_is_nb_event(struct hw_perf_event *hwc)
 {
        return (hwc->config & 0xe0) == 0xe0;
@@ -385,13 +390,181 @@ static __initconst const struct x86_pmu amd_pmu = {
        .cpu_dead               = amd_pmu_cpu_dead,
 };
 
+/* AMD Family 15h */
+
+#define AMD_EVENT_TYPE_MASK    0x000000F0ULL
+
+#define AMD_EVENT_FP           0x00000000ULL ... 0x00000010ULL
+#define AMD_EVENT_LS           0x00000020ULL ... 0x00000030ULL
+#define AMD_EVENT_DC           0x00000040ULL ... 0x00000050ULL
+#define AMD_EVENT_CU           0x00000060ULL ... 0x00000070ULL
+#define AMD_EVENT_IC_DE                0x00000080ULL ... 0x00000090ULL
+#define AMD_EVENT_EX_LS                0x000000C0ULL
+#define AMD_EVENT_DE           0x000000D0ULL
+#define AMD_EVENT_NB           0x000000E0ULL ... 0x000000F0ULL
+
+/*
+ * AMD family 15h event code/PMC mappings:
+ *
+ * type = event_code & 0x0F0:
+ *
+ * 0x000       FP      PERF_CTL[5:3]
+ * 0x010       FP      PERF_CTL[5:3]
+ * 0x020       LS      PERF_CTL[5:0]
+ * 0x030       LS      PERF_CTL[5:0]
+ * 0x040       DC      PERF_CTL[5:0]
+ * 0x050       DC      PERF_CTL[5:0]
+ * 0x060       CU      PERF_CTL[2:0]
+ * 0x070       CU      PERF_CTL[2:0]
+ * 0x080       IC/DE   PERF_CTL[2:0]
+ * 0x090       IC/DE   PERF_CTL[2:0]
+ * 0x0A0       ---
+ * 0x0B0       ---
+ * 0x0C0       EX/LS   PERF_CTL[5:0]
+ * 0x0D0       DE      PERF_CTL[2:0]
+ * 0x0E0       NB      NB_PERF_CTL[3:0]
+ * 0x0F0       NB      NB_PERF_CTL[3:0]
+ *
+ * Exceptions:
+ *
+ * 0x003       FP      PERF_CTL[3]
+ * 0x00B       FP      PERF_CTL[3]
+ * 0x00D       FP      PERF_CTL[3]
+ * 0x023       DE      PERF_CTL[2:0]
+ * 0x02D       LS      PERF_CTL[3]
+ * 0x02E       LS      PERF_CTL[3,0]
+ * 0x043       CU      PERF_CTL[2:0]
+ * 0x045       CU      PERF_CTL[2:0]
+ * 0x046       CU      PERF_CTL[2:0]
+ * 0x054       CU      PERF_CTL[2:0]
+ * 0x055       CU      PERF_CTL[2:0]
+ * 0x08F       IC      PERF_CTL[0]
+ * 0x187       DE      PERF_CTL[0]
+ * 0x188       DE      PERF_CTL[0]
+ * 0x0DB       EX      PERF_CTL[5:0]
+ * 0x0DC       LS      PERF_CTL[5:0]
+ * 0x0DD       LS      PERF_CTL[5:0]
+ * 0x0DE       LS      PERF_CTL[5:0]
+ * 0x0DF       LS      PERF_CTL[5:0]
+ * 0x1D6       EX      PERF_CTL[5:0]
+ * 0x1D8       EX      PERF_CTL[5:0]
+ */
+
+static struct event_constraint amd_f15_PMC0  = EVENT_CONSTRAINT(0, 0x01, 0);
+static struct event_constraint amd_f15_PMC20 = EVENT_CONSTRAINT(0, 0x07, 0);
+static struct event_constraint amd_f15_PMC3  = EVENT_CONSTRAINT(0, 0x08, 0);
+static struct event_constraint amd_f15_PMC30 = EVENT_CONSTRAINT(0, 0x09, 0);
+static struct event_constraint amd_f15_PMC50 = EVENT_CONSTRAINT(0, 0x3F, 0);
+static struct event_constraint amd_f15_PMC53 = EVENT_CONSTRAINT(0, 0x38, 0);
+
+static struct event_constraint *
+amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, struct perf_event *event)
+{
+       unsigned int event_code = amd_get_event_code(&event->hw);
+
+       switch (event_code & AMD_EVENT_TYPE_MASK) {
+       case AMD_EVENT_FP:
+               switch (event_code) {
+               case 0x003:
+               case 0x00B:
+               case 0x00D:
+                       return &amd_f15_PMC3;
+               default:
+                       return &amd_f15_PMC53;
+               }
+       case AMD_EVENT_LS:
+       case AMD_EVENT_DC:
+       case AMD_EVENT_EX_LS:
+               switch (event_code) {
+               case 0x023:
+               case 0x043:
+               case 0x045:
+               case 0x046:
+               case 0x054:
+               case 0x055:
+                       return &amd_f15_PMC20;
+               case 0x02D:
+                       return &amd_f15_PMC3;
+               case 0x02E:
+                       return &amd_f15_PMC30;
+               default:
+                       return &amd_f15_PMC50;
+               }
+       case AMD_EVENT_CU:
+       case AMD_EVENT_IC_DE:
+       case AMD_EVENT_DE:
+               switch (event_code) {
+               case 0x08F:
+               case 0x187:
+               case 0x188:
+                       return &amd_f15_PMC0;
+               case 0x0DB ... 0x0DF:
+               case 0x1D6:
+               case 0x1D8:
+                       return &amd_f15_PMC50;
+               default:
+                       return &amd_f15_PMC20;
+               }
+       case AMD_EVENT_NB:
+               /* not yet implemented */
+               return &emptyconstraint;
+       default:
+               return &emptyconstraint;
+       }
+}
+
+static __initconst const struct x86_pmu amd_pmu_f15h = {
+       .name                   = "AMD Family 15h",
+       .handle_irq             = x86_pmu_handle_irq,
+       .disable_all            = x86_pmu_disable_all,
+       .enable_all             = x86_pmu_enable_all,
+       .enable                 = x86_pmu_enable_event,
+       .disable                = x86_pmu_disable_event,
+       .hw_config              = amd_pmu_hw_config,
+       .schedule_events        = x86_schedule_events,
+       .eventsel               = MSR_F15H_PERF_CTL,
+       .perfctr                = MSR_F15H_PERF_CTR,
+       .event_map              = amd_pmu_event_map,
+       .max_events             = ARRAY_SIZE(amd_perfmon_event_map),
+       .num_counters           = 6,
+       .cntval_bits            = 48,
+       .cntval_mask            = (1ULL << 48) - 1,
+       .apic                   = 1,
+       /* use highest bit to detect overflow */
+       .max_period             = (1ULL << 47) - 1,
+       .get_event_constraints  = amd_get_event_constraints_f15h,
+       /* nortbridge counters not yet implemented: */
+#if 0
+       .put_event_constraints  = amd_put_event_constraints,
+
+       .cpu_prepare            = amd_pmu_cpu_prepare,
+       .cpu_starting           = amd_pmu_cpu_starting,
+       .cpu_dead               = amd_pmu_cpu_dead,
+#endif
+};
+
 static __init int amd_pmu_init(void)
 {
        /* Performance-monitoring supported from K7 and later: */
        if (boot_cpu_data.x86 < 6)
                return -ENODEV;
 
-       x86_pmu = amd_pmu;
+       /*
+        * If core performance counter extensions exists, it must be
+        * family 15h, otherwise fail. See x86_pmu_addr_offset().
+        */
+       switch (boot_cpu_data.x86) {
+       case 0x15:
+               if (!cpu_has_perfctr_core)
+                       return -ENODEV;
+               x86_pmu = amd_pmu_f15h;
+               break;
+       default:
+               if (cpu_has_perfctr_core)
+                       return -ENODEV;
+               x86_pmu = amd_pmu;
+               break;
+       }
 
        /* Events are common for all AMDs */
        memcpy(hw_cache_event_ids, amd_hw_cache_event_ids,
index 008835c..8fc2b2c 100644 (file)
@@ -1,5 +1,27 @@
 #ifdef CONFIG_CPU_SUP_INTEL
 
+#define MAX_EXTRA_REGS 2
+
+/*
+ * Per register state.
+ */
+struct er_account {
+       int                     ref;            /* reference count */
+       unsigned int            extra_reg;      /* extra MSR number */
+       u64                     extra_config;   /* extra MSR config */
+};
+
+/*
+ * Per core state
+ * This used to coordinate shared registers for HT threads.
+ */
+struct intel_percore {
+       raw_spinlock_t          lock;           /* protect structure */
+       struct er_account       regs[MAX_EXTRA_REGS];
+       int                     refcnt;         /* number of threads */
+       unsigned                core_id;
+};
+
 /*
  * Intel PerfMon, used on Core and later.
  */
@@ -64,6 +86,18 @@ static struct event_constraint intel_nehalem_event_constraints[] =
        EVENT_CONSTRAINT_END
 };
 
+static struct extra_reg intel_nehalem_extra_regs[] =
+{
+       INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0xffff),
+       EVENT_EXTRA_END
+};
+
+static struct event_constraint intel_nehalem_percore_constraints[] =
+{
+       INTEL_EVENT_CONSTRAINT(0xb7, 0),
+       EVENT_CONSTRAINT_END
+};
+
 static struct event_constraint intel_westmere_event_constraints[] =
 {
        FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
@@ -76,6 +110,33 @@ static struct event_constraint intel_westmere_event_constraints[] =
        EVENT_CONSTRAINT_END
 };
 
+static struct event_constraint intel_snb_event_constraints[] =
+{
+       FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
+       FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
+       /* FIXED_EVENT_CONSTRAINT(0x013c, 2), CPU_CLK_UNHALTED.REF */
+       INTEL_EVENT_CONSTRAINT(0x48, 0x4), /* L1D_PEND_MISS.PENDING */
+       INTEL_EVENT_CONSTRAINT(0xb7, 0x1), /* OFF_CORE_RESPONSE_0 */
+       INTEL_EVENT_CONSTRAINT(0xbb, 0x8), /* OFF_CORE_RESPONSE_1 */
+       INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PREC_DIST */
+       INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.LOAD_LATENCY */
+       EVENT_CONSTRAINT_END
+};
+
+static struct extra_reg intel_westmere_extra_regs[] =
+{
+       INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0xffff),
+       INTEL_EVENT_EXTRA_REG(0xbb, MSR_OFFCORE_RSP_1, 0xffff),
+       EVENT_EXTRA_END
+};
+
+static struct event_constraint intel_westmere_percore_constraints[] =
+{
+       INTEL_EVENT_CONSTRAINT(0xb7, 0),
+       INTEL_EVENT_CONSTRAINT(0xbb, 0),
+       EVENT_CONSTRAINT_END
+};
+
 static struct event_constraint intel_gen_event_constraints[] =
 {
        FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
@@ -89,6 +150,106 @@ static u64 intel_pmu_event_map(int hw_event)
        return intel_perfmon_event_map[hw_event];
 }
 
+static __initconst const u64 snb_hw_cache_event_ids
+                               [PERF_COUNT_HW_CACHE_MAX]
+                               [PERF_COUNT_HW_CACHE_OP_MAX]
+                               [PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(L1D) ] = {
+       [ C(OP_READ) ] = {
+               [ C(RESULT_ACCESS) ] = 0xf1d0, /* MEM_UOP_RETIRED.LOADS        */
+               [ C(RESULT_MISS)   ] = 0x0151, /* L1D.REPLACEMENT              */
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = 0xf2d0, /* MEM_UOP_RETIRED.STORES       */
+               [ C(RESULT_MISS)   ] = 0x0851, /* L1D.ALL_M_REPLACEMENT        */
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = 0x0,
+               [ C(RESULT_MISS)   ] = 0x024e, /* HW_PRE_REQ.DL1_MISS          */
+       },
+ },
+ [ C(L1I ) ] = {
+       [ C(OP_READ) ] = {
+               [ C(RESULT_ACCESS) ] = 0x0,
+               [ C(RESULT_MISS)   ] = 0x0280, /* ICACHE.MISSES */
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = -1,
+               [ C(RESULT_MISS)   ] = -1,
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = 0x0,
+               [ C(RESULT_MISS)   ] = 0x0,
+       },
+ },
+ [ C(LL  ) ] = {
+       /*
+        * TBD: Need Off-core Response Performance Monitoring support
+        */
+       [ C(OP_READ) ] = {
+               /* OFFCORE_RESPONSE_0.ANY_DATA.LOCAL_CACHE */
+               [ C(RESULT_ACCESS) ] = 0x01b7,
+               /* OFFCORE_RESPONSE_1.ANY_DATA.ANY_LLC_MISS */
+               [ C(RESULT_MISS)   ] = 0x01bb,
+       },
+       [ C(OP_WRITE) ] = {
+               /* OFFCORE_RESPONSE_0.ANY_RFO.LOCAL_CACHE */
+               [ C(RESULT_ACCESS) ] = 0x01b7,
+               /* OFFCORE_RESPONSE_1.ANY_RFO.ANY_LLC_MISS */
+               [ C(RESULT_MISS)   ] = 0x01bb,
+       },
+       [ C(OP_PREFETCH) ] = {
+               /* OFFCORE_RESPONSE_0.PREFETCH.LOCAL_CACHE */
+               [ C(RESULT_ACCESS) ] = 0x01b7,
+               /* OFFCORE_RESPONSE_1.PREFETCH.ANY_LLC_MISS */
+               [ C(RESULT_MISS)   ] = 0x01bb,
+       },
+ },
+ [ C(DTLB) ] = {
+       [ C(OP_READ) ] = {
+               [ C(RESULT_ACCESS) ] = 0x81d0, /* MEM_UOP_RETIRED.ALL_LOADS */
+               [ C(RESULT_MISS)   ] = 0x0108, /* DTLB_LOAD_MISSES.CAUSES_A_WALK */
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = 0x82d0, /* MEM_UOP_RETIRED.ALL_STORES */
+               [ C(RESULT_MISS)   ] = 0x0149, /* DTLB_STORE_MISSES.MISS_CAUSES_A_WALK */
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = 0x0,
+               [ C(RESULT_MISS)   ] = 0x0,
+       },
+ },
+ [ C(ITLB) ] = {
+       [ C(OP_READ) ] = {
+               [ C(RESULT_ACCESS) ] = 0x1085, /* ITLB_MISSES.STLB_HIT         */
+               [ C(RESULT_MISS)   ] = 0x0185, /* ITLB_MISSES.CAUSES_A_WALK    */
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = -1,
+               [ C(RESULT_MISS)   ] = -1,
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = -1,
+               [ C(RESULT_MISS)   ] = -1,
+       },
+ },
+ [ C(BPU ) ] = {
+       [ C(OP_READ) ] = {
+               [ C(RESULT_ACCESS) ] = 0x00c4, /* BR_INST_RETIRED.ALL_BRANCHES */
+               [ C(RESULT_MISS)   ] = 0x00c5, /* BR_MISP_RETIRED.ALL_BRANCHES */
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = -1,
+               [ C(RESULT_MISS)   ] = -1,
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = -1,
+               [ C(RESULT_MISS)   ] = -1,
+       },
+ },
+};
+
 static __initconst const u64 westmere_hw_cache_event_ids
                                [PERF_COUNT_HW_CACHE_MAX]
                                [PERF_COUNT_HW_CACHE_OP_MAX]
@@ -124,16 +285,26 @@ static __initconst const u64 westmere_hw_cache_event_ids
  },
  [ C(LL  ) ] = {
        [ C(OP_READ) ] = {
-               [ C(RESULT_ACCESS) ] = 0x0324, /* L2_RQSTS.LOADS               */
-               [ C(RESULT_MISS)   ] = 0x0224, /* L2_RQSTS.LD_MISS             */
+               /* OFFCORE_RESPONSE_0.ANY_DATA.LOCAL_CACHE */
+               [ C(RESULT_ACCESS) ] = 0x01b7,
+               /* OFFCORE_RESPONSE_1.ANY_DATA.ANY_LLC_MISS */
+               [ C(RESULT_MISS)   ] = 0x01bb,
        },
+       /*
+        * Use RFO, not WRITEBACK, because a write miss would typically occur
+        * on RFO.
+        */
        [ C(OP_WRITE) ] = {
-               [ C(RESULT_ACCESS) ] = 0x0c24, /* L2_RQSTS.RFOS                */
-               [ C(RESULT_MISS)   ] = 0x0824, /* L2_RQSTS.RFO_MISS            */
+               /* OFFCORE_RESPONSE_1.ANY_RFO.LOCAL_CACHE */
+               [ C(RESULT_ACCESS) ] = 0x01bb,
+               /* OFFCORE_RESPONSE_0.ANY_RFO.ANY_LLC_MISS */
+               [ C(RESULT_MISS)   ] = 0x01b7,
        },
        [ C(OP_PREFETCH) ] = {
-               [ C(RESULT_ACCESS) ] = 0x4f2e, /* LLC Reference                */
-               [ C(RESULT_MISS)   ] = 0x412e, /* LLC Misses                   */
+               /* OFFCORE_RESPONSE_0.PREFETCH.LOCAL_CACHE */
+               [ C(RESULT_ACCESS) ] = 0x01b7,
+               /* OFFCORE_RESPONSE_1.PREFETCH.ANY_LLC_MISS */
+               [ C(RESULT_MISS)   ] = 0x01bb,
        },
  },
  [ C(DTLB) ] = {
@@ -180,6 +351,39 @@ static __initconst const u64 westmere_hw_cache_event_ids
  },
 };
 
+/*
+ * OFFCORE_RESPONSE MSR bits (subset), See IA32 SDM Vol 3 30.6.1.3
+ */
+
+#define DMND_DATA_RD     (1 << 0)
+#define DMND_RFO         (1 << 1)
+#define DMND_WB          (1 << 3)
+#define PF_DATA_RD       (1 << 4)
+#define PF_DATA_RFO      (1 << 5)
+#define RESP_UNCORE_HIT  (1 << 8)
+#define RESP_MISS        (0xf600) /* non uncore hit */
+
+static __initconst const u64 nehalem_hw_cache_extra_regs
+                               [PERF_COUNT_HW_CACHE_MAX]
+                               [PERF_COUNT_HW_CACHE_OP_MAX]
+                               [PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(LL  ) ] = {
+       [ C(OP_READ) ] = {
+               [ C(RESULT_ACCESS) ] = DMND_DATA_RD|RESP_UNCORE_HIT,
+               [ C(RESULT_MISS)   ] = DMND_DATA_RD|RESP_MISS,
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = DMND_RFO|DMND_WB|RESP_UNCORE_HIT,
+               [ C(RESULT_MISS)   ] = DMND_RFO|DMND_WB|RESP_MISS,
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = PF_DATA_RD|PF_DATA_RFO|RESP_UNCORE_HIT,
+               [ C(RESULT_MISS)   ] = PF_DATA_RD|PF_DATA_RFO|RESP_MISS,
+       },
+ }
+};
+
 static __initconst const u64 nehalem_hw_cache_event_ids
                                [PERF_COUNT_HW_CACHE_MAX]
                                [PERF_COUNT_HW_CACHE_OP_MAX]
@@ -215,16 +419,26 @@ static __initconst const u64 nehalem_hw_cache_event_ids
  },
  [ C(LL  ) ] = {
        [ C(OP_READ) ] = {
-               [ C(RESULT_ACCESS) ] = 0x0324, /* L2_RQSTS.LOADS               */
-               [ C(RESULT_MISS)   ] = 0x0224, /* L2_RQSTS.LD_MISS             */
+               /* OFFCORE_RESPONSE.ANY_DATA.LOCAL_CACHE */
+               [ C(RESULT_ACCESS) ] = 0x01b7,
+               /* OFFCORE_RESPONSE.ANY_DATA.ANY_LLC_MISS */
+               [ C(RESULT_MISS)   ] = 0x01b7,
        },
+       /*
+        * Use RFO, not WRITEBACK, because a write miss would typically occur
+        * on RFO.
+        */
        [ C(OP_WRITE) ] = {
-               [ C(RESULT_ACCESS) ] = 0x0c24, /* L2_RQSTS.RFOS                */
-               [ C(RESULT_MISS)   ] = 0x0824, /* L2_RQSTS.RFO_MISS            */
+               /* OFFCORE_RESPONSE.ANY_RFO.LOCAL_CACHE */
+               [ C(RESULT_ACCESS) ] = 0x01b7,
+               /* OFFCORE_RESPONSE.ANY_RFO.ANY_LLC_MISS */
+               [ C(RESULT_MISS)   ] = 0x01b7,
        },
        [ C(OP_PREFETCH) ] = {
-               [ C(RESULT_ACCESS) ] = 0x4f2e, /* LLC Reference                */
-               [ C(RESULT_MISS)   ] = 0x412e, /* LLC Misses                   */
+               /* OFFCORE_RESPONSE.PREFETCH.LOCAL_CACHE */
+               [ C(RESULT_ACCESS) ] = 0x01b7,
+               /* OFFCORE_RESPONSE.PREFETCH.ANY_LLC_MISS */
+               [ C(RESULT_MISS)   ] = 0x01b7,
        },
  },
  [ C(DTLB) ] = {
@@ -691,8 +905,8 @@ static void intel_pmu_reset(void)
        printk("clearing PMU state on CPU#%d\n", smp_processor_id());
 
        for (idx = 0; idx < x86_pmu.num_counters; idx++) {
-               checking_wrmsrl(x86_pmu.eventsel + idx, 0ull);
-               checking_wrmsrl(x86_pmu.perfctr  + idx, 0ull);
+               checking_wrmsrl(x86_pmu_config_addr(idx), 0ull);
+               checking_wrmsrl(x86_pmu_event_addr(idx),  0ull);
        }
        for (idx = 0; idx < x86_pmu.num_counters_fixed; idx++)
                checking_wrmsrl(MSR_ARCH_PERFMON_FIXED_CTR0 + idx, 0ull);
@@ -793,6 +1007,67 @@ intel_bts_constraints(struct perf_event *event)
        return NULL;
 }
 
+static struct event_constraint *
+intel_percore_constraints(struct cpu_hw_events *cpuc, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       unsigned int e = hwc->config & ARCH_PERFMON_EVENTSEL_EVENT;
+       struct event_constraint *c;
+       struct intel_percore *pc;
+       struct er_account *era;
+       int i;
+       int free_slot;
+       int found;
+
+       if (!x86_pmu.percore_constraints || hwc->extra_alloc)
+               return NULL;
+
+       for (c = x86_pmu.percore_constraints; c->cmask; c++) {
+               if (e != c->code)
+                       continue;
+
+               /*
+                * Allocate resource per core.
+                */
+               pc = cpuc->per_core;
+               if (!pc)
+                       break;
+               c = &emptyconstraint;
+               raw_spin_lock(&pc->lock);
+               free_slot = -1;
+               found = 0;
+               for (i = 0; i < MAX_EXTRA_REGS; i++) {
+                       era = &pc->regs[i];
+                       if (era->ref > 0 && hwc->extra_reg == era->extra_reg) {
+                               /* Allow sharing same config */
+                               if (hwc->extra_config == era->extra_config) {
+                                       era->ref++;
+                                       cpuc->percore_used = 1;
+                                       hwc->extra_alloc = 1;
+                                       c = NULL;
+                               }
+                               /* else conflict */
+                               found = 1;
+                               break;
+                       } else if (era->ref == 0 && free_slot == -1)
+                               free_slot = i;
+               }
+               if (!found && free_slot != -1) {
+                       era = &pc->regs[free_slot];
+                       era->ref = 1;
+                       era->extra_reg = hwc->extra_reg;
+                       era->extra_config = hwc->extra_config;
+                       cpuc->percore_used = 1;
+                       hwc->extra_alloc = 1;
+                       c = NULL;
+               }
+               raw_spin_unlock(&pc->lock);
+               return c;
+       }
+
+       return NULL;
+}
+
 static struct event_constraint *
 intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event)
 {
@@ -806,9 +1081,51 @@ intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event
        if (c)
                return c;
 
+       c = intel_percore_constraints(cpuc, event);
+       if (c)
+               return c;
+
        return x86_get_event_constraints(cpuc, event);
 }
 
+static void intel_put_event_constraints(struct cpu_hw_events *cpuc,
+                                       struct perf_event *event)
+{
+       struct extra_reg *er;
+       struct intel_percore *pc;
+       struct er_account *era;
+       struct hw_perf_event *hwc = &event->hw;
+       int i, allref;
+
+       if (!cpuc->percore_used)
+               return;
+
+       for (er = x86_pmu.extra_regs; er->msr; er++) {
+               if (er->event != (hwc->config & er->config_mask))
+                       continue;
+
+               pc = cpuc->per_core;
+               raw_spin_lock(&pc->lock);
+               for (i = 0; i < MAX_EXTRA_REGS; i++) {
+                       era = &pc->regs[i];
+                       if (era->ref > 0 &&
+                           era->extra_config == hwc->extra_config &&
+                           era->extra_reg == er->msr) {
+                               era->ref--;
+                               hwc->extra_alloc = 0;
+                               break;
+                       }
+               }
+               allref = 0;
+               for (i = 0; i < MAX_EXTRA_REGS; i++)
+                       allref += pc->regs[i].ref;
+               if (allref == 0)
+                       cpuc->percore_used = 0;
+               raw_spin_unlock(&pc->lock);
+               break;
+       }
+}
+
 static int intel_pmu_hw_config(struct perf_event *event)
 {
        int ret = x86_pmu_hw_config(event);
@@ -880,20 +1197,67 @@ static __initconst const struct x86_pmu core_pmu = {
         */
        .max_period             = (1ULL << 31) - 1,
        .get_event_constraints  = intel_get_event_constraints,
+       .put_event_constraints  = intel_put_event_constraints,
        .event_constraints      = intel_core_event_constraints,
 };
 
+static int intel_pmu_cpu_prepare(int cpu)
+{
+       struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
+
+       if (!cpu_has_ht_siblings())
+               return NOTIFY_OK;
+
+       cpuc->per_core = kzalloc_node(sizeof(struct intel_percore),
+                                     GFP_KERNEL, cpu_to_node(cpu));
+       if (!cpuc->per_core)
+               return NOTIFY_BAD;
+
+       raw_spin_lock_init(&cpuc->per_core->lock);
+       cpuc->per_core->core_id = -1;
+       return NOTIFY_OK;
+}
+
 static void intel_pmu_cpu_starting(int cpu)
 {
+       struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
+       int core_id = topology_core_id(cpu);
+       int i;
+
        init_debug_store_on_cpu(cpu);
        /*
         * Deal with CPUs that don't clear their LBRs on power-up.
         */
        intel_pmu_lbr_reset();
+
+       if (!cpu_has_ht_siblings())
+               return;
+
+       for_each_cpu(i, topology_thread_cpumask(cpu)) {
+               struct intel_percore *pc = per_cpu(cpu_hw_events, i).per_core;
+
+               if (pc && pc->core_id == core_id) {
+                       kfree(cpuc->per_core);
+                       cpuc->per_core = pc;
+                       break;
+               }
+       }
+
+       cpuc->per_core->core_id = core_id;
+       cpuc->per_core->refcnt++;
 }
 
 static void intel_pmu_cpu_dying(int cpu)
 {
+       struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
+       struct intel_percore *pc = cpuc->per_core;
+
+       if (pc) {
+               if (pc->core_id == -1 || --pc->refcnt == 0)
+                       kfree(pc);
+               cpuc->per_core = NULL;
+       }
+
        fini_debug_store_on_cpu(cpu);
 }
 
@@ -918,7 +1282,9 @@ static __initconst const struct x86_pmu intel_pmu = {
         */
        .max_period             = (1ULL << 31) - 1,
        .get_event_constraints  = intel_get_event_constraints,
+       .put_event_constraints  = intel_put_event_constraints,
 
+       .cpu_prepare            = intel_pmu_cpu_prepare,
        .cpu_starting           = intel_pmu_cpu_starting,
        .cpu_dying              = intel_pmu_cpu_dying,
 };
@@ -1024,6 +1390,7 @@ static __init int intel_pmu_init(void)
                intel_pmu_lbr_init_core();
 
                x86_pmu.event_constraints = intel_core2_event_constraints;
+               x86_pmu.pebs_constraints = intel_core2_pebs_event_constraints;
                pr_cont("Core2 events, ");
                break;
 
@@ -1032,11 +1399,16 @@ static __init int intel_pmu_init(void)
        case 46: /* 45 nm nehalem-ex, "Beckton" */
                memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
+               memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs,
+                      sizeof(hw_cache_extra_regs));
 
                intel_pmu_lbr_init_nhm();
 
                x86_pmu.event_constraints = intel_nehalem_event_constraints;
+               x86_pmu.pebs_constraints = intel_nehalem_pebs_event_constraints;
+               x86_pmu.percore_constraints = intel_nehalem_percore_constraints;
                x86_pmu.enable_all = intel_pmu_nhm_enable_all;
+               x86_pmu.extra_regs = intel_nehalem_extra_regs;
                pr_cont("Nehalem events, ");
                break;
 
@@ -1047,6 +1419,7 @@ static __init int intel_pmu_init(void)
                intel_pmu_lbr_init_atom();
 
                x86_pmu.event_constraints = intel_gen_event_constraints;
+               x86_pmu.pebs_constraints = intel_atom_pebs_event_constraints;
                pr_cont("Atom events, ");
                break;
 
@@ -1054,14 +1427,30 @@ static __init int intel_pmu_init(void)
        case 44: /* 32 nm nehalem, "Gulftown" */
                memcpy(hw_cache_event_ids, westmere_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
+               memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs,
+                      sizeof(hw_cache_extra_regs));
 
                intel_pmu_lbr_init_nhm();
 
                x86_pmu.event_constraints = intel_westmere_event_constraints;
+               x86_pmu.percore_constraints = intel_westmere_percore_constraints;
                x86_pmu.enable_all = intel_pmu_nhm_enable_all;
+               x86_pmu.pebs_constraints = intel_westmere_pebs_event_constraints;
+               x86_pmu.extra_regs = intel_westmere_extra_regs;
                pr_cont("Westmere events, ");
                break;
 
+       case 42: /* SandyBridge */
+               memcpy(hw_cache_event_ids, snb_hw_cache_event_ids,
+                      sizeof(hw_cache_event_ids));
+
+               intel_pmu_lbr_init_nhm();
+
+               x86_pmu.event_constraints = intel_snb_event_constraints;
+               x86_pmu.pebs_constraints = intel_snb_pebs_events;
+               pr_cont("SandyBridge events, ");
+               break;
+
        default:
                /*
                 * default constraints for v2 and up
index b7dcd9f..b95c66a 100644 (file)
@@ -361,30 +361,88 @@ static int intel_pmu_drain_bts_buffer(void)
 /*
  * PEBS
  */
-
-static struct event_constraint intel_core_pebs_events[] = {
-       PEBS_EVENT_CONSTRAINT(0x00c0, 0x1), /* INSTR_RETIRED.ANY */
+static struct event_constraint intel_core2_pebs_event_constraints[] = {
+       PEBS_EVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY */
        PEBS_EVENT_CONSTRAINT(0xfec1, 0x1), /* X87_OPS_RETIRED.ANY */
        PEBS_EVENT_CONSTRAINT(0x00c5, 0x1), /* BR_INST_RETIRED.MISPRED */
        PEBS_EVENT_CONSTRAINT(0x1fc7, 0x1), /* SIMD_INST_RETURED.ANY */
-       PEBS_EVENT_CONSTRAINT(0x01cb, 0x1), /* MEM_LOAD_RETIRED.L1D_MISS */
-       PEBS_EVENT_CONSTRAINT(0x02cb, 0x1), /* MEM_LOAD_RETIRED.L1D_LINE_MISS */
-       PEBS_EVENT_CONSTRAINT(0x04cb, 0x1), /* MEM_LOAD_RETIRED.L2_MISS */
-       PEBS_EVENT_CONSTRAINT(0x08cb, 0x1), /* MEM_LOAD_RETIRED.L2_LINE_MISS */
-       PEBS_EVENT_CONSTRAINT(0x10cb, 0x1), /* MEM_LOAD_RETIRED.DTLB_MISS */
+       INTEL_EVENT_CONSTRAINT(0xcb, 0x1),  /* MEM_LOAD_RETIRED.* */
+       EVENT_CONSTRAINT_END
+};
+
+static struct event_constraint intel_atom_pebs_event_constraints[] = {
+       PEBS_EVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY */
+       PEBS_EVENT_CONSTRAINT(0x00c5, 0x1), /* MISPREDICTED_BRANCH_RETIRED */
+       INTEL_EVENT_CONSTRAINT(0xcb, 0x1),  /* MEM_LOAD_RETIRED.* */
        EVENT_CONSTRAINT_END
 };
 
-static struct event_constraint intel_nehalem_pebs_events[] = {
-       PEBS_EVENT_CONSTRAINT(0x00c0, 0xf), /* INSTR_RETIRED.ANY */
-       PEBS_EVENT_CONSTRAINT(0xfec1, 0xf), /* X87_OPS_RETIRED.ANY */
-       PEBS_EVENT_CONSTRAINT(0x00c5, 0xf), /* BR_INST_RETIRED.MISPRED */
-       PEBS_EVENT_CONSTRAINT(0x1fc7, 0xf), /* SIMD_INST_RETURED.ANY */
-       PEBS_EVENT_CONSTRAINT(0x01cb, 0xf), /* MEM_LOAD_RETIRED.L1D_MISS */
-       PEBS_EVENT_CONSTRAINT(0x02cb, 0xf), /* MEM_LOAD_RETIRED.L1D_LINE_MISS */
-       PEBS_EVENT_CONSTRAINT(0x04cb, 0xf), /* MEM_LOAD_RETIRED.L2_MISS */
-       PEBS_EVENT_CONSTRAINT(0x08cb, 0xf), /* MEM_LOAD_RETIRED.L2_LINE_MISS */
-       PEBS_EVENT_CONSTRAINT(0x10cb, 0xf), /* MEM_LOAD_RETIRED.DTLB_MISS */
+static struct event_constraint intel_nehalem_pebs_event_constraints[] = {
+       INTEL_EVENT_CONSTRAINT(0x0b, 0xf),  /* MEM_INST_RETIRED.* */
+       INTEL_EVENT_CONSTRAINT(0x0f, 0xf),  /* MEM_UNCORE_RETIRED.* */
+       PEBS_EVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */
+       INTEL_EVENT_CONSTRAINT(0xc0, 0xf),  /* INST_RETIRED.ANY */
+       INTEL_EVENT_CONSTRAINT(0xc2, 0xf),  /* UOPS_RETIRED.* */
+       INTEL_EVENT_CONSTRAINT(0xc4, 0xf),  /* BR_INST_RETIRED.* */
+       PEBS_EVENT_CONSTRAINT(0x02c5, 0xf), /* BR_MISP_RETIRED.NEAR_CALL */
+       INTEL_EVENT_CONSTRAINT(0xc7, 0xf),  /* SSEX_UOPS_RETIRED.* */
+       PEBS_EVENT_CONSTRAINT(0x20c8, 0xf), /* ITLB_MISS_RETIRED */
+       INTEL_EVENT_CONSTRAINT(0xcb, 0xf),  /* MEM_LOAD_RETIRED.* */
+       INTEL_EVENT_CONSTRAINT(0xf7, 0xf),  /* FP_ASSIST.* */
+       EVENT_CONSTRAINT_END
+};
+
+static struct event_constraint intel_westmere_pebs_event_constraints[] = {
+       INTEL_EVENT_CONSTRAINT(0x0b, 0xf),  /* MEM_INST_RETIRED.* */
+       INTEL_EVENT_CONSTRAINT(0x0f, 0xf),  /* MEM_UNCORE_RETIRED.* */
+       PEBS_EVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */
+       INTEL_EVENT_CONSTRAINT(0xc0, 0xf),  /* INSTR_RETIRED.* */
+       INTEL_EVENT_CONSTRAINT(0xc2, 0xf),  /* UOPS_RETIRED.* */
+
+       INTEL_EVENT_CONSTRAINT(0xc4, 0xf),  /* BR_INST_RETIRED.* */
+       INTEL_EVENT_CONSTRAINT(0xc5, 0xf),  /* BR_MISP_RETIRED.* */
+       INTEL_EVENT_CONSTRAINT(0xc7, 0xf),  /* SSEX_UOPS_RETIRED.* */
+       PEBS_EVENT_CONSTRAINT(0x20c8, 0xf), /* ITLB_MISS_RETIRED */
+       INTEL_EVENT_CONSTRAINT(0xcb, 0xf),  /* MEM_LOAD_RETIRED.* */
+       INTEL_EVENT_CONSTRAINT(0xf7, 0xf),  /* FP_ASSIST.* */
+       EVENT_CONSTRAINT_END
+};
+
+static struct event_constraint intel_snb_pebs_events[] = {
+       PEBS_EVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
+       PEBS_EVENT_CONSTRAINT(0x01c2, 0xf), /* UOPS_RETIRED.ALL */
+       PEBS_EVENT_CONSTRAINT(0x02c2, 0xf), /* UOPS_RETIRED.RETIRE_SLOTS */
+       PEBS_EVENT_CONSTRAINT(0x01c4, 0xf), /* BR_INST_RETIRED.CONDITIONAL */
+       PEBS_EVENT_CONSTRAINT(0x02c4, 0xf), /* BR_INST_RETIRED.NEAR_CALL */
+       PEBS_EVENT_CONSTRAINT(0x04c4, 0xf), /* BR_INST_RETIRED.ALL_BRANCHES */
+       PEBS_EVENT_CONSTRAINT(0x08c4, 0xf), /* BR_INST_RETIRED.NEAR_RETURN */
+       PEBS_EVENT_CONSTRAINT(0x10c4, 0xf), /* BR_INST_RETIRED.NOT_TAKEN */
+       PEBS_EVENT_CONSTRAINT(0x20c4, 0xf), /* BR_INST_RETIRED.NEAR_TAKEN */
+       PEBS_EVENT_CONSTRAINT(0x40c4, 0xf), /* BR_INST_RETIRED.FAR_BRANCH */
+       PEBS_EVENT_CONSTRAINT(0x01c5, 0xf), /* BR_MISP_RETIRED.CONDITIONAL */
+       PEBS_EVENT_CONSTRAINT(0x02c5, 0xf), /* BR_MISP_RETIRED.NEAR_CALL */
+       PEBS_EVENT_CONSTRAINT(0x04c5, 0xf), /* BR_MISP_RETIRED.ALL_BRANCHES */
+       PEBS_EVENT_CONSTRAINT(0x10c5, 0xf), /* BR_MISP_RETIRED.NOT_TAKEN */
+       PEBS_EVENT_CONSTRAINT(0x20c5, 0xf), /* BR_MISP_RETIRED.TAKEN */
+       PEBS_EVENT_CONSTRAINT(0x01cd, 0x8), /* MEM_TRANS_RETIRED.LOAD_LATENCY */
+       PEBS_EVENT_CONSTRAINT(0x02cd, 0x8), /* MEM_TRANS_RETIRED.PRECISE_STORE */
+       PEBS_EVENT_CONSTRAINT(0x11d0, 0xf), /* MEM_UOP_RETIRED.STLB_MISS_LOADS */
+       PEBS_EVENT_CONSTRAINT(0x12d0, 0xf), /* MEM_UOP_RETIRED.STLB_MISS_STORES */
+       PEBS_EVENT_CONSTRAINT(0x21d0, 0xf), /* MEM_UOP_RETIRED.LOCK_LOADS */
+       PEBS_EVENT_CONSTRAINT(0x22d0, 0xf), /* MEM_UOP_RETIRED.LOCK_STORES */
+       PEBS_EVENT_CONSTRAINT(0x41d0, 0xf), /* MEM_UOP_RETIRED.SPLIT_LOADS */
+       PEBS_EVENT_CONSTRAINT(0x42d0, 0xf), /* MEM_UOP_RETIRED.SPLIT_STORES */
+       PEBS_EVENT_CONSTRAINT(0x81d0, 0xf), /* MEM_UOP_RETIRED.ANY_LOADS */
+       PEBS_EVENT_CONSTRAINT(0x82d0, 0xf), /* MEM_UOP_RETIRED.ANY_STORES */
+       PEBS_EVENT_CONSTRAINT(0x01d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.L1_HIT */
+       PEBS_EVENT_CONSTRAINT(0x02d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.L2_HIT */
+       PEBS_EVENT_CONSTRAINT(0x04d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.LLC_HIT */
+       PEBS_EVENT_CONSTRAINT(0x40d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.HIT_LFB */
+       PEBS_EVENT_CONSTRAINT(0x01d2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_MISS */
+       PEBS_EVENT_CONSTRAINT(0x02d2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT */
+       PEBS_EVENT_CONSTRAINT(0x04d2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM */
+       PEBS_EVENT_CONSTRAINT(0x08d2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_NONE */
+       PEBS_EVENT_CONSTRAINT(0x02d4, 0xf), /* MEM_LOAD_UOPS_MISC_RETIRED.LLC_MISS */
        EVENT_CONSTRAINT_END
 };
 
@@ -695,20 +753,17 @@ static void intel_ds_init(void)
                        printk(KERN_CONT "PEBS fmt0%c, ", pebs_type);
                        x86_pmu.pebs_record_size = sizeof(struct pebs_record_core);
                        x86_pmu.drain_pebs = intel_pmu_drain_pebs_core;
-                       x86_pmu.pebs_constraints = intel_core_pebs_events;
                        break;
 
                case 1:
                        printk(KERN_CONT "PEBS fmt1%c, ", pebs_type);
                        x86_pmu.pebs_record_size = sizeof(struct pebs_record_nhm);
                        x86_pmu.drain_pebs = intel_pmu_drain_pebs_nhm;
-                       x86_pmu.pebs_constraints = intel_nehalem_pebs_events;
                        break;
 
                default:
                        printk(KERN_CONT "no PEBS fmt%d%c, ", format, pebs_type);
                        x86_pmu.pebs = 0;
-                       break;
                }
        }
 }
index e56b9bf..3769ac8 100644 (file)
@@ -682,7 +682,7 @@ static int p4_validate_raw_event(struct perf_event *event)
         * if an event is shared accross the logical threads
         * the user needs special permissions to be able to use it
         */
-       if (p4_event_bind_map[v].shared) {
+       if (p4_ht_active() && p4_event_bind_map[v].shared) {
                if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN))
                        return -EACCES;
        }
@@ -727,7 +727,8 @@ static int p4_hw_config(struct perf_event *event)
                event->hw.config = p4_set_ht_bit(event->hw.config);
 
        if (event->attr.type == PERF_TYPE_RAW) {
-
+               struct p4_event_bind *bind;
+               unsigned int esel;
                /*
                 * Clear bits we reserve to be managed by kernel itself
                 * and never allowed from a user space
@@ -743,6 +744,13 @@ static int p4_hw_config(struct perf_event *event)
                 * bits since we keep additional info here (for cache events and etc)
                 */
                event->hw.config |= event->attr.config;
+               bind = p4_config_get_bind(event->attr.config);
+               if (!bind) {
+                       rc = -EINVAL;
+                       goto out;
+               }
+               esel = P4_OPCODE_ESEL(bind->opcode);
+               event->hw.config |= p4_config_pack_cccr(P4_CCCR_ESEL(esel));
        }
 
        rc = x86_setup_perfctr(event);
@@ -756,15 +764,20 @@ static inline int p4_pmu_clear_cccr_ovf(struct hw_perf_event *hwc)
        u64 v;
 
        /* an official way for overflow indication */
-       rdmsrl(hwc->config_base + hwc->idx, v);
+       rdmsrl(hwc->config_base, v);
        if (v & P4_CCCR_OVF) {
-               wrmsrl(hwc->config_base + hwc->idx, v & ~P4_CCCR_OVF);
+               wrmsrl(hwc->config_base, v & ~P4_CCCR_OVF);
                return 1;
        }
 
-       /* it might be unflagged overflow */
-       rdmsrl(hwc->event_base + hwc->idx, v);
-       if (!(v & ARCH_P4_CNTRVAL_MASK))
+       /*
+        * In some circumstances the overflow might issue an NMI but did
+        * not set P4_CCCR_OVF bit. Because a counter holds a negative value
+        * we simply check for high bit being set, if it's cleared it means
+        * the counter has reached zero value and continued counting before
+        * real NMI signal was received:
+        */
+       if (!(v & ARCH_P4_UNFLAGGED_BIT))
                return 1;
 
        return 0;
@@ -802,7 +815,7 @@ static inline void p4_pmu_disable_event(struct perf_event *event)
         * state we need to clear P4_CCCR_OVF, otherwise interrupt get
         * asserted again and again
         */
-       (void)checking_wrmsrl(hwc->config_base + hwc->idx,
+       (void)checking_wrmsrl(hwc->config_base,
                (u64)(p4_config_unpack_cccr(hwc->config)) &
                        ~P4_CCCR_ENABLE & ~P4_CCCR_OVF & ~P4_CCCR_RESERVED);
 }
@@ -872,7 +885,7 @@ static void p4_pmu_enable_event(struct perf_event *event)
        p4_pmu_enable_pebs(hwc->config);
 
        (void)checking_wrmsrl(escr_addr, escr_conf);
-       (void)checking_wrmsrl(hwc->config_base + hwc->idx,
+       (void)checking_wrmsrl(hwc->config_base,
                                (cccr & ~P4_CCCR_RESERVED) | P4_CCCR_ENABLE);
 }
 
index 34ba07b..20c097e 100644 (file)
@@ -68,7 +68,7 @@ p6_pmu_disable_event(struct perf_event *event)
        if (cpuc->enabled)
                val |= ARCH_PERFMON_EVENTSEL_ENABLE;
 
-       (void)checking_wrmsrl(hwc->config_base + hwc->idx, val);
+       (void)checking_wrmsrl(hwc->config_base, val);
 }
 
 static void p6_pmu_enable_event(struct perf_event *event)
@@ -81,7 +81,7 @@ static void p6_pmu_enable_event(struct perf_event *event)
        if (cpuc->enabled)
                val |= ARCH_PERFMON_EVENTSEL_ENABLE;
 
-       (void)checking_wrmsrl(hwc->config_base + hwc->idx, val);
+       (void)checking_wrmsrl(hwc->config_base, val);
 }
 
 static __initconst const struct x86_pmu p6_pmu = {
index d5a2366..966512b 100644 (file)
@@ -46,6 +46,8 @@ static inline unsigned int nmi_perfctr_msr_to_bit(unsigned int msr)
        /* returns the bit offset of the performance counter register */
        switch (boot_cpu_data.x86_vendor) {
        case X86_VENDOR_AMD:
+               if (msr >= MSR_F15H_PERF_CTR)
+                       return (msr - MSR_F15H_PERF_CTR) >> 1;
                return msr - MSR_K7_PERFCTR0;
        case X86_VENDOR_INTEL:
                if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
@@ -70,6 +72,8 @@ static inline unsigned int nmi_evntsel_msr_to_bit(unsigned int msr)
        /* returns the bit offset of the event selection register */
        switch (boot_cpu_data.x86_vendor) {
        case X86_VENDOR_AMD:
+               if (msr >= MSR_F15H_PERF_CTL)
+                       return (msr - MSR_F15H_PERF_CTL) >> 1;
                return msr - MSR_K7_EVNTSEL0;
        case X86_VENDOR_INTEL:
                if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c
new file mode 100644 (file)
index 0000000..7a8cebc
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ * Architecture specific OF callbacks.
+ */
+#include <linux/bootmem.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/of_pci.h>
+
+#include <asm/hpet.h>
+#include <asm/irq_controller.h>
+#include <asm/apic.h>
+#include <asm/pci_x86.h>
+
+__initdata u64 initial_dtb;
+char __initdata cmd_line[COMMAND_LINE_SIZE];
+static LIST_HEAD(irq_domains);
+static DEFINE_RAW_SPINLOCK(big_irq_lock);
+
+int __initdata of_ioapic;
+
+#ifdef CONFIG_X86_IO_APIC
+static void add_interrupt_host(struct irq_domain *ih)
+{
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&big_irq_lock, flags);
+       list_add(&ih->l, &irq_domains);
+       raw_spin_unlock_irqrestore(&big_irq_lock, flags);
+}
+#endif
+
+static struct irq_domain *get_ih_from_node(struct device_node *controller)
+{
+       struct irq_domain *ih, *found = NULL;
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&big_irq_lock, flags);
+       list_for_each_entry(ih, &irq_domains, l) {
+               if (ih->controller ==  controller) {
+                       found = ih;
+                       break;
+               }
+       }
+       raw_spin_unlock_irqrestore(&big_irq_lock, flags);
+       return found;
+}
+
+unsigned int irq_create_of_mapping(struct device_node *controller,
+                                  const u32 *intspec, unsigned int intsize)
+{
+       struct irq_domain *ih;
+       u32 virq, type;
+       int ret;
+
+       ih = get_ih_from_node(controller);
+       if (!ih)
+               return 0;
+       ret = ih->xlate(ih, intspec, intsize, &virq, &type);
+       if (ret)
+               return ret;
+       if (type == IRQ_TYPE_NONE)
+               return virq;
+       /* set the mask if it is different from current */
+       if (type == (irq_to_desc(virq)->status & IRQF_TRIGGER_MASK))
+               set_irq_type(virq, type);
+       return virq;
+}
+EXPORT_SYMBOL_GPL(irq_create_of_mapping);
+
+unsigned long pci_address_to_pio(phys_addr_t address)
+{
+       /*
+        * The ioport address can be directly used by inX / outX
+        */
+       BUG_ON(address >= (1 << 16));
+       return (unsigned long)address;
+}
+EXPORT_SYMBOL_GPL(pci_address_to_pio);
+
+void __init early_init_dt_scan_chosen_arch(unsigned long node)
+{
+       BUG();
+}
+
+void __init early_init_dt_add_memory_arch(u64 base, u64 size)
+{
+       BUG();
+}
+
+void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
+{
+       return __alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS));
+}
+
+void __init add_dtb(u64 data)
+{
+       initial_dtb = data + offsetof(struct setup_data, data);
+}
+
+/*
+ * CE4100 ids. Will be moved to machine_device_initcall() once we have it.
+ */
+static struct of_device_id __initdata ce4100_ids[] = {
+       { .compatible = "intel,ce4100-cp", },
+       { .compatible = "isa", },
+       { .compatible = "pci", },
+       {},
+};
+
+static int __init add_bus_probe(void)
+{
+       if (!of_have_populated_dt())
+               return 0;
+
+       return of_platform_bus_probe(NULL, ce4100_ids, NULL);
+}
+module_init(add_bus_probe);
+
+#ifdef CONFIG_PCI
+static int x86_of_pci_irq_enable(struct pci_dev *dev)
+{
+       struct of_irq oirq;
+       u32 virq;
+       int ret;
+       u8 pin;
+
+       ret = pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+       if (ret)
+               return ret;
+       if (!pin)
+               return 0;
+
+       ret = of_irq_map_pci(dev, &oirq);
+       if (ret)
+               return ret;
+
+       virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
+                       oirq.size);
+       if (virq == 0)
+               return -EINVAL;
+       dev->irq = virq;
+       return 0;
+}
+
+static void x86_of_pci_irq_disable(struct pci_dev *dev)
+{
+}
+
+void __cpuinit x86_of_pci_init(void)
+{
+       struct device_node *np;
+
+       pcibios_enable_irq = x86_of_pci_irq_enable;
+       pcibios_disable_irq = x86_of_pci_irq_disable;
+
+       for_each_node_by_type(np, "pci") {
+               const void *prop;
+               struct pci_bus *bus;
+               unsigned int bus_min;
+               struct device_node *child;
+
+               prop = of_get_property(np, "bus-range", NULL);
+               if (!prop)
+                       continue;
+               bus_min = be32_to_cpup(prop);
+
+               bus = pci_find_bus(0, bus_min);
+               if (!bus) {
+                       printk(KERN_ERR "Can't find a node for bus %s.\n",
+                                       np->full_name);
+                       continue;
+               }
+
+               if (bus->self)
+                       bus->self->dev.of_node = np;
+               else
+                       bus->dev.of_node = np;
+
+               for_each_child_of_node(np, child) {
+                       struct pci_dev *dev;
+                       u32 devfn;
+
+                       prop = of_get_property(child, "reg", NULL);
+                       if (!prop)
+                               continue;
+
+                       devfn = (be32_to_cpup(prop) >> 8) & 0xff;
+                       dev = pci_get_slot(bus, devfn);
+                       if (!dev)
+                               continue;
+                       dev->dev.of_node = child;
+                       pci_dev_put(dev);
+               }
+       }
+}
+#endif
+
+static void __init dtb_setup_hpet(void)
+{
+#ifdef CONFIG_HPET_TIMER
+       struct device_node *dn;
+       struct resource r;
+       int ret;
+
+       dn = of_find_compatible_node(NULL, NULL, "intel,ce4100-hpet");
+       if (!dn)
+               return;
+       ret = of_address_to_resource(dn, 0, &r);
+       if (ret) {
+               WARN_ON(1);
+               return;
+       }
+       hpet_address = r.start;
+#endif
+}
+
+static void __init dtb_lapic_setup(void)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+       struct device_node *dn;
+       struct resource r;
+       int ret;
+
+       dn = of_find_compatible_node(NULL, NULL, "intel,ce4100-lapic");
+       if (!dn)
+               return;
+
+       ret = of_address_to_resource(dn, 0, &r);
+       if (WARN_ON(ret))
+               return;
+
+       /* Did the boot loader setup the local APIC ? */
+       if (!cpu_has_apic) {
+               if (apic_force_enable(r.start))
+                       return;
+       }
+       smp_found_config = 1;
+       pic_mode = 1;
+       register_lapic_address(r.start);
+       generic_processor_info(boot_cpu_physical_apicid,
+                              GET_APIC_VERSION(apic_read(APIC_LVR)));
+#endif
+}
+
+#ifdef CONFIG_X86_IO_APIC
+static unsigned int ioapic_id;
+
+static void __init dtb_add_ioapic(struct device_node *dn)
+{
+       struct resource r;
+       int ret;
+
+       ret = of_address_to_resource(dn, 0, &r);
+       if (ret) {
+               printk(KERN_ERR "Can't obtain address from node %s.\n",
+                               dn->full_name);
+               return;
+       }
+       mp_register_ioapic(++ioapic_id, r.start, gsi_top);
+}
+
+static void __init dtb_ioapic_setup(void)
+{
+       struct device_node *dn;
+
+       for_each_compatible_node(dn, NULL, "intel,ce4100-ioapic")
+               dtb_add_ioapic(dn);
+
+       if (nr_ioapics) {
+               of_ioapic = 1;
+               return;
+       }
+       printk(KERN_ERR "Error: No information about IO-APIC in OF.\n");
+}
+#else
+static void __init dtb_ioapic_setup(void) {}
+#endif
+
+static void __init dtb_apic_setup(void)
+{
+       dtb_lapic_setup();
+       dtb_ioapic_setup();
+}
+
+#ifdef CONFIG_OF_FLATTREE
+static void __init x86_flattree_get_config(void)
+{
+       u32 size, map_len;
+       void *new_dtb;
+
+       if (!initial_dtb)
+               return;
+
+       map_len = max(PAGE_SIZE - (initial_dtb & ~PAGE_MASK),
+                       (u64)sizeof(struct boot_param_header));
+
+       initial_boot_params = early_memremap(initial_dtb, map_len);
+       size = be32_to_cpu(initial_boot_params->totalsize);
+       if (map_len < size) {
+               early_iounmap(initial_boot_params, map_len);
+               initial_boot_params = early_memremap(initial_dtb, size);
+               map_len = size;
+       }
+
+       new_dtb = alloc_bootmem(size);
+       memcpy(new_dtb, initial_boot_params, size);
+       early_iounmap(initial_boot_params, map_len);
+
+       initial_boot_params = new_dtb;
+
+       /* root level address cells */
+       of_scan_flat_dt(early_init_dt_scan_root, NULL);
+
+       unflatten_device_tree();
+}
+#else
+static inline void x86_flattree_get_config(void) { }
+#endif
+
+void __init x86_dtb_init(void)
+{
+       x86_flattree_get_config();
+
+       if (!of_have_populated_dt())
+               return;
+
+       dtb_setup_hpet();
+       dtb_apic_setup();
+}
+
+#ifdef CONFIG_X86_IO_APIC
+
+struct of_ioapic_type {
+       u32 out_type;
+       u32 trigger;
+       u32 polarity;
+};
+
+static struct of_ioapic_type of_ioapic_type[] =
+{
+       {
+               .out_type       = IRQ_TYPE_EDGE_RISING,
+               .trigger        = IOAPIC_EDGE,
+               .polarity       = 1,
+       },
+       {
+               .out_type       = IRQ_TYPE_LEVEL_LOW,
+               .trigger        = IOAPIC_LEVEL,
+               .polarity       = 0,
+       },
+       {
+               .out_type       = IRQ_TYPE_LEVEL_HIGH,
+               .trigger        = IOAPIC_LEVEL,
+               .polarity       = 1,
+       },
+       {
+               .out_type       = IRQ_TYPE_EDGE_FALLING,
+               .trigger        = IOAPIC_EDGE,
+               .polarity       = 0,
+       },
+};
+
+static int ioapic_xlate(struct irq_domain *id, const u32 *intspec, u32 intsize,
+                       u32 *out_hwirq, u32 *out_type)
+{
+       struct io_apic_irq_attr attr;
+       struct of_ioapic_type *it;
+       u32 line, idx, type;
+
+       if (intsize < 2)
+               return -EINVAL;
+
+       line = *intspec;
+       idx = (u32) id->priv;
+       *out_hwirq = line + mp_gsi_routing[idx].gsi_base;
+
+       intspec++;
+       type = *intspec;
+
+       if (type >= ARRAY_SIZE(of_ioapic_type))
+               return -EINVAL;
+
+       it = of_ioapic_type + type;
+       *out_type = it->out_type;
+
+       set_io_apic_irq_attr(&attr, idx, line, it->trigger, it->polarity);
+
+       return io_apic_setup_irq_pin(*out_hwirq, cpu_to_node(0), &attr);
+}
+
+static void __init ioapic_add_ofnode(struct device_node *np)
+{
+       struct resource r;
+       int i, ret;
+
+       ret = of_address_to_resource(np, 0, &r);
+       if (ret) {
+               printk(KERN_ERR "Failed to obtain address for %s\n",
+                               np->full_name);
+               return;
+       }
+
+       for (i = 0; i < nr_ioapics; i++) {
+               if (r.start == mp_ioapics[i].apicaddr) {
+                       struct irq_domain *id;
+
+                       id = kzalloc(sizeof(*id), GFP_KERNEL);
+                       BUG_ON(!id);
+                       id->controller = np;
+                       id->xlate = ioapic_xlate;
+                       id->priv = (void *)i;
+                       add_interrupt_host(id);
+                       return;
+               }
+       }
+       printk(KERN_ERR "IOxAPIC at %s is not registered.\n", np->full_name);
+}
+
+void __init x86_add_irq_domains(void)
+{
+       struct device_node *dp;
+
+       if (!of_have_populated_dt())
+               return;
+
+       for_each_node_with_property(dp, "interrupt-controller") {
+               if (of_device_is_compatible(dp, "intel,ce4100-ioapic"))
+                       ioapic_add_ofnode(dp);
+       }
+}
+#else
+void __init x86_add_irq_domains(void) { }
+#endif
index df20723..220a1c1 100644 (file)
@@ -320,31 +320,6 @@ void die(const char *str, struct pt_regs *regs, long err)
        oops_end(flags, regs, sig);
 }
 
-void notrace __kprobes
-die_nmi(char *str, struct pt_regs *regs, int do_panic)
-{
-       unsigned long flags;
-
-       if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP)
-               return;
-
-       /*
-        * We are in trouble anyway, lets at least try
-        * to get a message out.
-        */
-       flags = oops_begin();
-       printk(KERN_EMERG "%s", str);
-       printk(" on CPU%d, ip %08lx, registers:\n",
-               smp_processor_id(), regs->ip);
-       show_registers(regs);
-       oops_end(flags, regs, 0);
-       if (do_panic || panic_on_oops)
-               panic("Non maskable interrupt");
-       nmi_exit();
-       local_irq_enable();
-       do_exit(SIGBUS);
-}
-
 static int __init oops_setup(char *s)
 {
        if (!s)
index 6410133..a6b6fcf 100644 (file)
@@ -149,13 +149,13 @@ void dump_trace(struct task_struct *task,
        unsigned used = 0;
        struct thread_info *tinfo;
        int graph = 0;
+       unsigned long dummy;
        unsigned long bp;
 
        if (!task)
                task = current;
 
        if (!stack) {
-               unsigned long dummy;
                stack = &dummy;
                if (task && task != current)
                        stack = (unsigned long *)task->thread.sp;
index 294f26d..cdf5bfd 100644 (file)
@@ -667,21 +667,15 @@ __init void e820_setup_gap(void)
  * boot_params.e820_map, others are passed via SETUP_E820_EXT node of
  * linked list of struct setup_data, which is parsed here.
  */
-void __init parse_e820_ext(struct setup_data *sdata, unsigned long pa_data)
+void __init parse_e820_ext(struct setup_data *sdata)
 {
-       u32 map_len;
        int entries;
        struct e820entry *extmap;
 
        entries = sdata->len / sizeof(struct e820entry);
-       map_len = sdata->len + sizeof(struct setup_data);
-       if (map_len > PAGE_SIZE)
-               sdata = early_ioremap(pa_data, map_len);
        extmap = (struct e820entry *)(sdata->data);
        __append_e820_map(extmap, entries);
        sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
-       if (map_len > PAGE_SIZE)
-               early_iounmap(sdata, map_len);
        printk(KERN_INFO "extended physical RAM map:\n");
        e820_print_map("extended");
 }
@@ -847,15 +841,21 @@ static int __init parse_memopt(char *p)
        if (!p)
                return -EINVAL;
 
-#ifdef CONFIG_X86_32
        if (!strcmp(p, "nopentium")) {
+#ifdef CONFIG_X86_32
                setup_clear_cpu_cap(X86_FEATURE_PSE);
                return 0;
-       }
+#else
+               printk(KERN_WARNING "mem=nopentium ignored! (only supported on x86_32)\n");
+               return -EINVAL;
 #endif
+       }
 
        userdef = 1;
        mem_size = memparse(p, &p);
+       /* don't remove all of memory when handling "mem={invalid}" param */
+       if (mem_size == 0)
+               return -EINVAL;
        e820_remove_range(mem_size, ULLONG_MAX - mem_size, E820_RAM, 1);
 
        return 0;
index 76b8cd9..9efbdcc 100644 (file)
@@ -143,15 +143,10 @@ static void __init ati_bugs(int num, int slot, int func)
 
 static u32 __init ati_sbx00_rev(int num, int slot, int func)
 {
-       u32 old, d;
+       u32 d;
 
-       d = read_pci_config(num, slot, func, 0x70);
-       old = d;
-       d &= ~(1<<8);
-       write_pci_config(num, slot, func, 0x70, d);
        d = read_pci_config(num, slot, func, 0x8);
        d &= 0xff;
-       write_pci_config(num, slot, func, 0x70, old);
 
        return d;
 }
@@ -160,13 +155,16 @@ static void __init ati_bugs_contd(int num, int slot, int func)
 {
        u32 d, rev;
 
-       if (acpi_use_timer_override)
-               return;
-
        rev = ati_sbx00_rev(num, slot, func);
+       if (rev >= 0x40)
+               acpi_fix_pin2_polarity = 1;
+
        if (rev > 0x13)
                return;
 
+       if (acpi_use_timer_override)
+               return;
+
        /* check for IRQ0 interrupt swap */
        d = read_pci_config(num, slot, func, 0x64);
        if (!(d & (1<<14)))
index c8b4efa..fa41f72 100644 (file)
@@ -65,6 +65,8 @@
 #define sysexit_audit  syscall_exit_work
 #endif
 
+       .section .entry.text, "ax"
+
 /*
  * We use macros for low-level operations which need to be overridden
  * for paravirtualization.  The following will never clobber any registers:
@@ -395,7 +397,7 @@ sysenter_past_esp:
         * A tiny bit of offset fixup is necessary - 4*4 means the 4 words
         * pushed above; +8 corresponds to copy_thread's esp0 setting.
         */
-       pushl_cfi ((TI_sysenter_return)-THREAD_SIZE_asm+8+4*4)(%esp)
+       pushl_cfi ((TI_sysenter_return)-THREAD_SIZE+8+4*4)(%esp)
        CFI_REL_OFFSET eip, 0
 
        pushl_cfi %eax
@@ -788,7 +790,7 @@ ENDPROC(ptregs_clone)
  */
 .section .init.rodata,"a"
 ENTRY(interrupt)
-.text
+.section .entry.text, "ax"
        .p2align 5
        .p2align CONFIG_X86_L1_CACHE_SHIFT
 ENTRY(irq_entries_start)
@@ -807,7 +809,7 @@ vector=FIRST_EXTERNAL_VECTOR
       .endif
       .previous
        .long 1b
-      .text
+      .section .entry.text, "ax"
 vector=vector+1
     .endif
   .endr
@@ -1409,8 +1411,7 @@ END(general_protection)
 #ifdef CONFIG_KVM_GUEST
 ENTRY(async_page_fault)
        RING0_EC_FRAME
-       pushl $do_async_page_fault
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $do_async_page_fault
        jmp error_code
        CFI_ENDPROC
 END(apf_page_fault)
index aed1ffb..b72b4a6 100644 (file)
@@ -61,6 +61,8 @@
 #define __AUDIT_ARCH_LE           0x40000000
 
        .code64
+       .section .entry.text, "ax"
+
 #ifdef CONFIG_FUNCTION_TRACER
 #ifdef CONFIG_DYNAMIC_FTRACE
 ENTRY(mcount)
@@ -744,7 +746,7 @@ END(stub_rt_sigreturn)
  */
        .section .init.rodata,"a"
 ENTRY(interrupt)
-       .text
+       .section .entry.text
        .p2align 5
        .p2align CONFIG_X86_L1_CACHE_SHIFT
 ENTRY(irq_entries_start)
@@ -763,7 +765,7 @@ vector=FIRST_EXTERNAL_VECTOR
       .endif
       .previous
        .quad 1b
-      .text
+      .section .entry.text
 vector=vector+1
     .endif
   .endr
@@ -975,9 +977,12 @@ apicinterrupt X86_PLATFORM_IPI_VECTOR \
        x86_platform_ipi smp_x86_platform_ipi
 
 #ifdef CONFIG_SMP
-.irpc idx, "01234567"
+.irp idx,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, \
+       16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+.if NUM_INVALIDATE_TLB_VECTORS > \idx
 apicinterrupt (INVALIDATE_TLB_VECTOR_START)+\idx \
        invalidate_interrupt\idx smp_invalidate_interrupt
+.endif
 .endr
 #endif
 
@@ -1248,7 +1253,7 @@ ENTRY(xen_do_hypervisor_callback)   # do_hypervisor_callback(struct *pt_regs)
        decl PER_CPU_VAR(irq_count)
        jmp  error_exit
        CFI_ENDPROC
-END(do_hypervisor_callback)
+END(xen_do_hypervisor_callback)
 
 /*
  * Hypervisor uses this for application faults while it executes.
index 382eb29..a93742a 100644 (file)
@@ -437,18 +437,19 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
                return;
        }
 
-       if (ftrace_push_return_trace(old, self_addr, &trace.depth,
-                   frame_pointer) == -EBUSY) {
-               *parent = old;
-               return;
-       }
-
        trace.func = self_addr;
+       trace.depth = current->curr_ret_stack + 1;
 
        /* Only trace if the calling function expects to */
        if (!ftrace_graph_entry(&trace)) {
-               current->curr_ret_stack--;
                *parent = old;
+               return;
+       }
+
+       if (ftrace_push_return_trace(old, self_addr, &trace.depth,
+                   frame_pointer) == -EBUSY) {
+               *parent = old;
+               return;
        }
 }
 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
index fc293dc..ce0be7c 100644 (file)
@@ -73,7 +73,7 @@ MAPPING_BEYOND_END = PAGE_TABLE_SIZE(LOWMEM_PAGES) << PAGE_SHIFT
  */
 KERNEL_PAGES = LOWMEM_PAGES
 
-INIT_MAP_SIZE = PAGE_TABLE_SIZE(KERNEL_PAGES) * PAGE_SIZE_asm
+INIT_MAP_SIZE = PAGE_TABLE_SIZE(KERNEL_PAGES) * PAGE_SIZE
 RESERVE_BRK(pagetables, INIT_MAP_SIZE)
 
 /*
@@ -85,6 +85,8 @@ RESERVE_BRK(pagetables, INIT_MAP_SIZE)
  */
 __HEAD
 ENTRY(startup_32)
+       movl pa(stack_start),%ecx
+       
        /* test KEEP_SEGMENTS flag to see if the bootloader is asking
                us to not reload segments */
        testb $(1<<6), BP_loadflags(%esi)
@@ -99,7 +101,9 @@ ENTRY(startup_32)
        movl %eax,%es
        movl %eax,%fs
        movl %eax,%gs
+       movl %eax,%ss
 2:
+       leal -__PAGE_OFFSET(%ecx),%esp
 
 /*
  * Clear BSS first so that there are no surprises...
@@ -133,7 +137,7 @@ ENTRY(startup_32)
        movsl
 1:
 
-#ifdef CONFIG_OLPC_OPENFIRMWARE
+#ifdef CONFIG_OLPC
        /* save OFW's pgdir table for later use when calling into OFW */
        movl %cr3, %eax
        movl %eax, pa(olpc_ofw_pgd)
@@ -145,8 +149,6 @@ ENTRY(startup_32)
  * _brk_end is set up to point to the first "safe" location.
  * Mappings are created both at virtual address 0 (identity mapping)
  * and PAGE_OFFSET for up to _end.
- *
- * Note that the stack is not yet set up!
  */
 #ifdef CONFIG_X86_PAE
 
@@ -282,6 +284,9 @@ ENTRY(startup_32_smp)
        movl %eax,%es
        movl %eax,%fs
        movl %eax,%gs
+       movl pa(stack_start),%ecx
+       movl %eax,%ss
+       leal -__PAGE_OFFSET(%ecx),%esp
 #endif /* CONFIG_SMP */
 default_entry:
 
@@ -347,8 +352,8 @@ default_entry:
        movl %eax,%cr0          /* ..and set paging (PG) bit */
        ljmp $__BOOT_CS,$1f     /* Clear prefetch and normalize %eip */
 1:
-       /* Set up the stack pointer */
-       lss stack_start,%esp
+       /* Shift the stack pointer to a virtual address */
+       addl $__PAGE_OFFSET, %esp
 
 /*
  * Initialize eflags.  Some BIOS's leave bits like NT set.  This would
@@ -360,9 +365,7 @@ default_entry:
 
 #ifdef CONFIG_SMP
        cmpb $0, ready
-       jz  1f                          /* Initial CPU cleans BSS */
-       jmp checkCPUtype
-1:
+       jnz checkCPUtype
 #endif /* CONFIG_SMP */
 
 /*
@@ -470,14 +473,7 @@ is386:     movl $2,%ecx            # set MP
 
        cld                     # gcc2 wants the direction flag cleared at all times
        pushl $0                # fake return address for unwinder
-#ifdef CONFIG_SMP
-       movb ready, %cl
        movb $1, ready
-       cmpb $0,%cl             # the first CPU calls start_kernel
-       je   1f
-       movl (stack_start), %esp
-1:
-#endif /* CONFIG_SMP */
        jmp *(initial_code)
 
 /*
@@ -627,7 +623,7 @@ ENTRY(initial_code)
  * BSS section
  */
 __PAGE_ALIGNED_BSS
-       .align PAGE_SIZE_asm
+       .align PAGE_SIZE
 #ifdef CONFIG_X86_PAE
 initial_pg_pmd:
        .fill 1024*KPMDS,4,0
@@ -648,7 +644,7 @@ ENTRY(swapper_pg_dir)
 #ifdef CONFIG_X86_PAE
 __PAGE_ALIGNED_DATA
        /* Page-aligned for the benefit of paravirt? */
-       .align PAGE_SIZE_asm
+       .align PAGE_SIZE
 ENTRY(initial_page_table)
        .long   pa(initial_pg_pmd+PGD_IDENT_ATTR),0     /* low identity map */
 # if KPMDS == 3
@@ -666,19 +662,19 @@ ENTRY(initial_page_table)
 # else
 #  error "Kernel PMDs should be 1, 2 or 3"
 # endif
-       .align PAGE_SIZE_asm            /* needs to be page-sized too */
+       .align PAGE_SIZE                /* needs to be page-sized too */
 #endif
 
 .data
+.balign 4
 ENTRY(stack_start)
        .long init_thread_union+THREAD_SIZE
-       .long __BOOT_DS
-
-ready: .byte 0
 
 early_recursion_flag:
        .long 0
 
+ready: .byte 0
+
 int_msg:
        .asciz "Unknown interrupt or fault at: %p %p %p\n"
 
index 4ff5968..bfe8f72 100644 (file)
@@ -503,7 +503,7 @@ static int hpet_assign_irq(struct hpet_dev *dev)
        if (!irq)
                return -EINVAL;
 
-       set_irq_data(irq, dev);
+       irq_set_handler_data(irq, dev);
 
        if (hpet_setup_msi_irq(irq))
                return -EINVAL;
index 20757cb..d9ca749 100644 (file)
@@ -112,7 +112,7 @@ static void make_8259A_irq(unsigned int irq)
 {
        disable_irq_nosync(irq);
        io_apic_irqs &= ~(1<<irq);
-       set_irq_chip_and_handler_name(irq, &i8259A_chip, handle_level_irq,
+       irq_set_chip_and_handler_name(irq, &i8259A_chip, handle_level_irq,
                                      i8259A_chip.name);
        enable_irq(irq);
 }
index 8eec0ec..8c96897 100644 (file)
 #include <linux/slab.h>
 #include <linux/thread_info.h>
 #include <linux/syscalls.h>
+#include <linux/bitmap.h>
 #include <asm/syscalls.h>
 
-/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
-static void set_bitmap(unsigned long *bitmap, unsigned int base,
-                      unsigned int extent, int new_value)
-{
-       unsigned int i;
-
-       for (i = base; i < base + extent; i++) {
-               if (new_value)
-                       __set_bit(i, bitmap);
-               else
-                       __clear_bit(i, bitmap);
-       }
-}
-
 /*
  * this changes the io permissions bitmap in the current task.
  */
@@ -69,7 +56,10 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on)
         */
        tss = &per_cpu(init_tss, get_cpu());
 
-       set_bitmap(t->io_bitmap_ptr, from, num, !turn_on);
+       if (turn_on)
+               bitmap_clear(t->io_bitmap_ptr, from, num);
+       else
+               bitmap_set(t->io_bitmap_ptr, from, num);
 
        /*
         * Search for a (possibly new) maximum. This is simple and stupid,
index 52945da..948a31e 100644 (file)
@@ -44,9 +44,9 @@ void ack_bad_irq(unsigned int irq)
 
 #define irq_stats(x)           (&per_cpu(irq_stat, x))
 /*
- * /proc/interrupts printing:
+ * /proc/interrupts printing for arch specific interrupts
  */
-static int show_other_interrupts(struct seq_file *p, int prec)
+int arch_show_interrupts(struct seq_file *p, int prec)
 {
        int j;
 
@@ -122,59 +122,6 @@ static int show_other_interrupts(struct seq_file *p, int prec)
        return 0;
 }
 
-int show_interrupts(struct seq_file *p, void *v)
-{
-       unsigned long flags, any_count = 0;
-       int i = *(loff_t *) v, j, prec;
-       struct irqaction *action;
-       struct irq_desc *desc;
-
-       if (i > nr_irqs)
-               return 0;
-
-       for (prec = 3, j = 1000; prec < 10 && j <= nr_irqs; ++prec)
-               j *= 10;
-
-       if (i == nr_irqs)
-               return show_other_interrupts(p, prec);
-
-       /* print header */
-       if (i == 0) {
-               seq_printf(p, "%*s", prec + 8, "");
-               for_each_online_cpu(j)
-                       seq_printf(p, "CPU%-8d", j);
-               seq_putc(p, '\n');
-       }
-
-       desc = irq_to_desc(i);
-       if (!desc)
-               return 0;
-
-       raw_spin_lock_irqsave(&desc->lock, flags);
-       for_each_online_cpu(j)
-               any_count |= kstat_irqs_cpu(i, j);
-       action = desc->action;
-       if (!action && !any_count)
-               goto out;
-
-       seq_printf(p, "%*d: ", prec, i);
-       for_each_online_cpu(j)
-               seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
-       seq_printf(p, " %8s", desc->irq_data.chip->name);
-       seq_printf(p, "-%-8s", desc->name);
-
-       if (action) {
-               seq_printf(p, "  %s", action->name);
-               while ((action = action->next) != NULL)
-                       seq_printf(p, ", %s", action->name);
-       }
-
-       seq_putc(p, '\n');
-out:
-       raw_spin_unlock_irqrestore(&desc->lock, flags);
-       return 0;
-}
-
 /*
  * /proc/stat helpers
  */
@@ -276,15 +223,6 @@ void smp_x86_platform_ipi(struct pt_regs *regs)
 
 EXPORT_SYMBOL_GPL(vector_used_by_percpu_irq);
 
-#ifdef CONFIG_OF
-unsigned int irq_create_of_mapping(struct device_node *controller,
-               const u32 *intspec, unsigned int intsize)
-{
-       return intspec[0];
-}
-EXPORT_SYMBOL_GPL(irq_create_of_mapping);
-#endif
-
 #ifdef CONFIG_HOTPLUG_CPU
 /* A cpu has been removed from cpu_online_mask.  Reset irq affinities. */
 void fixup_irqs(void)
@@ -293,6 +231,7 @@ void fixup_irqs(void)
        static int warned;
        struct irq_desc *desc;
        struct irq_data *data;
+       struct irq_chip *chip;
 
        for_each_irq_desc(irq, desc) {
                int break_affinity = 0;
@@ -307,10 +246,10 @@ void fixup_irqs(void)
                /* interrupt's are disabled at this point */
                raw_spin_lock(&desc->lock);
 
-               data = &desc->irq_data;
+               data = irq_desc_get_irq_data(desc);
                affinity = data->affinity;
                if (!irq_has_action(irq) ||
-                   cpumask_equal(affinity, cpu_online_mask)) {
+                   cpumask_subset(affinity, cpu_online_mask)) {
                        raw_spin_unlock(&desc->lock);
                        continue;
                }
@@ -327,16 +266,17 @@ void fixup_irqs(void)
                        affinity = cpu_all_mask;
                }
 
-               if (!(desc->status & IRQ_MOVE_PCNTXT) && data->chip->irq_mask)
-                       data->chip->irq_mask(data);
+               chip = irq_data_get_irq_chip(data);
+               if (!irqd_can_move_in_process_context(data) && chip->irq_mask)
+                       chip->irq_mask(data);
 
-               if (data->chip->irq_set_affinity)
-                       data->chip->irq_set_affinity(data, affinity, true);
+               if (chip->irq_set_affinity)
+                       chip->irq_set_affinity(data, affinity, true);
                else if (!(warned++))
                        set_affinity = 0;
 
-               if (!(desc->status & IRQ_MOVE_PCNTXT) && data->chip->irq_unmask)
-                       data->chip->irq_unmask(data);
+               if (!irqd_can_move_in_process_context(data) && chip->irq_unmask)
+                       chip->irq_unmask(data);
 
                raw_spin_unlock(&desc->lock);
 
@@ -367,10 +307,12 @@ void fixup_irqs(void)
                if (irr  & (1 << (vector % 32))) {
                        irq = __this_cpu_read(vector_irq[vector]);
 
-                       data = irq_get_irq_data(irq);
+                       desc = irq_to_desc(irq);
+                       data = irq_desc_get_irq_data(desc);
+                       chip = irq_data_get_irq_chip(data);
                        raw_spin_lock(&desc->lock);
-                       if (data->chip->irq_retrigger)
-                               data->chip->irq_retrigger(data);
+                       if (chip->irq_retrigger)
+                               chip->irq_retrigger(data);
                        raw_spin_unlock(&desc->lock);
                }
        }
index c752e97..f470e4e 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/setup.h>
 #include <asm/i8259.h>
 #include <asm/traps.h>
+#include <asm/prom.h>
 
 /*
  * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
@@ -71,6 +72,7 @@ static irqreturn_t math_error_irq(int cpl, void *dev_id)
 static struct irqaction fpu_irq = {
        .handler = math_error_irq,
        .name = "fpu",
+       .flags = IRQF_NO_THREAD,
 };
 #endif
 
@@ -80,6 +82,7 @@ static struct irqaction fpu_irq = {
 static struct irqaction irq2 = {
        .handler = no_action,
        .name = "cascade",
+       .flags = IRQF_NO_THREAD,
 };
 
 DEFINE_PER_CPU(vector_irq_t, vector_irq) = {
@@ -110,13 +113,19 @@ void __init init_ISA_irqs(void)
        legacy_pic->init(0);
 
        for (i = 0; i < legacy_pic->nr_legacy_irqs; i++)
-               set_irq_chip_and_handler_name(i, chip, handle_level_irq, name);
+               irq_set_chip_and_handler_name(i, chip, handle_level_irq, name);
 }
 
 void __init init_IRQ(void)
 {
        int i;
 
+       /*
+        * We probably need a better place for this, but it works for
+        * now ...
+        */
+       x86_add_irq_domains();
+
        /*
         * On cpu 0, Assign IRQ0_VECTOR..IRQ15_VECTOR's to IRQ 0..15.
         * If these IRQ's are handled by legacy interrupt-controllers like PIC,
@@ -164,14 +173,77 @@ static void __init smp_intr_init(void)
        alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
 
        /* IPIs for invalidation */
-       alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+0, invalidate_interrupt0);
-       alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+1, invalidate_interrupt1);
-       alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+2, invalidate_interrupt2);
-       alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+3, invalidate_interrupt3);
-       alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+4, invalidate_interrupt4);
-       alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+5, invalidate_interrupt5);
-       alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+6, invalidate_interrupt6);
-       alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+7, invalidate_interrupt7);
+#define ALLOC_INVTLB_VEC(NR) \
+       alloc_intr_gate(INVALIDATE_TLB_VECTOR_START+NR, \
+               invalidate_interrupt##NR)
+
+       switch (NUM_INVALIDATE_TLB_VECTORS) {
+       default:
+               ALLOC_INVTLB_VEC(31);
+       case 31:
+               ALLOC_INVTLB_VEC(30);
+       case 30:
+               ALLOC_INVTLB_VEC(29);
+       case 29:
+               ALLOC_INVTLB_VEC(28);
+       case 28:
+               ALLOC_INVTLB_VEC(27);
+       case 27:
+               ALLOC_INVTLB_VEC(26);
+       case 26:
+               ALLOC_INVTLB_VEC(25);
+       case 25:
+               ALLOC_INVTLB_VEC(24);
+       case 24:
+               ALLOC_INVTLB_VEC(23);
+       case 23:
+               ALLOC_INVTLB_VEC(22);
+       case 22:
+               ALLOC_INVTLB_VEC(21);
+       case 21:
+               ALLOC_INVTLB_VEC(20);
+       case 20:
+               ALLOC_INVTLB_VEC(19);
+       case 19:
+               ALLOC_INVTLB_VEC(18);
+       case 18:
+               ALLOC_INVTLB_VEC(17);
+       case 17:
+               ALLOC_INVTLB_VEC(16);
+       case 16:
+               ALLOC_INVTLB_VEC(15);
+       case 15:
+               ALLOC_INVTLB_VEC(14);
+       case 14:
+               ALLOC_INVTLB_VEC(13);
+       case 13:
+               ALLOC_INVTLB_VEC(12);
+       case 12:
+               ALLOC_INVTLB_VEC(11);
+       case 11:
+               ALLOC_INVTLB_VEC(10);
+       case 10:
+               ALLOC_INVTLB_VEC(9);
+       case 9:
+               ALLOC_INVTLB_VEC(8);
+       case 8:
+               ALLOC_INVTLB_VEC(7);
+       case 7:
+               ALLOC_INVTLB_VEC(6);
+       case 6:
+               ALLOC_INVTLB_VEC(5);
+       case 5:
+               ALLOC_INVTLB_VEC(4);
+       case 4:
+               ALLOC_INVTLB_VEC(3);
+       case 3:
+               ALLOC_INVTLB_VEC(2);
+       case 2:
+               ALLOC_INVTLB_VEC(1);
+       case 1:
+               ALLOC_INVTLB_VEC(0);
+               break;
+       }
 
        /* IPI for generic function call */
        alloc_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
@@ -243,7 +315,7 @@ void __init native_init_IRQ(void)
                        set_intr_gate(i, interrupt[i-FIRST_EXTERNAL_VECTOR]);
        }
 
-       if (!acpi_ioapic)
+       if (!acpi_ioapic && !of_ioapic)
                setup_irq(2, &irq2);
 
 #ifdef CONFIG_X86_32
index a413000..7c64c42 100644 (file)
@@ -533,15 +533,6 @@ static int __kgdb_notify(struct die_args *args, unsigned long cmd)
                }
                return NOTIFY_DONE;
 
-       case DIE_NMIWATCHDOG:
-               if (atomic_read(&kgdb_active) != -1) {
-                       /* KGDB CPU roundup: */
-                       kgdb_nmicallback(raw_smp_processor_id(), regs);
-                       return NOTIFY_STOP;
-               }
-               /* Enter debugger: */
-               break;
-
        case DIE_DEBUG:
                if (atomic_read(&kgdb_cpu_doing_single_step) != -1) {
                        if (user_mode(regs))
index d91c477..c969fd9 100644 (file)
@@ -1276,6 +1276,14 @@ static int __kprobes can_optimize(unsigned long paddr)
        if (!kallsyms_lookup_size_offset(paddr, &size, &offset))
                return 0;
 
+       /*
+        * Do not optimize in the entry code due to the unstable
+        * stack handling.
+        */
+       if ((paddr >= (unsigned long )__entry_text_start) &&
+           (paddr <  (unsigned long )__entry_text_end))
+               return 0;
+
        /* Check there is enough space for a relative jump. */
        if (size - offset < RELATIVEJUMP_SIZE)
                return 0;
index 0fe6d1a..c561038 100644 (file)
@@ -66,7 +66,6 @@ struct microcode_amd {
        unsigned int                    mpb[0];
 };
 
-#define UCODE_MAX_SIZE                 2048
 #define UCODE_CONTAINER_SECTION_HDR    8
 #define UCODE_CONTAINER_HEADER_SIZE    12
 
@@ -77,20 +76,20 @@ static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
        struct cpuinfo_x86 *c = &cpu_data(cpu);
        u32 dummy;
 
-       memset(csig, 0, sizeof(*csig));
        if (c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) {
-               pr_warning("microcode: CPU%d: AMD CPU family 0x%x not "
-                          "supported\n", cpu, c->x86);
+               pr_warning("CPU%d: family %d not supported\n", cpu, c->x86);
                return -1;
        }
+
        rdmsr(MSR_AMD64_PATCH_LEVEL, csig->rev, dummy);
-       pr_info("CPU%d: patch_level=0x%x\n", cpu, csig->rev);
+       pr_info("CPU%d: patch_level=0x%08x\n", cpu, csig->rev);
+
        return 0;
 }
 
-static int get_matching_microcode(int cpu, void *mc, int rev)
+static int get_matching_microcode(int cpu, struct microcode_header_amd *mc_hdr,
+                                 int rev)
 {
-       struct microcode_header_amd *mc_header = mc;
        unsigned int current_cpu_id;
        u16 equiv_cpu_id = 0;
        unsigned int i = 0;
@@ -109,17 +108,17 @@ static int get_matching_microcode(int cpu, void *mc, int rev)
        if (!equiv_cpu_id)
                return 0;
 
-       if (mc_header->processor_rev_id != equiv_cpu_id)
+       if (mc_hdr->processor_rev_id != equiv_cpu_id)
                return 0;
 
        /* ucode might be chipset specific -- currently we don't support this */
-       if (mc_header->nb_dev_id || mc_header->sb_dev_id) {
-               pr_err("CPU%d: loading of chipset specific code not yet supported\n",
+       if (mc_hdr->nb_dev_id || mc_hdr->sb_dev_id) {
+               pr_err("CPU%d: chipset specific code not yet supported\n",
                       cpu);
                return 0;
        }
 
-       if (mc_header->patch_id <= rev)
+       if (mc_hdr->patch_id <= rev)
                return 0;
 
        return 1;
@@ -144,71 +143,93 @@ static int apply_microcode_amd(int cpu)
 
        /* check current patch id and patch's id for match */
        if (rev != mc_amd->hdr.patch_id) {
-               pr_err("CPU%d: update failed (for patch_level=0x%x)\n",
+               pr_err("CPU%d: update failed for patch_level=0x%08x\n",
                       cpu, mc_amd->hdr.patch_id);
                return -1;
        }
 
-       pr_info("CPU%d: updated (new patch_level=0x%x)\n", cpu, rev);
+       pr_info("CPU%d: new patch_level=0x%08x\n", cpu, rev);
        uci->cpu_sig.rev = rev;
 
        return 0;
 }
 
-static void *
-get_next_ucode(const u8 *buf, unsigned int size, unsigned int *mc_size)
+static unsigned int verify_ucode_size(int cpu, const u8 *buf, unsigned int size)
 {
-       unsigned int total_size;
-       u8 section_hdr[UCODE_CONTAINER_SECTION_HDR];
-       void *mc;
+       struct cpuinfo_x86 *c = &cpu_data(cpu);
+       unsigned int max_size, actual_size;
+
+#define F1XH_MPB_MAX_SIZE 2048
+#define F14H_MPB_MAX_SIZE 1824
+#define F15H_MPB_MAX_SIZE 4096
+
+       switch (c->x86) {
+       case 0x14:
+               max_size = F14H_MPB_MAX_SIZE;
+               break;
+       case 0x15:
+               max_size = F15H_MPB_MAX_SIZE;
+               break;
+       default:
+               max_size = F1XH_MPB_MAX_SIZE;
+               break;
+       }
 
-       get_ucode_data(section_hdr, buf, UCODE_CONTAINER_SECTION_HDR);
+       actual_size = buf[4] + (buf[5] << 8);
 
-       if (section_hdr[0] != UCODE_UCODE_TYPE) {
-               pr_err("error: invalid type field in container file section header\n");
-               return NULL;
+       if (actual_size > size || actual_size > max_size) {
+               pr_err("section size mismatch\n");
+               return 0;
        }
 
-       total_size = (unsigned long) (section_hdr[4] + (section_hdr[5] << 8));
+       return actual_size;
+}
 
-       if (total_size > size || total_size > UCODE_MAX_SIZE) {
-               pr_err("error: size mismatch\n");
-               return NULL;
+static struct microcode_header_amd *
+get_next_ucode(int cpu, const u8 *buf, unsigned int size, unsigned int *mc_size)
+{
+       struct microcode_header_amd *mc = NULL;
+       unsigned int actual_size = 0;
+
+       if (buf[0] != UCODE_UCODE_TYPE) {
+               pr_err("invalid type field in container file section header\n");
+               goto out;
        }
 
-       mc = vzalloc(UCODE_MAX_SIZE);
+       actual_size = verify_ucode_size(cpu, buf, size);
+       if (!actual_size)
+               goto out;
+
+       mc = vzalloc(actual_size);
        if (!mc)
-               return NULL;
+               goto out;
 
-       get_ucode_data(mc, buf + UCODE_CONTAINER_SECTION_HDR, total_size);
-       *mc_size = total_size + UCODE_CONTAINER_SECTION_HDR;
+       get_ucode_data(mc, buf + UCODE_CONTAINER_SECTION_HDR, actual_size);
+       *mc_size = actual_size + UCODE_CONTAINER_SECTION_HDR;
 
+out:
        return mc;
 }
 
 static int install_equiv_cpu_table(const u8 *buf)
 {
-       u8 *container_hdr[UCODE_CONTAINER_HEADER_SIZE];
-       unsigned int *buf_pos = (unsigned int *)container_hdr;
-       unsigned long size;
-
-       get_ucode_data(&container_hdr, buf, UCODE_CONTAINER_HEADER_SIZE);
-
-       size = buf_pos[2];
-
-       if (buf_pos[1] != UCODE_EQUIV_CPU_TABLE_TYPE || !size) {
-               pr_err("error: invalid type field in container file section header\n");
-               return 0;
+       unsigned int *ibuf = (unsigned int *)buf;
+       unsigned int type = ibuf[1];
+       unsigned int size = ibuf[2];
+
+       if (type != UCODE_EQUIV_CPU_TABLE_TYPE || !size) {
+               pr_err("empty section/"
+                      "invalid type field in container file section header\n");
+               return -EINVAL;
        }
 
        equiv_cpu_table = vmalloc(size);
        if (!equiv_cpu_table) {
                pr_err("failed to allocate equivalent CPU table\n");
-               return 0;
+               return -ENOMEM;
        }
 
-       buf += UCODE_CONTAINER_HEADER_SIZE;
-       get_ucode_data(equiv_cpu_table, buf, size);
+       get_ucode_data(equiv_cpu_table, buf + UCODE_CONTAINER_HEADER_SIZE, size);
 
        return size + UCODE_CONTAINER_HEADER_SIZE; /* add header length */
 }
@@ -223,16 +244,16 @@ static enum ucode_state
 generic_load_microcode(int cpu, const u8 *data, size_t size)
 {
        struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+       struct microcode_header_amd *mc_hdr = NULL;
+       unsigned int mc_size, leftover;
+       int offset;
        const u8 *ucode_ptr = data;
        void *new_mc = NULL;
-       void *mc;
-       int new_rev = uci->cpu_sig.rev;
-       unsigned int leftover;
-       unsigned long offset;
+       unsigned int new_rev = uci->cpu_sig.rev;
        enum ucode_state state = UCODE_OK;
 
        offset = install_equiv_cpu_table(ucode_ptr);
-       if (!offset) {
+       if (offset < 0) {
                pr_err("failed to create equivalent cpu table\n");
                return UCODE_ERROR;
        }
@@ -241,64 +262,65 @@ generic_load_microcode(int cpu, const u8 *data, size_t size)
        leftover = size - offset;
 
        while (leftover) {
-               unsigned int uninitialized_var(mc_size);
-               struct microcode_header_amd *mc_header;
-
-               mc = get_next_ucode(ucode_ptr, leftover, &mc_size);
-               if (!mc)
+               mc_hdr = get_next_ucode(cpu, ucode_ptr, leftover, &mc_size);
+               if (!mc_hdr)
                        break;
 
-               mc_header = (struct microcode_header_amd *)mc;
-               if (get_matching_microcode(cpu, mc, new_rev)) {
+               if (get_matching_microcode(cpu, mc_hdr, new_rev)) {
                        vfree(new_mc);
-                       new_rev = mc_header->patch_id;
-                       new_mc  = mc;
+                       new_rev = mc_hdr->patch_id;
+                       new_mc  = mc_hdr;
                } else
-                       vfree(mc);
+                       vfree(mc_hdr);
 
                ucode_ptr += mc_size;
                leftover  -= mc_size;
        }
 
-       if (new_mc) {
-               if (!leftover) {
-                       vfree(uci->mc);
-                       uci->mc = new_mc;
-                       pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n",
-                                cpu, new_rev, uci->cpu_sig.rev);
-               } else {
-                       vfree(new_mc);
-                       state = UCODE_ERROR;
-               }
-       } else
+       if (!new_mc) {
                state = UCODE_NFOUND;
+               goto free_table;
+       }
 
+       if (!leftover) {
+               vfree(uci->mc);
+               uci->mc = new_mc;
+               pr_debug("CPU%d update ucode (0x%08x -> 0x%08x)\n",
+                        cpu, uci->cpu_sig.rev, new_rev);
+       } else {
+               vfree(new_mc);
+               state = UCODE_ERROR;
+       }
+
+free_table:
        free_equiv_cpu_table();
 
        return state;
 }
 
-static enum ucode_state request_microcode_fw(int cpu, struct device *device)
+static enum ucode_state request_microcode_amd(int cpu, struct device *device)
 {
        const char *fw_name = "amd-ucode/microcode_amd.bin";
-       const struct firmware *firmware;
-       enum ucode_state ret;
+       const struct firmware *fw;
+       enum ucode_state ret = UCODE_NFOUND;
 
-       if (request_firmware(&firmware, fw_name, device)) {
-               printk(KERN_ERR "microcode: failed to load file %s\n", fw_name);
-               return UCODE_NFOUND;
+       if (request_firmware(&fw, fw_name, device)) {
+               pr_err("failed to load file %s\n", fw_name);
+               goto out;
        }
 
-       if (*(u32 *)firmware->data != UCODE_MAGIC) {
-               pr_err("invalid UCODE_MAGIC (0x%08x)\n",
-                      *(u32 *)firmware->data);
-               return UCODE_ERROR;
+       ret = UCODE_ERROR;
+       if (*(u32 *)fw->data != UCODE_MAGIC) {
+               pr_err("invalid magic value (0x%08x)\n", *(u32 *)fw->data);
+               goto fw_release;
        }
 
-       ret = generic_load_microcode(cpu, firmware->data, firmware->size);
+       ret = generic_load_microcode(cpu, fw->data, fw->size);
 
-       release_firmware(firmware);
+fw_release:
+       release_firmware(fw);
 
+out:
        return ret;
 }
 
@@ -319,7 +341,7 @@ static void microcode_fini_cpu_amd(int cpu)
 
 static struct microcode_ops microcode_amd_ops = {
        .request_microcode_user           = request_microcode_user,
-       .request_microcode_fw             = request_microcode_fw,
+       .request_microcode_fw             = request_microcode_amd,
        .collect_cpu_info                 = collect_cpu_info_amd,
        .apply_microcode                  = apply_microcode_amd,
        .microcode_fini_cpu               = microcode_fini_cpu_amd,
index 1cca374..87af68e 100644 (file)
@@ -417,8 +417,10 @@ static int mc_sysdev_add(struct sys_device *sys_dev)
        if (err)
                return err;
 
-       if (microcode_init_cpu(cpu) == UCODE_ERROR)
-               err = -EINVAL;
+       if (microcode_init_cpu(cpu) == UCODE_ERROR) {
+               sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
+               return -EINVAL;
+       }
 
        return err;
 }
index e764fc0..99fa3ad 100644 (file)
@@ -92,21 +92,28 @@ void show_regs(struct pt_regs *regs)
 
 void show_regs_common(void)
 {
-       const char *board, *product;
+       const char *vendor, *product, *board;
 
-       board = dmi_get_system_info(DMI_BOARD_NAME);
-       if (!board)
-               board = "";
+       vendor = dmi_get_system_info(DMI_SYS_VENDOR);
+       if (!vendor)
+               vendor = "";
        product = dmi_get_system_info(DMI_PRODUCT_NAME);
        if (!product)
                product = "";
 
+       /* Board Name is optional */
+       board = dmi_get_system_info(DMI_BOARD_NAME);
+
        printk(KERN_CONT "\n");
-       printk(KERN_DEFAULT "Pid: %d, comm: %.20s %s %s %.*s %s/%s\n",
+       printk(KERN_DEFAULT "Pid: %d, comm: %.20s %s %s %.*s",
                current->pid, current->comm, print_tainted(),
                init_utsname()->release,
                (int)strcspn(init_utsname()->version, " "),
-               init_utsname()->version, board, product);
+               init_utsname()->version);
+       printk(KERN_CONT " %s %s", vendor, product);
+       if (board)
+               printk(KERN_CONT "/%s", board);
+       printk(KERN_CONT "\n");
 }
 
 void flush_thread(void)
@@ -506,7 +513,7 @@ static void poll_idle(void)
 #define MWAIT_ECX_EXTENDED_INFO                0x01
 #define MWAIT_EDX_C1                   0xf0
 
-int __cpuinit mwait_usable(const struct cpuinfo_x86 *c)
+int mwait_usable(const struct cpuinfo_x86 *c)
 {
        u32 eax, ebx, ecx, edx;
 
index fc7aae1..715037c 100644 (file)
@@ -285,6 +285,14 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "P4S800"),
                },
        },
+       {       /* Handle problems with rebooting on VersaLogic Menlow boards */
+               .callback = set_bios_reboot,
+               .ident = "VersaLogic Menlow based board",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "VersaLogic Corporation"),
+                       DMI_MATCH(DMI_BOARD_NAME, "VersaLogic Menlow board"),
+               },
+       },
        { }
 };
 
index 6f39cab..3f2ad26 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/acpi.h>
 #include <linux/bcd.h>
 #include <linux/pnp.h>
+#include <linux/of.h>
 
 #include <asm/vsyscall.h>
 #include <asm/x86_init.h>
@@ -236,6 +237,8 @@ static __init int add_rtc_cmos(void)
                }
        }
 #endif
+       if (of_have_populated_dt())
+               return 0;
 
        platform_device_register(&rtc_device);
        dev_info(&rtc_device.dev,
index d3cfe26..b176f2b 100644 (file)
 #endif
 #include <asm/mce.h>
 #include <asm/alternative.h>
+#include <asm/prom.h>
 
 /*
  * end_pfn only includes RAM, while max_pfn_mapped includes all e820 entries.
@@ -293,10 +294,32 @@ static void __init init_gbpages(void)
        else
                direct_gbpages = 0;
 }
+
+static void __init cleanup_highmap_brk_end(void)
+{
+       pud_t *pud;
+       pmd_t *pmd;
+
+       mmu_cr4_features = read_cr4();
+
+       /*
+        * _brk_end cannot change anymore, but it and _end may be
+        * located on different 2M pages. cleanup_highmap(), however,
+        * can only consider _end when it runs, so destroy any
+        * mappings beyond _brk_end here.
+        */
+       pud = pud_offset(pgd_offset_k(_brk_end), _brk_end);
+       pmd = pmd_offset(pud, _brk_end - 1);
+       while (++pmd <= pmd_offset(pud, (unsigned long)_end - 1))
+               pmd_clear(pmd);
+}
 #else
 static inline void init_gbpages(void)
 {
 }
+static inline void cleanup_highmap_brk_end(void)
+{
+}
 #endif
 
 static void __init reserve_brk(void)
@@ -307,6 +330,8 @@ static void __init reserve_brk(void)
        /* Mark brk area as locked down and no longer taking any
           new allocations */
        _brk_start = 0;
+
+       cleanup_highmap_brk_end();
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -429,16 +454,30 @@ static void __init parse_setup_data(void)
                return;
        pa_data = boot_params.hdr.setup_data;
        while (pa_data) {
-               data = early_memremap(pa_data, PAGE_SIZE);
+               u32 data_len, map_len;
+
+               map_len = max(PAGE_SIZE - (pa_data & ~PAGE_MASK),
+                             (u64)sizeof(struct setup_data));
+               data = early_memremap(pa_data, map_len);
+               data_len = data->len + sizeof(struct setup_data);
+               if (data_len > map_len) {
+                       early_iounmap(data, map_len);
+                       data = early_memremap(pa_data, data_len);
+                       map_len = data_len;
+               }
+
                switch (data->type) {
                case SETUP_E820_EXT:
-                       parse_e820_ext(data, pa_data);
+                       parse_e820_ext(data);
+                       break;
+               case SETUP_DTB:
+                       add_dtb(pa_data);
                        break;
                default:
                        break;
                }
                pa_data = data->next;
-               early_iounmap(data, PAGE_SIZE);
+               early_iounmap(data, map_len);
        }
 }
 
@@ -680,15 +719,6 @@ static int __init parse_reservelow(char *p)
 
 early_param("reservelow", parse_reservelow);
 
-static u64 __init get_max_mapped(void)
-{
-       u64 end = max_pfn_mapped;
-
-       end <<= PAGE_SHIFT;
-
-       return end;
-}
-
 /*
  * Determine if we were loaded by an EFI loader.  If so, then we have also been
  * passed the efi memmap, systab, etc., so we should use these data structures
@@ -704,8 +734,6 @@ static u64 __init get_max_mapped(void)
 
 void __init setup_arch(char **cmdline_p)
 {
-       int acpi = 0;
-       int amd = 0;
        unsigned long flags;
 
 #ifdef CONFIG_X86_32
@@ -984,19 +1012,7 @@ void __init setup_arch(char **cmdline_p)
 
        early_acpi_boot_init();
 
-#ifdef CONFIG_ACPI_NUMA
-       /*
-        * Parse SRAT to discover nodes.
-        */
-       acpi = acpi_numa_init();
-#endif
-
-#ifdef CONFIG_AMD_NUMA
-       if (!acpi)
-               amd = !amd_numa_init(0, max_pfn);
-#endif
-
-       initmem_init(0, max_pfn, acpi, amd);
+       initmem_init();
        memblock_find_dma_reserve();
        dma32_reserve_bootmem();
 
@@ -1029,8 +1045,8 @@ void __init setup_arch(char **cmdline_p)
         * Read APIC and some other early information from ACPI tables.
         */
        acpi_boot_init();
-
        sfi_init();
+       x86_dtb_init();
 
        /*
         * get boot-time SMP configuration:
@@ -1040,9 +1056,7 @@ void __init setup_arch(char **cmdline_p)
 
        prefill_possible_map();
 
-#ifdef CONFIG_X86_64
        init_cpu_to_node();
-#endif
 
        init_apic_mappings();
        ioapic_and_gsi_init();
@@ -1066,6 +1080,8 @@ void __init setup_arch(char **cmdline_p)
 #endif
        x86_init.oem.banner();
 
+       x86_init.timers.wallclock_init();
+
        mcheck_init();
 
        local_irq_save(flags);
index 002b796..71f4727 100644 (file)
@@ -225,10 +225,15 @@ void __init setup_per_cpu_areas(void)
                per_cpu(x86_bios_cpu_apicid, cpu) =
                        early_per_cpu_map(x86_bios_cpu_apicid, cpu);
 #endif
+#ifdef CONFIG_X86_32
+               per_cpu(x86_cpu_to_logical_apicid, cpu) =
+                       early_per_cpu_map(x86_cpu_to_logical_apicid, cpu);
+#endif
 #ifdef CONFIG_X86_64
                per_cpu(irq_stack_ptr, cpu) =
                        per_cpu(irq_stack_union.irq_stack, cpu) +
                        IRQ_STACK_SIZE - 64;
+#endif
 #ifdef CONFIG_NUMA
                per_cpu(x86_cpu_to_node_map, cpu) =
                        early_per_cpu_map(x86_cpu_to_node_map, cpu);
@@ -241,7 +246,6 @@ void __init setup_per_cpu_areas(void)
                 * So set them all (boot cpu and all APs).
                 */
                set_cpu_numa_node(cpu, early_cpu_to_node(cpu));
-#endif
 #endif
                /*
                 * Up to this point, the boot CPU has been using .init.data
@@ -256,7 +260,10 @@ void __init setup_per_cpu_areas(void)
        early_per_cpu_ptr(x86_cpu_to_apicid) = NULL;
        early_per_cpu_ptr(x86_bios_cpu_apicid) = NULL;
 #endif
-#if defined(CONFIG_X86_64) && defined(CONFIG_NUMA)
+#ifdef CONFIG_X86_32
+       early_per_cpu_ptr(x86_cpu_to_logical_apicid) = NULL;
+#endif
+#ifdef CONFIG_NUMA
        early_per_cpu_ptr(x86_cpu_to_node_map) = NULL;
 #endif
 
index 0cbe8c0..e9efdfd 100644 (file)
@@ -64,6 +64,7 @@
 #include <asm/mtrr.h>
 #include <asm/mwait.h>
 #include <asm/apic.h>
+#include <asm/io_apic.h>
 #include <asm/setup.h>
 #include <asm/uv/uv.h>
 #include <linux/mc146818rtc.h>
 #include <asm/smpboot_hooks.h>
 #include <asm/i8259.h>
 
-#ifdef CONFIG_X86_32
-u8 apicid_2_node[MAX_APICID];
-#endif
-
 /* State of each CPU */
 DEFINE_PER_CPU(int, cpu_state) = { 0 };
 
@@ -130,68 +127,14 @@ EXPORT_PER_CPU_SYMBOL(cpu_sibling_map);
 DEFINE_PER_CPU(cpumask_var_t, cpu_core_map);
 EXPORT_PER_CPU_SYMBOL(cpu_core_map);
 
+DEFINE_PER_CPU(cpumask_var_t, cpu_llc_shared_map);
+
 /* Per CPU bogomips and other parameters */
 DEFINE_PER_CPU_SHARED_ALIGNED(struct cpuinfo_x86, cpu_info);
 EXPORT_PER_CPU_SYMBOL(cpu_info);
 
 atomic_t init_deasserted;
 
-#if defined(CONFIG_NUMA) && defined(CONFIG_X86_32)
-/* which node each logical CPU is on */
-int cpu_to_node_map[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = 0 };
-EXPORT_SYMBOL(cpu_to_node_map);
-
-/* set up a mapping between cpu and node. */
-static void map_cpu_to_node(int cpu, int node)
-{
-       printk(KERN_INFO "Mapping cpu %d to node %d\n", cpu, node);
-       cpumask_set_cpu(cpu, node_to_cpumask_map[node]);
-       cpu_to_node_map[cpu] = node;
-}
-
-/* undo a mapping between cpu and node. */
-static void unmap_cpu_to_node(int cpu)
-{
-       int node;
-
-       printk(KERN_INFO "Unmapping cpu %d from all nodes\n", cpu);
-       for (node = 0; node < MAX_NUMNODES; node++)
-               cpumask_clear_cpu(cpu, node_to_cpumask_map[node]);
-       cpu_to_node_map[cpu] = 0;
-}
-#else /* !(CONFIG_NUMA && CONFIG_X86_32) */
-#define map_cpu_to_node(cpu, node)     ({})
-#define unmap_cpu_to_node(cpu) ({})
-#endif
-
-#ifdef CONFIG_X86_32
-static int boot_cpu_logical_apicid;
-
-u8 cpu_2_logical_apicid[NR_CPUS] __read_mostly =
-                                       { [0 ... NR_CPUS-1] = BAD_APICID };
-
-static void map_cpu_to_logical_apicid(void)
-{
-       int cpu = smp_processor_id();
-       int apicid = logical_smp_processor_id();
-       int node = apic->apicid_to_node(apicid);
-
-       if (!node_online(node))
-               node = first_online_node;
-
-       cpu_2_logical_apicid[cpu] = apicid;
-       map_cpu_to_node(cpu, node);
-}
-
-void numa_remove_cpu(int cpu)
-{
-       cpu_2_logical_apicid[cpu] = BAD_APICID;
-       unmap_cpu_to_node(cpu);
-}
-#else
-#define map_cpu_to_logical_apicid()  do {} while (0)
-#endif
-
 /*
  * Report back to the Boot Processor.
  * Running on AP.
@@ -259,7 +202,6 @@ static void __cpuinit smp_callin(void)
                apic->smp_callin_clear_local_apic();
        setup_local_APIC();
        end_local_APIC_setup();
-       map_cpu_to_logical_apicid();
 
        /*
         * Need to setup vector mappings before we enable interrupts.
@@ -355,23 +297,6 @@ notrace static void __cpuinit start_secondary(void *unused)
        cpu_idle();
 }
 
-#ifdef CONFIG_CPUMASK_OFFSTACK
-/* In this case, llc_shared_map is a pointer to a cpumask. */
-static inline void copy_cpuinfo_x86(struct cpuinfo_x86 *dst,
-                                   const struct cpuinfo_x86 *src)
-{
-       struct cpumask *llc = dst->llc_shared_map;
-       *dst = *src;
-       dst->llc_shared_map = llc;
-}
-#else
-static inline void copy_cpuinfo_x86(struct cpuinfo_x86 *dst,
-                                   const struct cpuinfo_x86 *src)
-{
-       *dst = *src;
-}
-#endif /* CONFIG_CPUMASK_OFFSTACK */
-
 /*
  * The bootstrap kernel entry code has set these up. Save them for
  * a given CPU
@@ -381,7 +306,7 @@ void __cpuinit smp_store_cpu_info(int id)
 {
        struct cpuinfo_x86 *c = &cpu_data(id);
 
-       copy_cpuinfo_x86(c, &boot_cpu_data);
+       *c = boot_cpu_data;
        c->cpu_index = id;
        if (id != 0)
                identify_secondary_cpu(c);
@@ -389,15 +314,12 @@ void __cpuinit smp_store_cpu_info(int id)
 
 static void __cpuinit link_thread_siblings(int cpu1, int cpu2)
 {
-       struct cpuinfo_x86 *c1 = &cpu_data(cpu1);
-       struct cpuinfo_x86 *c2 = &cpu_data(cpu2);
-
        cpumask_set_cpu(cpu1, cpu_sibling_mask(cpu2));
        cpumask_set_cpu(cpu2, cpu_sibling_mask(cpu1));
        cpumask_set_cpu(cpu1, cpu_core_mask(cpu2));
        cpumask_set_cpu(cpu2, cpu_core_mask(cpu1));
-       cpumask_set_cpu(cpu1, c2->llc_shared_map);
-       cpumask_set_cpu(cpu2, c1->llc_shared_map);
+       cpumask_set_cpu(cpu1, cpu_llc_shared_mask(cpu2));
+       cpumask_set_cpu(cpu2, cpu_llc_shared_mask(cpu1));
 }
 
 
@@ -414,6 +336,7 @@ void __cpuinit set_cpu_sibling_map(int cpu)
 
                        if (cpu_has(c, X86_FEATURE_TOPOEXT)) {
                                if (c->phys_proc_id == o->phys_proc_id &&
+                                   per_cpu(cpu_llc_id, cpu) == per_cpu(cpu_llc_id, i) &&
                                    c->compute_unit_id == o->compute_unit_id)
                                        link_thread_siblings(cpu, i);
                        } else if (c->phys_proc_id == o->phys_proc_id &&
@@ -425,7 +348,7 @@ void __cpuinit set_cpu_sibling_map(int cpu)
                cpumask_set_cpu(cpu, cpu_sibling_mask(cpu));
        }
 
-       cpumask_set_cpu(cpu, c->llc_shared_map);
+       cpumask_set_cpu(cpu, cpu_llc_shared_mask(cpu));
 
        if (__this_cpu_read(cpu_info.x86_max_cores) == 1) {
                cpumask_copy(cpu_core_mask(cpu), cpu_sibling_mask(cpu));
@@ -436,8 +359,8 @@ void __cpuinit set_cpu_sibling_map(int cpu)
        for_each_cpu(i, cpu_sibling_setup_mask) {
                if (per_cpu(cpu_llc_id, cpu) != BAD_APICID &&
                    per_cpu(cpu_llc_id, cpu) == per_cpu(cpu_llc_id, i)) {
-                       cpumask_set_cpu(i, c->llc_shared_map);
-                       cpumask_set_cpu(cpu, cpu_data(i).llc_shared_map);
+                       cpumask_set_cpu(i, cpu_llc_shared_mask(cpu));
+                       cpumask_set_cpu(cpu, cpu_llc_shared_mask(i));
                }
                if (c->phys_proc_id == cpu_data(i).phys_proc_id) {
                        cpumask_set_cpu(i, cpu_core_mask(cpu));
@@ -476,7 +399,7 @@ const struct cpumask *cpu_coregroup_mask(int cpu)
            !(cpu_has(c, X86_FEATURE_AMD_DCM)))
                return cpu_core_mask(cpu);
        else
-               return c->llc_shared_map;
+               return cpu_llc_shared_mask(cpu);
 }
 
 static void impress_friends(void)
@@ -638,7 +561,7 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
         * target processor state.
         */
        startup_ipi_hook(phys_apicid, (unsigned long) start_secondary,
-                        (unsigned long)stack_start.sp);
+                        stack_start);
 
        /*
         * Run STARTUP IPI loop.
@@ -785,7 +708,7 @@ do_rest:
 #endif
        early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu);
        initial_code = (unsigned long)start_secondary;
-       stack_start.sp = (void *) c_idle.idle->thread.sp;
+       stack_start  = c_idle.idle->thread.sp;
 
        /* start_ip had better be page-aligned! */
        start_ip = setup_trampoline();
@@ -945,6 +868,14 @@ int __cpuinit native_cpu_up(unsigned int cpu)
        return 0;
 }
 
+/**
+ * arch_disable_smp_support() - disables SMP support for x86 at runtime
+ */
+void arch_disable_smp_support(void)
+{
+       disable_ioapic_support();
+}
+
 /*
  * Fall back to non SMP mode after errors.
  *
@@ -960,7 +891,6 @@ static __init void disable_smp(void)
                physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map);
        else
                physid_set_mask_of_physid(0, &phys_cpu_present_map);
-       map_cpu_to_logical_apicid();
        cpumask_set_cpu(0, cpu_sibling_mask(0));
        cpumask_set_cpu(0, cpu_core_mask(0));
 }
@@ -1045,7 +975,7 @@ static int __init smp_sanity_check(unsigned max_cpus)
                                "(tell your hw vendor)\n");
                }
                smpboot_clear_io_apic();
-               arch_disable_smp_support();
+               disable_ioapic_support();
                return -1;
        }
 
@@ -1060,7 +990,7 @@ static int __init smp_sanity_check(unsigned max_cpus)
 
                connect_bsp_APIC();
                setup_local_APIC();
-               end_local_APIC_setup();
+               bsp_end_local_APIC_setup();
                return -1;
        }
 
@@ -1089,21 +1019,19 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
 
        preempt_disable();
        smp_cpu_index_default();
-       memcpy(__this_cpu_ptr(&cpu_info), &boot_cpu_data, sizeof(cpu_info));
-       cpumask_copy(cpu_callin_mask, cpumask_of(0));
-       mb();
+
        /*
         * Setup boot CPU information
         */
        smp_store_cpu_info(0); /* Final full version of the data */
-#ifdef CONFIG_X86_32
-       boot_cpu_logical_apicid = logical_smp_processor_id();
-#endif
+       cpumask_copy(cpu_callin_mask, cpumask_of(0));
+       mb();
+
        current_thread_info()->cpu = 0;  /* needed? */
        for_each_possible_cpu(i) {
                zalloc_cpumask_var(&per_cpu(cpu_sibling_map, i), GFP_KERNEL);
                zalloc_cpumask_var(&per_cpu(cpu_core_map, i), GFP_KERNEL);
-               zalloc_cpumask_var(&cpu_data(i).llc_shared_map, GFP_KERNEL);
+               zalloc_cpumask_var(&per_cpu(cpu_llc_shared_map, i), GFP_KERNEL);
        }
        set_cpu_sibling_map(0);
 
@@ -1137,9 +1065,7 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
        if (!skip_ioapic_setup && nr_ioapics)
                enable_IO_APIC();
 
-       end_local_APIC_setup();
-
-       map_cpu_to_logical_apicid();
+       bsp_end_local_APIC_setup();
 
        if (apic->setup_portio_remap)
                apic->setup_portio_remap();
index b35786d..5f18174 100644 (file)
@@ -340,3 +340,6 @@ ENTRY(sys_call_table)
        .long sys_fanotify_init
        .long sys_fanotify_mark
        .long sys_prlimit64             /* 340 */
+       .long sys_name_to_handle_at
+       .long sys_open_by_handle_at
+       .long sys_clock_adjtime
index cef446f..101c323 100644 (file)
@@ -105,6 +105,7 @@ SECTIONS
                SCHED_TEXT
                LOCK_TEXT
                KPROBES_TEXT
+               ENTRY_TEXT
                IRQENTRY_TEXT
                *(.fixup)
                *(.gnu.warning)
@@ -305,7 +306,7 @@ SECTIONS
        }
 
 #if !defined(CONFIG_X86_64) || !defined(CONFIG_SMP)
-       PERCPU(INTERNODE_CACHE_BYTES, THREAD_SIZE)
+       PERCPU(INTERNODE_CACHE_BYTES, PAGE_SIZE)
 #endif
 
        . = ALIGN(PAGE_SIZE);
index 1b950d1..9796c2f 100644 (file)
@@ -52,6 +52,7 @@ extern void *__memcpy(void *, const void *, __kernel_size_t);
 EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(__memcpy);
+EXPORT_SYMBOL(memmove);
 
 EXPORT_SYMBOL(empty_zero_page);
 #ifndef CONFIG_PARAVIRT
index ceb2911..c11514e 100644 (file)
@@ -70,6 +70,7 @@ struct x86_init_ops x86_init __initdata = {
                .setup_percpu_clockev   = setup_boot_APIC_clock,
                .tsc_pre_init           = x86_init_noop,
                .timer_init             = hpet_time_init,
+               .wallclock_init         = x86_init_noop,
        },
 
        .iommu = {
index 25bd1bc..63fec15 100644 (file)
@@ -1150,8 +1150,8 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
        kvm_load_ldt(svm->host.ldt);
 #ifdef CONFIG_X86_64
        loadsegment(fs, svm->host.fs);
-       load_gs_index(svm->host.gs);
        wrmsrl(MSR_KERNEL_GS_BASE, current->thread.gs);
+       load_gs_index(svm->host.gs);
 #else
        loadsegment(gs, svm->host.gs);
 #endif
@@ -2777,6 +2777,8 @@ static int dr_interception(struct vcpu_svm *svm)
                        kvm_register_write(&svm->vcpu, reg, val);
        }
 
+       skip_emulated_instruction(&svm->vcpu);
+
        return 1;
 }
 
index 1357d7c..db93276 100644 (file)
@@ -62,21 +62,21 @@ TRACE_EVENT(kvm_hv_hypercall,
        TP_ARGS(code, fast, rep_cnt, rep_idx, ingpa, outgpa),
 
        TP_STRUCT__entry(
-               __field(        __u16,          code            )
-               __field(        bool,           fast            )
                __field(        __u16,          rep_cnt         )
                __field(        __u16,          rep_idx         )
                __field(        __u64,          ingpa           )
                __field(        __u64,          outgpa          )
+               __field(        __u16,          code            )
+               __field(        bool,           fast            )
        ),
 
        TP_fast_assign(
-               __entry->code           = code;
-               __entry->fast           = fast;
                __entry->rep_cnt        = rep_cnt;
                __entry->rep_idx        = rep_idx;
                __entry->ingpa          = ingpa;
                __entry->outgpa         = outgpa;
+               __entry->code           = code;
+               __entry->fast           = fast;
        ),
 
        TP_printk("code 0x%x %s cnt 0x%x idx 0x%x in 0x%llx out 0x%llx",
index eba687f..b9ec1c7 100644 (file)
@@ -847,7 +847,7 @@ static void __init lguest_init_IRQ(void)
 void lguest_setup_irq(unsigned int irq)
 {
        irq_alloc_desc_at(irq, 0);
-       set_irq_chip_and_handler_name(irq, &lguest_irq_controller,
+       irq_set_chip_and_handler_name(irq, &lguest_irq_controller,
                                      handle_level_irq, "level");
 }
 
@@ -995,7 +995,7 @@ static void lguest_time_irq(unsigned int irq, struct irq_desc *desc)
 static void lguest_time_init(void)
 {
        /* Set up the timer interrupt (0) to go to our simple timer routine */
-       set_irq_handler(0, lguest_time_irq);
+       irq_set_handler(0, lguest_time_irq);
 
        clocksource_register(&lguest_clock);
 
index 2cda60a..e8e7e0d 100644 (file)
 
 /* if you want SMP support, implement these with real spinlocks */
 .macro LOCK reg
-       pushfl
-       CFI_ADJUST_CFA_OFFSET 4
+       pushfl_cfi
        cli
 .endm
 
 .macro UNLOCK reg
-       popfl
-       CFI_ADJUST_CFA_OFFSET -4
+       popfl_cfi
 .endm
 
 #define BEGIN(op) \
index 71e080d..391a083 100644 (file)
 #include <asm/dwarf2.h>
 
 .macro SAVE reg
-       pushl %\reg
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %\reg
        CFI_REL_OFFSET \reg, 0
 .endm
 
 .macro RESTORE reg
-       popl %\reg
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %\reg
        CFI_RESTORE \reg
 .endm
 
index adbccd0..78d16a5 100644 (file)
@@ -50,11 +50,9 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
           */           
 ENTRY(csum_partial)
        CFI_STARTPROC
-       pushl %esi
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %esi
        CFI_REL_OFFSET esi, 0
-       pushl %ebx
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %ebx
        CFI_REL_OFFSET ebx, 0
        movl 20(%esp),%eax      # Function arg: unsigned int sum
        movl 16(%esp),%ecx      # Function arg: int len
@@ -132,11 +130,9 @@ ENTRY(csum_partial)
        jz 8f
        roll $8, %eax
 8:
-       popl %ebx
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %ebx
        CFI_RESTORE ebx
-       popl %esi
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %esi
        CFI_RESTORE esi
        ret
        CFI_ENDPROC
@@ -148,11 +144,9 @@ ENDPROC(csum_partial)
 
 ENTRY(csum_partial)
        CFI_STARTPROC
-       pushl %esi
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %esi
        CFI_REL_OFFSET esi, 0
-       pushl %ebx
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %ebx
        CFI_REL_OFFSET ebx, 0
        movl 20(%esp),%eax      # Function arg: unsigned int sum
        movl 16(%esp),%ecx      # Function arg: int len
@@ -260,11 +254,9 @@ ENTRY(csum_partial)
        jz 90f
        roll $8, %eax
 90: 
-       popl %ebx
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %ebx
        CFI_RESTORE ebx
-       popl %esi
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %esi
        CFI_RESTORE esi
        ret
        CFI_ENDPROC
@@ -309,14 +301,11 @@ ENTRY(csum_partial_copy_generic)
        CFI_STARTPROC
        subl  $4,%esp   
        CFI_ADJUST_CFA_OFFSET 4
-       pushl %edi
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %edi
        CFI_REL_OFFSET edi, 0
-       pushl %esi
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %esi
        CFI_REL_OFFSET esi, 0
-       pushl %ebx
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %ebx
        CFI_REL_OFFSET ebx, 0
        movl ARGBASE+16(%esp),%eax      # sum
        movl ARGBASE+12(%esp),%ecx      # len
@@ -426,17 +415,13 @@ DST(      movb %cl, (%edi)        )
 
 .previous
 
-       popl %ebx
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %ebx
        CFI_RESTORE ebx
-       popl %esi
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %esi
        CFI_RESTORE esi
-       popl %edi
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %edi
        CFI_RESTORE edi
-       popl %ecx                       # equivalent to addl $4,%esp
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %ecx                   # equivalent to addl $4,%esp
        ret     
        CFI_ENDPROC
 ENDPROC(csum_partial_copy_generic)
@@ -459,14 +444,11 @@ ENDPROC(csum_partial_copy_generic)
                
 ENTRY(csum_partial_copy_generic)
        CFI_STARTPROC
-       pushl %ebx
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %ebx
        CFI_REL_OFFSET ebx, 0
-       pushl %edi
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %edi
        CFI_REL_OFFSET edi, 0
-       pushl %esi
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %esi
        CFI_REL_OFFSET esi, 0
        movl ARGBASE+4(%esp),%esi       #src
        movl ARGBASE+8(%esp),%edi       #dst    
@@ -527,14 +509,11 @@ DST(      movb %dl, (%edi)         )
        jmp  7b                 
 .previous                              
 
-       popl %esi
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %esi
        CFI_RESTORE esi
-       popl %edi
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %edi
        CFI_RESTORE edi
-       popl %ebx
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %ebx
        CFI_RESTORE ebx
        ret
        CFI_ENDPROC
diff --git a/arch/x86/lib/memmove_64.S b/arch/x86/lib/memmove_64.S
new file mode 100644 (file)
index 0000000..0ecb843
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * Normally compiler builtins are used, but sometimes the compiler calls out
+ * of line code. Based on asm-i386/string.h.
+ *
+ * This assembly file is re-written from memmove_64.c file.
+ *     - Copyright 2011 Fenghua Yu <fenghua.yu@intel.com>
+ */
+#define _STRING_C
+#include <linux/linkage.h>
+#include <asm/dwarf2.h>
+
+#undef memmove
+
+/*
+ * Implement memmove(). This can handle overlap between src and dst.
+ *
+ * Input:
+ * rdi: dest
+ * rsi: src
+ * rdx: count
+ *
+ * Output:
+ * rax: dest
+ */
+ENTRY(memmove)
+       CFI_STARTPROC
+       /* Handle more 32bytes in loop */
+       mov %rdi, %rax
+       cmp $0x20, %rdx
+       jb      1f
+
+       /* Decide forward/backward copy mode */
+       cmp %rdi, %rsi
+       jb      2f
+
+       /*
+        * movsq instruction have many startup latency
+        * so we handle small size by general register.
+        */
+       cmp  $680, %rdx
+       jb      3f
+       /*
+        * movsq instruction is only good for aligned case.
+        */
+
+       cmpb %dil, %sil
+       je 4f
+3:
+       sub $0x20, %rdx
+       /*
+        * We gobble 32byts forward in each loop.
+        */
+5:
+       sub $0x20, %rdx
+       movq 0*8(%rsi), %r11
+       movq 1*8(%rsi), %r10
+       movq 2*8(%rsi), %r9
+       movq 3*8(%rsi), %r8
+       leaq 4*8(%rsi), %rsi
+
+       movq %r11, 0*8(%rdi)
+       movq %r10, 1*8(%rdi)
+       movq %r9, 2*8(%rdi)
+       movq %r8, 3*8(%rdi)
+       leaq 4*8(%rdi), %rdi
+       jae 5b
+       addq $0x20, %rdx
+       jmp 1f
+       /*
+        * Handle data forward by movsq.
+        */
+       .p2align 4
+4:
+       movq %rdx, %rcx
+       movq -8(%rsi, %rdx), %r11
+       lea -8(%rdi, %rdx), %r10
+       shrq $3, %rcx
+       rep movsq
+       movq %r11, (%r10)
+       jmp 13f
+       /*
+        * Handle data backward by movsq.
+        */
+       .p2align 4
+7:
+       movq %rdx, %rcx
+       movq (%rsi), %r11
+       movq %rdi, %r10
+       leaq -8(%rsi, %rdx), %rsi
+       leaq -8(%rdi, %rdx), %rdi
+       shrq $3, %rcx
+       std
+       rep movsq
+       cld
+       movq %r11, (%r10)
+       jmp 13f
+
+       /*
+        * Start to prepare for backward copy.
+        */
+       .p2align 4
+2:
+       cmp $680, %rdx
+       jb 6f
+       cmp %dil, %sil
+       je 7b
+6:
+       /*
+        * Calculate copy position to tail.
+        */
+       addq %rdx, %rsi
+       addq %rdx, %rdi
+       subq $0x20, %rdx
+       /*
+        * We gobble 32byts backward in each loop.
+        */
+8:
+       subq $0x20, %rdx
+       movq -1*8(%rsi), %r11
+       movq -2*8(%rsi), %r10
+       movq -3*8(%rsi), %r9
+       movq -4*8(%rsi), %r8
+       leaq -4*8(%rsi), %rsi
+
+       movq %r11, -1*8(%rdi)
+       movq %r10, -2*8(%rdi)
+       movq %r9, -3*8(%rdi)
+       movq %r8, -4*8(%rdi)
+       leaq -4*8(%rdi), %rdi
+       jae 8b
+       /*
+        * Calculate copy position to head.
+        */
+       addq $0x20, %rdx
+       subq %rdx, %rsi
+       subq %rdx, %rdi
+1:
+       cmpq $16, %rdx
+       jb 9f
+       /*
+        * Move data from 16 bytes to 31 bytes.
+        */
+       movq 0*8(%rsi), %r11
+       movq 1*8(%rsi), %r10
+       movq -2*8(%rsi, %rdx), %r9
+       movq -1*8(%rsi, %rdx), %r8
+       movq %r11, 0*8(%rdi)
+       movq %r10, 1*8(%rdi)
+       movq %r9, -2*8(%rdi, %rdx)
+       movq %r8, -1*8(%rdi, %rdx)
+       jmp 13f
+       .p2align 4
+9:
+       cmpq $8, %rdx
+       jb 10f
+       /*
+        * Move data from 8 bytes to 15 bytes.
+        */
+       movq 0*8(%rsi), %r11
+       movq -1*8(%rsi, %rdx), %r10
+       movq %r11, 0*8(%rdi)
+       movq %r10, -1*8(%rdi, %rdx)
+       jmp 13f
+10:
+       cmpq $4, %rdx
+       jb 11f
+       /*
+        * Move data from 4 bytes to 7 bytes.
+        */
+       movl (%rsi), %r11d
+       movl -4(%rsi, %rdx), %r10d
+       movl %r11d, (%rdi)
+       movl %r10d, -4(%rdi, %rdx)
+       jmp 13f
+11:
+       cmp $2, %rdx
+       jb 12f
+       /*
+        * Move data from 2 bytes to 3 bytes.
+        */
+       movw (%rsi), %r11w
+       movw -2(%rsi, %rdx), %r10w
+       movw %r11w, (%rdi)
+       movw %r10w, -2(%rdi, %rdx)
+       jmp 13f
+12:
+       cmp $1, %rdx
+       jb 13f
+       /*
+        * Move data for 1 byte.
+        */
+       movb (%rsi), %r11b
+       movb %r11b, (%rdi)
+13:
+       retq
+       CFI_ENDPROC
+ENDPROC(memmove)
diff --git a/arch/x86/lib/memmove_64.c b/arch/x86/lib/memmove_64.c
deleted file mode 100644 (file)
index 6d0f0ec..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/* Normally compiler builtins are used, but sometimes the compiler calls out
-   of line code. Based on asm-i386/string.h.
- */
-#define _STRING_C
-#include <linux/string.h>
-#include <linux/module.h>
-
-#undef memmove
-void *memmove(void *dest, const void *src, size_t count)
-{
-       unsigned long d0,d1,d2,d3,d4,d5,d6,d7;
-       char *ret;
-
-       __asm__ __volatile__(
-               /* Handle more 32bytes in loop */
-               "mov %2, %3\n\t"
-               "cmp $0x20, %0\n\t"
-               "jb     1f\n\t"
-
-               /* Decide forward/backward copy mode */
-               "cmp %2, %1\n\t"
-               "jb     2f\n\t"
-
-               /*
-                * movsq instruction have many startup latency
-                * so we handle small size by general register.
-                */
-               "cmp  $680, %0\n\t"
-               "jb 3f\n\t"
-               /*
-                * movsq instruction is only good for aligned case.
-                */
-               "cmpb %%dil, %%sil\n\t"
-               "je 4f\n\t"
-               "3:\n\t"
-               "sub $0x20, %0\n\t"
-               /*
-                * We gobble 32byts forward in each loop.
-                */
-               "5:\n\t"
-               "sub $0x20, %0\n\t"
-               "movq 0*8(%1), %4\n\t"
-               "movq 1*8(%1), %5\n\t"
-               "movq 2*8(%1), %6\n\t"
-               "movq 3*8(%1), %7\n\t"
-               "leaq 4*8(%1), %1\n\t"
-
-               "movq %4, 0*8(%2)\n\t"
-               "movq %5, 1*8(%2)\n\t"
-               "movq %6, 2*8(%2)\n\t"
-               "movq %7, 3*8(%2)\n\t"
-               "leaq 4*8(%2), %2\n\t"
-               "jae 5b\n\t"
-               "addq $0x20, %0\n\t"
-               "jmp 1f\n\t"
-               /*
-                * Handle data forward by movsq.
-                */
-               ".p2align 4\n\t"
-               "4:\n\t"
-               "movq %0, %8\n\t"
-               "movq -8(%1, %0), %4\n\t"
-               "lea -8(%2, %0), %5\n\t"
-               "shrq $3, %8\n\t"
-               "rep movsq\n\t"
-               "movq %4, (%5)\n\t"
-               "jmp 13f\n\t"
-               /*
-                * Handle data backward by movsq.
-                */
-               ".p2align 4\n\t"
-               "7:\n\t"
-               "movq %0, %8\n\t"
-               "movq (%1), %4\n\t"
-               "movq %2, %5\n\t"
-               "leaq -8(%1, %0), %1\n\t"
-               "leaq -8(%2, %0), %2\n\t"
-               "shrq $3, %8\n\t"
-               "std\n\t"
-               "rep movsq\n\t"
-               "cld\n\t"
-               "movq %4, (%5)\n\t"
-               "jmp 13f\n\t"
-
-               /*
-                * Start to prepare for backward copy.
-                */
-               ".p2align 4\n\t"
-               "2:\n\t"
-               "cmp $680, %0\n\t"
-               "jb 6f \n\t"
-               "cmp %%dil, %%sil\n\t"
-               "je 7b \n\t"
-               "6:\n\t"
-               /*
-                * Calculate copy position to tail.
-                */
-               "addq %0, %1\n\t"
-               "addq %0, %2\n\t"
-               "subq $0x20, %0\n\t"
-               /*
-                * We gobble 32byts backward in each loop.
-                */
-               "8:\n\t"
-               "subq $0x20, %0\n\t"
-               "movq -1*8(%1), %4\n\t"
-               "movq -2*8(%1), %5\n\t"
-               "movq -3*8(%1), %6\n\t"
-               "movq -4*8(%1), %7\n\t"
-               "leaq -4*8(%1), %1\n\t"
-
-               "movq %4, -1*8(%2)\n\t"
-               "movq %5, -2*8(%2)\n\t"
-               "movq %6, -3*8(%2)\n\t"
-               "movq %7, -4*8(%2)\n\t"
-               "leaq -4*8(%2), %2\n\t"
-               "jae 8b\n\t"
-               /*
-                * Calculate copy position to head.
-                */
-               "addq $0x20, %0\n\t"
-               "subq %0, %1\n\t"
-               "subq %0, %2\n\t"
-               "1:\n\t"
-               "cmpq $16, %0\n\t"
-               "jb 9f\n\t"
-               /*
-                * Move data from 16 bytes to 31 bytes.
-                */
-               "movq 0*8(%1), %4\n\t"
-               "movq 1*8(%1), %5\n\t"
-               "movq -2*8(%1, %0), %6\n\t"
-               "movq -1*8(%1, %0), %7\n\t"
-               "movq %4, 0*8(%2)\n\t"
-               "movq %5, 1*8(%2)\n\t"
-               "movq %6, -2*8(%2, %0)\n\t"
-               "movq %7, -1*8(%2, %0)\n\t"
-               "jmp 13f\n\t"
-               ".p2align 4\n\t"
-               "9:\n\t"
-               "cmpq $8, %0\n\t"
-               "jb 10f\n\t"
-               /*
-                * Move data from 8 bytes to 15 bytes.
-                */
-               "movq 0*8(%1), %4\n\t"
-               "movq -1*8(%1, %0), %5\n\t"
-               "movq %4, 0*8(%2)\n\t"
-               "movq %5, -1*8(%2, %0)\n\t"
-               "jmp 13f\n\t"
-               "10:\n\t"
-               "cmpq $4, %0\n\t"
-               "jb 11f\n\t"
-               /*
-                * Move data from 4 bytes to 7 bytes.
-                */
-               "movl (%1), %4d\n\t"
-               "movl -4(%1, %0), %5d\n\t"
-               "movl %4d, (%2)\n\t"
-               "movl %5d, -4(%2, %0)\n\t"
-               "jmp 13f\n\t"
-               "11:\n\t"
-               "cmp $2, %0\n\t"
-               "jb 12f\n\t"
-               /*
-                * Move data from 2 bytes to 3 bytes.
-                */
-               "movw (%1), %4w\n\t"
-               "movw -2(%1, %0), %5w\n\t"
-               "movw %4w, (%2)\n\t"
-               "movw %5w, -2(%2, %0)\n\t"
-               "jmp 13f\n\t"
-               "12:\n\t"
-               "cmp $1, %0\n\t"
-               "jb 13f\n\t"
-               /*
-                * Move data for 1 byte.
-                */
-               "movb (%1), %4b\n\t"
-               "movb %4b, (%2)\n\t"
-               "13:\n\t"
-               : "=&d" (d0), "=&S" (d1), "=&D" (d2), "=&a" (ret) ,
-                 "=r"(d3), "=r"(d4), "=r"(d5), "=r"(d6), "=&c" (d7)
-               :"0" (count),
-                "1" (src),
-                "2" (dest)
-               :"memory");
-
-               return ret;
-
-}
-EXPORT_SYMBOL(memmove);
index 41fcf00..6774397 100644 (file)
 #include <asm/dwarf2.h>
 
 #define save_common_regs \
-       pushq %rdi; \
-       pushq %rsi; \
-       pushq %rcx; \
-       pushq %r8; \
-       pushq %r9; \
-       pushq %r10; \
-       pushq %r11
+       pushq_cfi %rdi; CFI_REL_OFFSET rdi, 0; \
+       pushq_cfi %rsi; CFI_REL_OFFSET rsi, 0; \
+       pushq_cfi %rcx; CFI_REL_OFFSET rcx, 0; \
+       pushq_cfi %r8;  CFI_REL_OFFSET r8,  0; \
+       pushq_cfi %r9;  CFI_REL_OFFSET r9,  0; \
+       pushq_cfi %r10; CFI_REL_OFFSET r10, 0; \
+       pushq_cfi %r11; CFI_REL_OFFSET r11, 0
 
 #define restore_common_regs \
-       popq %r11; \
-       popq %r10; \
-       popq %r9; \
-       popq %r8; \
-       popq %rcx; \
-       popq %rsi; \
-       popq %rdi
+       popq_cfi %r11; CFI_RESTORE r11; \
+       popq_cfi %r10; CFI_RESTORE r10; \
+       popq_cfi %r9;  CFI_RESTORE r9; \
+       popq_cfi %r8;  CFI_RESTORE r8; \
+       popq_cfi %rcx; CFI_RESTORE rcx; \
+       popq_cfi %rsi; CFI_RESTORE rsi; \
+       popq_cfi %rdi; CFI_RESTORE rdi
 
 /* Fix up special calling conventions */
 ENTRY(call_rwsem_down_read_failed)
+       CFI_STARTPROC
        save_common_regs
-       pushq %rdx
+       pushq_cfi %rdx
+       CFI_REL_OFFSET rdx, 0
        movq %rax,%rdi
        call rwsem_down_read_failed
-       popq %rdx
+       popq_cfi %rdx
+       CFI_RESTORE rdx
        restore_common_regs
        ret
-       ENDPROC(call_rwsem_down_read_failed)
+       CFI_ENDPROC
+ENDPROC(call_rwsem_down_read_failed)
 
 ENTRY(call_rwsem_down_write_failed)
+       CFI_STARTPROC
        save_common_regs
        movq %rax,%rdi
        call rwsem_down_write_failed
        restore_common_regs
        ret
-       ENDPROC(call_rwsem_down_write_failed)
+       CFI_ENDPROC
+ENDPROC(call_rwsem_down_write_failed)
 
 ENTRY(call_rwsem_wake)
+       CFI_STARTPROC
        decl %edx       /* do nothing if still outstanding active readers */
        jnz 1f
        save_common_regs
@@ -67,15 +74,20 @@ ENTRY(call_rwsem_wake)
        call rwsem_wake
        restore_common_regs
 1:     ret
-       ENDPROC(call_rwsem_wake)
+       CFI_ENDPROC
+ENDPROC(call_rwsem_wake)
 
 /* Fix up special calling conventions */
 ENTRY(call_rwsem_downgrade_wake)
+       CFI_STARTPROC
        save_common_regs
-       pushq %rdx
+       pushq_cfi %rdx
+       CFI_REL_OFFSET rdx, 0
        movq %rax,%rdi
        call rwsem_downgrade_wake
-       popq %rdx
+       popq_cfi %rdx
+       CFI_RESTORE rdx
        restore_common_regs
        ret
-       ENDPROC(call_rwsem_downgrade_wake)
+       CFI_ENDPROC
+ENDPROC(call_rwsem_downgrade_wake)
index 648fe47..06691da 100644 (file)
@@ -36,7 +36,7 @@
  */
 #ifdef CONFIG_SMP
 ENTRY(__write_lock_failed)
-       CFI_STARTPROC simple
+       CFI_STARTPROC
        FRAME
 2:     LOCK_PREFIX
        addl    $ RW_LOCK_BIAS,(%eax)
@@ -74,29 +74,23 @@ ENTRY(__read_lock_failed)
 /* Fix up special calling conventions */
 ENTRY(call_rwsem_down_read_failed)
        CFI_STARTPROC
-       push %ecx
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %ecx
        CFI_REL_OFFSET ecx,0
-       push %edx
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %edx
        CFI_REL_OFFSET edx,0
        call rwsem_down_read_failed
-       pop %edx
-       CFI_ADJUST_CFA_OFFSET -4
-       pop %ecx
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %edx
+       popl_cfi %ecx
        ret
        CFI_ENDPROC
        ENDPROC(call_rwsem_down_read_failed)
 
 ENTRY(call_rwsem_down_write_failed)
        CFI_STARTPROC
-       push %ecx
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %ecx
        CFI_REL_OFFSET ecx,0
        calll rwsem_down_write_failed
-       pop %ecx
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %ecx
        ret
        CFI_ENDPROC
        ENDPROC(call_rwsem_down_write_failed)
@@ -105,12 +99,10 @@ ENTRY(call_rwsem_wake)
        CFI_STARTPROC
        decw %dx    /* do nothing if still outstanding active readers */
        jnz 1f
-       push %ecx
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %ecx
        CFI_REL_OFFSET ecx,0
        call rwsem_wake
-       pop %ecx
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %ecx
 1:     ret
        CFI_ENDPROC
        ENDPROC(call_rwsem_wake)
@@ -118,17 +110,13 @@ ENTRY(call_rwsem_wake)
 /* Fix up special calling conventions */
 ENTRY(call_rwsem_downgrade_wake)
        CFI_STARTPROC
-       push %ecx
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %ecx
        CFI_REL_OFFSET ecx,0
-       push %edx
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %edx
        CFI_REL_OFFSET edx,0
        call rwsem_downgrade_wake
-       pop %edx
-       CFI_ADJUST_CFA_OFFSET -4
-       pop %ecx
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %edx
+       popl_cfi %ecx
        ret
        CFI_ENDPROC
        ENDPROC(call_rwsem_downgrade_wake)
index 650b11e..2930ae0 100644 (file)
@@ -7,24 +7,6 @@
 
        #include <linux/linkage.h>
 
-#define ARCH_TRACE_IRQS_ON                     \
-       pushl %eax;                             \
-       pushl %ecx;                             \
-       pushl %edx;                             \
-       call trace_hardirqs_on;                 \
-       popl %edx;                              \
-       popl %ecx;                              \
-       popl %eax;
-
-#define ARCH_TRACE_IRQS_OFF                    \
-       pushl %eax;                             \
-       pushl %ecx;                             \
-       pushl %edx;                             \
-       call trace_hardirqs_off;                \
-       popl %edx;                              \
-       popl %ecx;                              \
-       popl %eax;
-
 #ifdef CONFIG_TRACE_IRQFLAGS
        /* put return address in eax (arg1) */
        .macro thunk_ra name,func
index bf9a7d5..782b082 100644 (file)
        CFI_ENDPROC
        .endm
 
-       /* rdi: arg1 ... normal C conventions. rax is passed from C. */         
-       .macro thunk_retrax name,func
-       .globl \name
-\name: 
-       CFI_STARTPROC
-       SAVE_ARGS
-       call \func
-       jmp  restore_norax
-       CFI_ENDPROC
-       .endm
-       
-
-       .section .sched.text, "ax"
-#ifdef CONFIG_RWSEM_XCHGADD_ALGORITHM
-       thunk rwsem_down_read_failed_thunk,rwsem_down_read_failed
-       thunk rwsem_down_write_failed_thunk,rwsem_down_write_failed
-       thunk rwsem_wake_thunk,rwsem_wake
-       thunk rwsem_downgrade_thunk,rwsem_downgrade_wake
-#endif 
-       
 #ifdef CONFIG_TRACE_IRQFLAGS
        /* put return address in rdi (arg1) */
        .macro thunk_ra name,func
@@ -72,10 +52,3 @@ restore:
        RESTORE_ARGS
        ret     
        CFI_ENDPROC
-       
-       CFI_STARTPROC
-       SAVE_ARGS
-restore_norax: 
-       RESTORE_ARGS 1
-       ret
-       CFI_ENDPROC
index 09df2f9..3e608ed 100644 (file)
@@ -25,6 +25,7 @@ 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_NUMA_EMU)         += numa_emulation.o
 
 obj-$(CONFIG_HAVE_MEMBLOCK)            += memblock.o
 
index f21962c..0919c26 100644 (file)
@@ -26,9 +26,7 @@
 #include <asm/apic.h>
 #include <asm/amd_nb.h>
 
-static struct bootnode __initdata nodes[8];
 static unsigned char __initdata nodeids[8];
-static nodemask_t __initdata nodes_parsed = NODE_MASK_NONE;
 
 static __init int find_northbridge(void)
 {
@@ -51,7 +49,7 @@ static __init int find_northbridge(void)
                return num;
        }
 
-       return -1;
+       return -ENOENT;
 }
 
 static __init void early_get_boot_cpu_id(void)
@@ -69,17 +67,18 @@ static __init void early_get_boot_cpu_id(void)
 #endif
 }
 
-int __init amd_numa_init(unsigned long start_pfn, unsigned long end_pfn)
+int __init amd_numa_init(void)
 {
-       unsigned long start = PFN_PHYS(start_pfn);
-       unsigned long end = PFN_PHYS(end_pfn);
+       unsigned long start = PFN_PHYS(0);
+       unsigned long end = PFN_PHYS(max_pfn);
        unsigned numnodes;
        unsigned long prevbase;
-       int i, nb, found = 0;
+       int i, j, nb;
        u32 nodeid, reg;
+       unsigned int bits, cores, apicid_base;
 
        if (!early_pci_allowed())
-               return -1;
+               return -EINVAL;
 
        nb = find_northbridge();
        if (nb < 0)
@@ -90,7 +89,7 @@ int __init amd_numa_init(unsigned long start_pfn, unsigned long end_pfn)
        reg = read_pci_config(0, nb, 0, 0x60);
        numnodes = ((reg >> 4) & 0xF) + 1;
        if (numnodes <= 1)
-               return -1;
+               return -ENOENT;
 
        pr_info("Number of physical nodes %d\n", numnodes);
 
@@ -121,9 +120,9 @@ int __init amd_numa_init(unsigned long start_pfn, unsigned long end_pfn)
                if ((base >> 8) & 3 || (limit >> 8) & 3) {
                        pr_err("Node %d using interleaving mode %lx/%lx\n",
                               nodeid, (base >> 8) & 3, (limit >> 8) & 3);
-                       return -1;
+                       return -EINVAL;
                }
-               if (node_isset(nodeid, nodes_parsed)) {
+               if (node_isset(nodeid, numa_nodes_parsed)) {
                        pr_info("Node %d already present, skipping\n",
                                nodeid);
                        continue;
@@ -160,117 +159,28 @@ int __init amd_numa_init(unsigned long start_pfn, unsigned long end_pfn)
                if (prevbase > base) {
                        pr_err("Node map not sorted %lx,%lx\n",
                               prevbase, base);
-                       return -1;
+                       return -EINVAL;
                }
 
                pr_info("Node %d MemBase %016lx Limit %016lx\n",
                        nodeid, base, limit);
 
-               found++;
-
-               nodes[nodeid].start = base;
-               nodes[nodeid].end = limit;
-
                prevbase = base;
-
-               node_set(nodeid, nodes_parsed);
-       }
-
-       if (!found)
-               return -1;
-       return 0;
-}
-
-#ifdef CONFIG_NUMA_EMU
-static s16 fake_apicid_to_node[MAX_LOCAL_APIC] __initdata = {
-       [0 ... MAX_LOCAL_APIC-1] = NUMA_NO_NODE
-};
-
-void __init amd_get_nodes(struct bootnode *physnodes)
-{
-       int i;
-
-       for_each_node_mask(i, nodes_parsed) {
-               physnodes[i].start = nodes[i].start;
-               physnodes[i].end = nodes[i].end;
+               numa_add_memblk(nodeid, base, limit);
+               node_set(nodeid, numa_nodes_parsed);
        }
-}
-
-static int __init find_node_by_addr(unsigned long addr)
-{
-       int ret = NUMA_NO_NODE;
-       int i;
-
-       for (i = 0; i < 8; i++)
-               if (addr >= nodes[i].start && addr < nodes[i].end) {
-                       ret = i;
-                       break;
-               }
-       return ret;
-}
 
-/*
- * For NUMA emulation, fake proximity domain (_PXM) to node id mappings must be
- * setup to represent the physical topology but reflect the emulated
- * environment.  For each emulated node, the real node which it appears on is
- * found and a fake pxm to nid mapping is created which mirrors the actual
- * locality.  node_distance() then represents the correct distances between
- * emulated nodes by using the fake acpi mappings to pxms.
- */
-void __init amd_fake_nodes(const struct bootnode *nodes, int nr_nodes)
-{
-       unsigned int bits;
-       unsigned int cores;
-       unsigned int apicid_base = 0;
-       int i;
+       if (!nodes_weight(numa_nodes_parsed))
+               return -ENOENT;
 
+       /*
+        * We seem to have valid NUMA configuration.  Map apicids to nodes
+        * using the coreid bits from early_identify_cpu.
+        */
        bits = boot_cpu_data.x86_coreid_bits;
        cores = 1 << bits;
-       early_get_boot_cpu_id();
-       if (boot_cpu_physical_apicid > 0)
-               apicid_base = boot_cpu_physical_apicid;
-
-       for (i = 0; i < nr_nodes; i++) {
-               int index;
-               int nid;
-               int j;
-
-               nid = find_node_by_addr(nodes[i].start);
-               if (nid == NUMA_NO_NODE)
-                       continue;
-
-               index = nodeids[nid] << bits;
-               if (fake_apicid_to_node[index + apicid_base] == NUMA_NO_NODE)
-                       for (j = apicid_base; j < cores + apicid_base; j++)
-                               fake_apicid_to_node[index + j] = i;
-#ifdef CONFIG_ACPI_NUMA
-               __acpi_map_pxm_to_node(nid, i);
-#endif
-       }
-       memcpy(apicid_to_node, fake_apicid_to_node, sizeof(apicid_to_node));
-}
-#endif /* CONFIG_NUMA_EMU */
-
-int __init amd_scan_nodes(void)
-{
-       unsigned int bits;
-       unsigned int cores;
-       unsigned int apicid_base;
-       int i;
-
-       BUG_ON(nodes_empty(nodes_parsed));
-       node_possible_map = nodes_parsed;
-       memnode_shift = compute_hash_shift(nodes, 8, NULL);
-       if (memnode_shift < 0) {
-               pr_err("No NUMA node hash function found. Contact maintainer\n");
-               return -1;
-       }
-       pr_info("Using node hash shift of %d\n", memnode_shift);
-
-       /* use the coreid bits from early_identify_cpu */
-       bits = boot_cpu_data.x86_coreid_bits;
-       cores = (1<<bits);
        apicid_base = 0;
+
        /* get the APIC ID of the BSP early for systems with apicid lifting */
        early_get_boot_cpu_id();
        if (boot_cpu_physical_apicid > 0) {
@@ -278,17 +188,9 @@ int __init amd_scan_nodes(void)
                apicid_base = boot_cpu_physical_apicid;
        }
 
-       for_each_node_mask(i, node_possible_map) {
-               int j;
-
-               memblock_x86_register_active_regions(i,
-                               nodes[i].start >> PAGE_SHIFT,
-                               nodes[i].end >> PAGE_SHIFT);
+       for_each_node_mask(i, numa_nodes_parsed)
                for (j = apicid_base; j < cores + apicid_base; j++)
-                       apicid_to_node[(i << bits) + j] = i;
-               setup_node_bootmem(i, nodes[i].start, nodes[i].end);
-       }
+                       set_apicid_to_node((i << bits) + j, i);
 
-       numa_init_array();
        return 0;
 }
index 7d90ceb..20e3f87 100644 (file)
@@ -229,15 +229,14 @@ void vmalloc_sync_all(void)
        for (address = VMALLOC_START & PMD_MASK;
             address >= TASK_SIZE && address < FIXADDR_TOP;
             address += PMD_SIZE) {
-
-               unsigned long flags;
                struct page *page;
 
-               spin_lock_irqsave(&pgd_lock, flags);
+               spin_lock(&pgd_lock);
                list_for_each_entry(page, &pgd_list, lru) {
                        spinlock_t *pgt_lock;
                        pmd_t *ret;
 
+                       /* the pgt_lock only for Xen */
                        pgt_lock = &pgd_page_get_mm(page)->page_table_lock;
 
                        spin_lock(pgt_lock);
@@ -247,7 +246,7 @@ void vmalloc_sync_all(void)
                        if (!ret)
                                break;
                }
-               spin_unlock_irqrestore(&pgd_lock, flags);
+               spin_unlock(&pgd_lock);
        }
 }
 
@@ -828,6 +827,13 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code,
               unsigned long address, unsigned int fault)
 {
        if (fault & VM_FAULT_OOM) {
+               /* Kernel mode? Handle exceptions or die: */
+               if (!(error_code & PF_USER)) {
+                       up_read(&current->mm->mmap_sem);
+                       no_context(regs, error_code, address);
+                       return;
+               }
+
                out_of_memory(regs, error_code, address);
        } else {
                if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|
index 947f42a..286d289 100644 (file)
@@ -18,9 +18,9 @@
 
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
-unsigned long __initdata e820_table_start;
-unsigned long __meminitdata e820_table_end;
-unsigned long __meminitdata e820_table_top;
+unsigned long __initdata pgt_buf_start;
+unsigned long __meminitdata pgt_buf_end;
+unsigned long __meminitdata pgt_buf_top;
 
 int after_bootmem;
 
@@ -33,7 +33,7 @@ int direct_gbpages
 static void __init find_early_table_space(unsigned long end, int use_pse,
                                          int use_gbpages)
 {
-       unsigned long puds, pmds, ptes, tables, start;
+       unsigned long puds, pmds, ptes, tables, start = 0, good_end = end;
        phys_addr_t base;
 
        puds = (end + PUD_SIZE - 1) >> PUD_SHIFT;
@@ -65,29 +65,20 @@ static void __init find_early_table_space(unsigned long end, int use_pse,
 #ifdef CONFIG_X86_32
        /* for fixmap */
        tables += roundup(__end_of_fixed_addresses * sizeof(pte_t), PAGE_SIZE);
-#endif
 
-       /*
-        * RED-PEN putting page tables only on node 0 could
-        * cause a hotspot and fill up ZONE_DMA. The page tables
-        * need roughly 0.5KB per GB.
-        */
-#ifdef CONFIG_X86_32
-       start = 0x7000;
-#else
-       start = 0x8000;
+       good_end = max_pfn_mapped << PAGE_SHIFT;
 #endif
-       base = memblock_find_in_range(start, max_pfn_mapped<<PAGE_SHIFT,
-                                       tables, PAGE_SIZE);
+
+       base = memblock_find_in_range(start, good_end, tables, PAGE_SIZE);
        if (base == MEMBLOCK_ERROR)
                panic("Cannot find space for the kernel page tables");
 
-       e820_table_start = base >> PAGE_SHIFT;
-       e820_table_end = e820_table_start;
-       e820_table_top = e820_table_start + (tables >> PAGE_SHIFT);
+       pgt_buf_start = base >> PAGE_SHIFT;
+       pgt_buf_end = pgt_buf_start;
+       pgt_buf_top = pgt_buf_start + (tables >> PAGE_SHIFT);
 
        printk(KERN_DEBUG "kernel direct mapping tables up to %lx @ %lx-%lx\n",
-               end, e820_table_start << PAGE_SHIFT, e820_table_top << PAGE_SHIFT);
+               end, pgt_buf_start << PAGE_SHIFT, pgt_buf_top << PAGE_SHIFT);
 }
 
 struct map_range {
@@ -279,30 +270,11 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
        load_cr3(swapper_pg_dir);
 #endif
 
-#ifdef CONFIG_X86_64
-       if (!after_bootmem && !start) {
-               pud_t *pud;
-               pmd_t *pmd;
-
-               mmu_cr4_features = read_cr4();
-
-               /*
-                * _brk_end cannot change anymore, but it and _end may be
-                * located on different 2M pages. cleanup_highmap(), however,
-                * can only consider _end when it runs, so destroy any
-                * mappings beyond _brk_end here.
-                */
-               pud = pud_offset(pgd_offset_k(_brk_end), _brk_end);
-               pmd = pmd_offset(pud, _brk_end - 1);
-               while (++pmd <= pmd_offset(pud, (unsigned long)_end - 1))
-                       pmd_clear(pmd);
-       }
-#endif
        __flush_tlb_all();
 
-       if (!after_bootmem && e820_table_end > e820_table_start)
-               memblock_x86_reserve_range(e820_table_start << PAGE_SHIFT,
-                                e820_table_end << PAGE_SHIFT, "PGTABLE");
+       if (!after_bootmem && pgt_buf_end > pgt_buf_start)
+               memblock_x86_reserve_range(pgt_buf_start << PAGE_SHIFT,
+                                pgt_buf_end << PAGE_SHIFT, "PGTABLE");
 
        if (!after_bootmem)
                early_memtest(start, end);
index c821074..73ad7eb 100644 (file)
@@ -62,10 +62,10 @@ bool __read_mostly __vmalloc_start_set = false;
 
 static __init void *alloc_low_page(void)
 {
-       unsigned long pfn = e820_table_end++;
+       unsigned long pfn = pgt_buf_end++;
        void *adr;
 
-       if (pfn >= e820_table_top)
+       if (pfn >= pgt_buf_top)
                panic("alloc_low_page: ran out of memory");
 
        adr = __va(pfn * PAGE_SIZE);
@@ -163,8 +163,8 @@ static pte_t *__init page_table_kmap_check(pte_t *pte, pmd_t *pmd,
        if (pmd_idx_kmap_begin != pmd_idx_kmap_end
            && (vaddr >> PMD_SHIFT) >= pmd_idx_kmap_begin
            && (vaddr >> PMD_SHIFT) <= pmd_idx_kmap_end
-           && ((__pa(pte) >> PAGE_SHIFT) < e820_table_start
-               || (__pa(pte) >> PAGE_SHIFT) >= e820_table_end)) {
+           && ((__pa(pte) >> PAGE_SHIFT) < pgt_buf_start
+               || (__pa(pte) >> PAGE_SHIFT) >= pgt_buf_end)) {
                pte_t *newpte;
                int i;
 
@@ -644,8 +644,7 @@ void __init find_low_pfn_range(void)
 }
 
 #ifndef CONFIG_NEED_MULTIPLE_NODES
-void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn,
-                               int acpi, int k8)
+void __init initmem_init(void)
 {
 #ifdef CONFIG_HIGHMEM
        highstart_pfn = highend_pfn = max_pfn;
index 71a5929..a08a62c 100644 (file)
@@ -105,18 +105,18 @@ void sync_global_pgds(unsigned long start, unsigned long end)
 
        for (address = start; address <= end; address += PGDIR_SIZE) {
                const pgd_t *pgd_ref = pgd_offset_k(address);
-               unsigned long flags;
                struct page *page;
 
                if (pgd_none(*pgd_ref))
                        continue;
 
-               spin_lock_irqsave(&pgd_lock, flags);
+               spin_lock(&pgd_lock);
                list_for_each_entry(page, &pgd_list, lru) {
                        pgd_t *pgd;
                        spinlock_t *pgt_lock;
 
                        pgd = (pgd_t *)page_address(page) + pgd_index(address);
+                       /* the pgt_lock only for Xen */
                        pgt_lock = &pgd_page_get_mm(page)->page_table_lock;
                        spin_lock(pgt_lock);
 
@@ -128,7 +128,7 @@ void sync_global_pgds(unsigned long start, unsigned long end)
 
                        spin_unlock(pgt_lock);
                }
-               spin_unlock_irqrestore(&pgd_lock, flags);
+               spin_unlock(&pgd_lock);
        }
 }
 
@@ -314,7 +314,7 @@ void __init cleanup_highmap(void)
 
 static __ref void *alloc_low_page(unsigned long *phys)
 {
-       unsigned long pfn = e820_table_end++;
+       unsigned long pfn = pgt_buf_end++;
        void *adr;
 
        if (after_bootmem) {
@@ -324,7 +324,7 @@ static __ref void *alloc_low_page(unsigned long *phys)
                return adr;
        }
 
-       if (pfn >= e820_table_top)
+       if (pfn >= pgt_buf_top)
                panic("alloc_low_page: ran out of memory");
 
        adr = early_memremap(pfn * PAGE_SIZE, PAGE_SIZE);
@@ -333,12 +333,28 @@ static __ref void *alloc_low_page(unsigned long *phys)
        return adr;
 }
 
+static __ref void *map_low_page(void *virt)
+{
+       void *adr;
+       unsigned long phys, left;
+
+       if (after_bootmem)
+               return virt;
+
+       phys = __pa(virt);
+       left = phys & (PAGE_SIZE - 1);
+       adr = early_memremap(phys & PAGE_MASK, PAGE_SIZE);
+       adr = (void *)(((unsigned long)adr) | left);
+
+       return adr;
+}
+
 static __ref void unmap_low_page(void *adr)
 {
        if (after_bootmem)
                return;
 
-       early_iounmap(adr, PAGE_SIZE);
+       early_iounmap((void *)((unsigned long)adr & PAGE_MASK), PAGE_SIZE);
 }
 
 static unsigned long __meminit
@@ -385,15 +401,6 @@ phys_pte_init(pte_t *pte_page, unsigned long addr, unsigned long end,
        return last_map_addr;
 }
 
-static unsigned long __meminit
-phys_pte_update(pmd_t *pmd, unsigned long address, unsigned long end,
-               pgprot_t prot)
-{
-       pte_t *pte = (pte_t *)pmd_page_vaddr(*pmd);
-
-       return phys_pte_init(pte, address, end, prot);
-}
-
 static unsigned long __meminit
 phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
              unsigned long page_size_mask, pgprot_t prot)
@@ -420,8 +427,10 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
                if (pmd_val(*pmd)) {
                        if (!pmd_large(*pmd)) {
                                spin_lock(&init_mm.page_table_lock);
-                               last_map_addr = phys_pte_update(pmd, address,
+                               pte = map_low_page((pte_t *)pmd_page_vaddr(*pmd));
+                               last_map_addr = phys_pte_init(pte, address,
                                                                end, prot);
+                               unmap_low_page(pte);
                                spin_unlock(&init_mm.page_table_lock);
                                continue;
                        }
@@ -467,18 +476,6 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
        return last_map_addr;
 }
 
-static unsigned long __meminit
-phys_pmd_update(pud_t *pud, unsigned long address, unsigned long end,
-               unsigned long page_size_mask, pgprot_t prot)
-{
-       pmd_t *pmd = pmd_offset(pud, 0);
-       unsigned long last_map_addr;
-
-       last_map_addr = phys_pmd_init(pmd, address, end, page_size_mask, prot);
-       __flush_tlb_all();
-       return last_map_addr;
-}
-
 static unsigned long __meminit
 phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,
                         unsigned long page_size_mask)
@@ -504,8 +501,11 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,
 
                if (pud_val(*pud)) {
                        if (!pud_large(*pud)) {
-                               last_map_addr = phys_pmd_update(pud, addr, end,
+                               pmd = map_low_page(pmd_offset(pud, 0));
+                               last_map_addr = phys_pmd_init(pmd, addr, end,
                                                         page_size_mask, prot);
+                               unmap_low_page(pmd);
+                               __flush_tlb_all();
                                continue;
                        }
                        /*
@@ -553,17 +553,6 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,
        return last_map_addr;
 }
 
-static unsigned long __meminit
-phys_pud_update(pgd_t *pgd, unsigned long addr, unsigned long end,
-                unsigned long page_size_mask)
-{
-       pud_t *pud;
-
-       pud = (pud_t *)pgd_page_vaddr(*pgd);
-
-       return phys_pud_init(pud, addr, end, page_size_mask);
-}
-
 unsigned long __meminit
 kernel_physical_mapping_init(unsigned long start,
                             unsigned long end,
@@ -587,8 +576,10 @@ kernel_physical_mapping_init(unsigned long start,
                        next = end;
 
                if (pgd_val(*pgd)) {
-                       last_map_addr = phys_pud_update(pgd, __pa(start),
+                       pud = map_low_page((pud_t *)pgd_page_vaddr(*pgd));
+                       last_map_addr = phys_pud_init(pud, __pa(start),
                                                 __pa(end), page_size_mask);
+                       unmap_low_page(pud);
                        continue;
                }
 
@@ -612,10 +603,9 @@ kernel_physical_mapping_init(unsigned long start,
 }
 
 #ifndef CONFIG_NUMA
-void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn,
-                               int acpi, int k8)
+void __init initmem_init(void)
 {
-       memblock_x86_register_active_regions(0, start_pfn, end_pfn);
+       memblock_x86_register_active_regions(0, 0, max_pfn);
 }
 #endif
 
index ebf6d78..9559d36 100644 (file)
@@ -26,11 +26,49 @@ static __init int numa_setup(char *opt)
 early_param("numa", numa_setup);
 
 /*
- * Which logical CPUs are on which nodes
+ * apicid, cpu, node mappings
  */
+s16 __apicid_to_node[MAX_LOCAL_APIC] __cpuinitdata = {
+       [0 ... MAX_LOCAL_APIC-1] = NUMA_NO_NODE
+};
+
 cpumask_var_t node_to_cpumask_map[MAX_NUMNODES];
 EXPORT_SYMBOL(node_to_cpumask_map);
 
+/*
+ * Map cpu index to node index
+ */
+DEFINE_EARLY_PER_CPU(int, x86_cpu_to_node_map, NUMA_NO_NODE);
+EXPORT_EARLY_PER_CPU_SYMBOL(x86_cpu_to_node_map);
+
+void __cpuinit numa_set_node(int cpu, int node)
+{
+       int *cpu_to_node_map = early_per_cpu_ptr(x86_cpu_to_node_map);
+
+       /* early setting, no percpu area yet */
+       if (cpu_to_node_map) {
+               cpu_to_node_map[cpu] = node;
+               return;
+       }
+
+#ifdef CONFIG_DEBUG_PER_CPU_MAPS
+       if (cpu >= nr_cpu_ids || !cpu_possible(cpu)) {
+               printk(KERN_ERR "numa_set_node: invalid cpu# (%d)\n", cpu);
+               dump_stack();
+               return;
+       }
+#endif
+       per_cpu(x86_cpu_to_node_map, cpu) = node;
+
+       if (node != NUMA_NO_NODE)
+               set_cpu_numa_node(cpu, node);
+}
+
+void __cpuinit numa_clear_node(int cpu)
+{
+       numa_set_node(cpu, NUMA_NO_NODE);
+}
+
 /*
  * Allocate node_to_cpumask_map based on number of available nodes
  * Requires node_possible_map to be valid.
@@ -57,7 +95,174 @@ void __init setup_node_to_cpumask_map(void)
        pr_debug("Node to cpumask map for %d nodes\n", nr_node_ids);
 }
 
-#ifdef CONFIG_DEBUG_PER_CPU_MAPS
+/*
+ * There are unfortunately some poorly designed mainboards around that
+ * only connect memory to a single CPU. This breaks the 1:1 cpu->node
+ * mapping. To avoid this fill in the mapping for all possible CPUs,
+ * as the number of CPUs is not known yet. We round robin the existing
+ * nodes.
+ */
+void __init numa_init_array(void)
+{
+       int rr, i;
+
+       rr = first_node(node_online_map);
+       for (i = 0; i < nr_cpu_ids; i++) {
+               if (early_cpu_to_node(i) != NUMA_NO_NODE)
+                       continue;
+               numa_set_node(i, rr);
+               rr = next_node(rr, node_online_map);
+               if (rr == MAX_NUMNODES)
+                       rr = first_node(node_online_map);
+       }
+}
+
+static __init int find_near_online_node(int node)
+{
+       int n, val;
+       int min_val = INT_MAX;
+       int best_node = -1;
+
+       for_each_online_node(n) {
+               val = node_distance(node, n);
+
+               if (val < min_val) {
+                       min_val = val;
+                       best_node = n;
+               }
+       }
+
+       return best_node;
+}
+
+/*
+ * Setup early cpu_to_node.
+ *
+ * Populate cpu_to_node[] only if x86_cpu_to_apicid[],
+ * and apicid_to_node[] tables have valid entries for a CPU.
+ * This means we skip cpu_to_node[] initialisation for NUMA
+ * emulation and faking node case (when running a kernel compiled
+ * for NUMA on a non NUMA box), which is OK as cpu_to_node[]
+ * is already initialized in a round robin manner at numa_init_array,
+ * prior to this call, and this initialization is good enough
+ * for the fake NUMA cases.
+ *
+ * Called before the per_cpu areas are setup.
+ */
+void __init init_cpu_to_node(void)
+{
+       int cpu;
+       u16 *cpu_to_apicid = early_per_cpu_ptr(x86_cpu_to_apicid);
+
+       BUG_ON(cpu_to_apicid == NULL);
+
+       for_each_possible_cpu(cpu) {
+               int node = numa_cpu_node(cpu);
+
+               if (node == NUMA_NO_NODE)
+                       continue;
+               if (!node_online(node))
+                       node = find_near_online_node(node);
+               numa_set_node(cpu, node);
+       }
+}
+
+#ifndef CONFIG_DEBUG_PER_CPU_MAPS
+
+# ifndef CONFIG_NUMA_EMU
+void __cpuinit numa_add_cpu(int cpu)
+{
+       cpumask_set_cpu(cpu, node_to_cpumask_map[early_cpu_to_node(cpu)]);
+}
+
+void __cpuinit numa_remove_cpu(int cpu)
+{
+       cpumask_clear_cpu(cpu, node_to_cpumask_map[early_cpu_to_node(cpu)]);
+}
+# endif        /* !CONFIG_NUMA_EMU */
+
+#else  /* !CONFIG_DEBUG_PER_CPU_MAPS */
+
+int __cpu_to_node(int cpu)
+{
+       if (early_per_cpu_ptr(x86_cpu_to_node_map)) {
+               printk(KERN_WARNING
+                       "cpu_to_node(%d): usage too early!\n", cpu);
+               dump_stack();
+               return early_per_cpu_ptr(x86_cpu_to_node_map)[cpu];
+       }
+       return per_cpu(x86_cpu_to_node_map, cpu);
+}
+EXPORT_SYMBOL(__cpu_to_node);
+
+/*
+ * Same function as cpu_to_node() but used if called before the
+ * per_cpu areas are setup.
+ */
+int early_cpu_to_node(int cpu)
+{
+       if (early_per_cpu_ptr(x86_cpu_to_node_map))
+               return early_per_cpu_ptr(x86_cpu_to_node_map)[cpu];
+
+       if (!cpu_possible(cpu)) {
+               printk(KERN_WARNING
+                       "early_cpu_to_node(%d): no per_cpu area!\n", cpu);
+               dump_stack();
+               return NUMA_NO_NODE;
+       }
+       return per_cpu(x86_cpu_to_node_map, cpu);
+}
+
+struct cpumask __cpuinit *debug_cpumask_set_cpu(int cpu, int enable)
+{
+       int node = early_cpu_to_node(cpu);
+       struct cpumask *mask;
+       char buf[64];
+
+       if (node == NUMA_NO_NODE) {
+               /* early_cpu_to_node() already emits a warning and trace */
+               return NULL;
+       }
+       mask = node_to_cpumask_map[node];
+       if (!mask) {
+               pr_err("node_to_cpumask_map[%i] NULL\n", node);
+               dump_stack();
+               return NULL;
+       }
+
+       cpulist_scnprintf(buf, sizeof(buf), mask);
+       printk(KERN_DEBUG "%s cpu %d node %d: mask now %s\n",
+               enable ? "numa_add_cpu" : "numa_remove_cpu",
+               cpu, node, buf);
+       return mask;
+}
+
+# ifndef CONFIG_NUMA_EMU
+static void __cpuinit numa_set_cpumask(int cpu, int enable)
+{
+       struct cpumask *mask;
+
+       mask = debug_cpumask_set_cpu(cpu, enable);
+       if (!mask)
+               return;
+
+       if (enable)
+               cpumask_set_cpu(cpu, mask);
+       else
+               cpumask_clear_cpu(cpu, mask);
+}
+
+void __cpuinit numa_add_cpu(int cpu)
+{
+       numa_set_cpumask(cpu, 1);
+}
+
+void __cpuinit numa_remove_cpu(int cpu)
+{
+       numa_set_cpumask(cpu, 0);
+}
+# endif        /* !CONFIG_NUMA_EMU */
+
 /*
  * Returns a pointer to the bitmask of CPUs on Node 'node'.
  */
@@ -80,4 +285,5 @@ const struct cpumask *cpumask_of_node(int node)
        return node_to_cpumask_map[node];
 }
 EXPORT_SYMBOL(cpumask_of_node);
-#endif
+
+#endif /* !CONFIG_DEBUG_PER_CPU_MAPS */
index 84a3e4c..bde3906 100644 (file)
@@ -110,6 +110,12 @@ 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
@@ -346,8 +352,7 @@ static void init_remap_allocator(int nid)
                (ulong) node_remap_end_vaddr[nid]);
 }
 
-void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn,
-                               int acpi, int k8)
+void __init initmem_init(void)
 {
        int nid;
        long kva_target_pfn;
@@ -361,6 +366,7 @@ void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn,
         */
 
        get_memcfg_numa();
+       numa_init_array();
 
        kva_pages = roundup(calculate_numa_remap_pages(), PTRS_PER_PTE);
 
index 95ea155..9ec0f20 100644 (file)
 #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/numa.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);
 
-struct memnode memnode;
+nodemask_t numa_nodes_parsed __initdata;
 
-s16 apicid_to_node[MAX_LOCAL_APIC] __cpuinitdata = {
-       [0 ... MAX_LOCAL_APIC-1] = NUMA_NO_NODE
-};
+struct memnode memnode;
 
 static unsigned long __initdata nodemap_addr;
 static unsigned long __initdata nodemap_size;
 
-/*
- * Map cpu index to node index
- */
-DEFINE_EARLY_PER_CPU(int, x86_cpu_to_node_map, NUMA_NO_NODE);
-EXPORT_EARLY_PER_CPU_SYMBOL(x86_cpu_to_node_map);
+static struct numa_meminfo numa_meminfo __initdata;
+
+static int numa_distance_cnt;
+static u8 *numa_distance;
 
 /*
  * Given a shift value, try to populate memnodemap[]
@@ -46,16 +45,15 @@ EXPORT_EARLY_PER_CPU_SYMBOL(x86_cpu_to_node_map);
  * 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 bootnode *nodes,
-                                     int numnodes, int shift, int *nodeids)
+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 < numnodes; i++) {
-               addr = nodes[i].start;
-               end = nodes[i].end;
+       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)
@@ -63,12 +61,7 @@ static int __init populate_memnodemap(const struct bootnode *nodes,
                do {
                        if (memnodemap[addr >> shift] != NUMA_NO_NODE)
                                return -1;
-
-                       if (!nodeids)
-                               memnodemap[addr >> shift] = i;
-                       else
-                               memnodemap[addr >> shift] = nodeids[i];
-
+                       memnodemap[addr >> shift] = mi->blk[i].nid;
                        addr += (1UL << shift);
                } while (addr < end);
                res = 1;
@@ -86,7 +79,7 @@ static int __init allocate_cachealigned_memnodemap(void)
 
        addr = 0x8000;
        nodemap_size = roundup(sizeof(s16) * memnodemapsize, L1_CACHE_BYTES);
-       nodemap_addr = memblock_find_in_range(addr, max_pfn<<PAGE_SHIFT,
+       nodemap_addr = memblock_find_in_range(addr, get_max_mapped(),
                                      nodemap_size, L1_CACHE_BYTES);
        if (nodemap_addr == MEMBLOCK_ERROR) {
                printk(KERN_ERR
@@ -106,16 +99,15 @@ static int __init allocate_cachealigned_memnodemap(void)
  * 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 bootnode *nodes,
-                                        int numnodes)
+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 < numnodes; i++) {
-               start = nodes[i].start;
-               end = nodes[i].end;
+       for (i = 0; i < mi->nr_blks; i++) {
+               start = mi->blk[i].start;
+               end = mi->blk[i].end;
                if (start >= end)
                        continue;
                bitfield |= start;
@@ -131,18 +123,17 @@ static int __init extract_lsb_from_nodes(const struct bootnode *nodes,
        return i;
 }
 
-int __init compute_hash_shift(struct bootnode *nodes, int numnodes,
-                             int *nodeids)
+static int __init compute_hash_shift(const struct numa_meminfo *mi)
 {
        int shift;
 
-       shift = extract_lsb_from_nodes(nodes, numnodes);
+       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(nodes, numnodes, shift, nodeids) != 1) {
+       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);
@@ -188,6 +179,63 @@ static void * __init early_node_mem(int nodeid, unsigned long start,
        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)
@@ -234,696 +282,386 @@ setup_node_bootmem(int nodeid, unsigned long start, unsigned long end)
        node_set_online(nodeid);
 }
 
-/*
- * There are unfortunately some poorly designed mainboards around that
- * only connect memory to a single CPU. This breaks the 1:1 cpu->node
- * mapping. To avoid this fill in the mapping for all possible CPUs,
- * as the number of CPUs is not known yet. We round robin the existing
- * nodes.
+/**
+ * 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.
  */
-void __init numa_init_array(void)
+int __init numa_cleanup_meminfo(struct numa_meminfo *mi)
 {
-       int rr, i;
+       const u64 low = 0;
+       const u64 high = (u64)max_pfn << PAGE_SHIFT;
+       int i, j, k;
 
-       rr = first_node(node_online_map);
-       for (i = 0; i < nr_cpu_ids; i++) {
-               if (early_cpu_to_node(i) != NUMA_NO_NODE)
-                       continue;
-               numa_set_node(i, rr);
-               rr = next_node(rr, node_online_map);
-               if (rr == MAX_NUMNODES)
-                       rr = first_node(node_online_map);
-       }
-}
-
-#ifdef CONFIG_NUMA_EMU
-/* Numa emulation */
-static struct bootnode nodes[MAX_NUMNODES] __initdata;
-static struct bootnode physnodes[MAX_NUMNODES] __cpuinitdata;
-static char *cmdline __initdata;
+       for (i = 0; i < mi->nr_blks; i++) {
+               struct numa_memblk *bi = &mi->blk[i];
 
-void __init numa_emu_cmdline(char *str)
-{
-       cmdline = str;
-}
+               /* make sure all blocks are inside the limits */
+               bi->start = max(bi->start, low);
+               bi->end = min(bi->end, high);
 
-static int __init setup_physnodes(unsigned long start, unsigned long end,
-                                       int acpi, int amd)
-{
-       int ret = 0;
-       int i;
-
-       memset(physnodes, 0, sizeof(physnodes));
-#ifdef CONFIG_ACPI_NUMA
-       if (acpi)
-               acpi_get_nodes(physnodes, start, end);
-#endif
-#ifdef CONFIG_AMD_NUMA
-       if (amd)
-               amd_get_nodes(physnodes);
-#endif
-       /*
-        * Basic sanity checking on the physical node map: there may be errors
-        * if the SRAT or AMD code incorrectly reported the topology or the mem=
-        * kernel parameter is used.
-        */
-       for (i = 0; i < MAX_NUMNODES; i++) {
-               if (physnodes[i].start == physnodes[i].end)
-                       continue;
-               if (physnodes[i].start > end) {
-                       physnodes[i].end = physnodes[i].start;
-                       continue;
-               }
-               if (physnodes[i].end < start) {
-                       physnodes[i].start = physnodes[i].end;
+               /* and there's no empty block */
+               if (bi->start == bi->end) {
+                       numa_remove_memblk_from(i--, mi);
                        continue;
                }
-               if (physnodes[i].start < start)
-                       physnodes[i].start = start;
-               if (physnodes[i].end > end)
-                       physnodes[i].end = end;
-               ret++;
-       }
-
-       /*
-        * If no physical topology was detected, a single node is faked to cover
-        * the entire address space.
-        */
-       if (!ret) {
-               physnodes[ret].start = start;
-               physnodes[ret].end = end;
-               ret = 1;
-       }
-       return ret;
-}
-
-static void __init fake_physnodes(int acpi, int amd, int nr_nodes)
-{
-       int i;
-
-       BUG_ON(acpi && amd);
-#ifdef CONFIG_ACPI_NUMA
-       if (acpi)
-               acpi_fake_nodes(nodes, nr_nodes);
-#endif
-#ifdef CONFIG_AMD_NUMA
-       if (amd)
-               amd_fake_nodes(nodes, nr_nodes);
-#endif
-       if (!acpi && !amd)
-               for (i = 0; i < nr_cpu_ids; i++)
-                       numa_set_node(i, 0);
-}
-
-/*
- * Setups up nid to range from addr to addr + size.  If the end
- * boundary is greater than max_addr, then max_addr is used instead.
- * The return value is 0 if there is additional memory left for
- * allocation past addr and -1 otherwise.  addr is adjusted to be at
- * the end of the node.
- */
-static int __init setup_node_range(int nid, u64 *addr, u64 size, u64 max_addr)
-{
-       int ret = 0;
-       nodes[nid].start = *addr;
-       *addr += size;
-       if (*addr >= max_addr) {
-               *addr = max_addr;
-               ret = -1;
-       }
-       nodes[nid].end = *addr;
-       node_set(nid, node_possible_map);
-       printk(KERN_INFO "Faking node %d at %016Lx-%016Lx (%LuMB)\n", nid,
-              nodes[nid].start, nodes[nid].end,
-              (nodes[nid].end - nodes[nid].start) >> 20);
-       return ret;
-}
-
-/*
- * Sets up nr_nodes fake nodes interleaved over physical nodes ranging from addr
- * to max_addr.  The return value is the number of nodes allocated.
- */
-static int __init split_nodes_interleave(u64 addr, u64 max_addr, int nr_nodes)
-{
-       nodemask_t physnode_mask = NODE_MASK_NONE;
-       u64 size;
-       int big;
-       int ret = 0;
-       int i;
-
-       if (nr_nodes <= 0)
-               return -1;
-       if (nr_nodes > MAX_NUMNODES) {
-               pr_info("numa=fake=%d too large, reducing to %d\n",
-                       nr_nodes, MAX_NUMNODES);
-               nr_nodes = MAX_NUMNODES;
-       }
-
-       size = (max_addr - addr - memblock_x86_hole_size(addr, max_addr)) / nr_nodes;
-       /*
-        * Calculate the number of big nodes that can be allocated as a result
-        * of consolidating the remainder.
-        */
-       big = ((size & ~FAKE_NODE_MIN_HASH_MASK) * nr_nodes) /
-               FAKE_NODE_MIN_SIZE;
-
-       size &= FAKE_NODE_MIN_HASH_MASK;
-       if (!size) {
-               pr_err("Not enough memory for each node.  "
-                       "NUMA emulation disabled.\n");
-               return -1;
-       }
 
-       for (i = 0; i < MAX_NUMNODES; i++)
-               if (physnodes[i].start != physnodes[i].end)
-                       node_set(i, physnode_mask);
-
-       /*
-        * Continue to fill physical nodes with fake nodes until there is no
-        * memory left on any of them.
-        */
-       while (nodes_weight(physnode_mask)) {
-               for_each_node_mask(i, physnode_mask) {
-                       u64 end = physnodes[i].start + size;
-                       u64 dma32_end = PFN_PHYS(MAX_DMA32_PFN);
-
-                       if (ret < big)
-                               end += FAKE_NODE_MIN_SIZE;
+               for (j = i + 1; j < mi->nr_blks; j++) {
+                       struct numa_memblk *bj = &mi->blk[j];
+                       unsigned long start, end;
 
                        /*
-                        * Continue to add memory to this fake node if its
-                        * non-reserved memory is less than the per-node size.
+                        * See whether there are overlapping blocks.  Whine
+                        * about but allow overlaps of the same nid.  They
+                        * will be merged below.
                         */
-                       while (end - physnodes[i].start -
-                               memblock_x86_hole_size(physnodes[i].start, end) < size) {
-                               end += FAKE_NODE_MIN_SIZE;
-                               if (end > physnodes[i].end) {
-                                       end = physnodes[i].end;
-                                       break;
+                       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);
                        }
 
                        /*
-                        * If there won't be at least FAKE_NODE_MIN_SIZE of
-                        * non-reserved memory in ZONE_DMA32 for the next node,
-                        * this one must extend to the boundary.
+                        * Join together blocks on the same node, holes
+                        * between which don't overlap with memory on other
+                        * nodes.
                         */
-                       if (end < dma32_end && dma32_end - end -
-                           memblock_x86_hole_size(end, dma32_end) < FAKE_NODE_MIN_SIZE)
-                               end = dma32_end;
-
-                       /*
-                        * If there won't be enough non-reserved memory for the
-                        * next node, this one must extend to the end of the
-                        * physical node.
-                        */
-                       if (physnodes[i].end - end -
-                           memblock_x86_hole_size(end, physnodes[i].end) < size)
-                               end = physnodes[i].end;
-
-                       /*
-                        * Avoid allocating more nodes than requested, which can
-                        * happen as a result of rounding down each node's size
-                        * to FAKE_NODE_MIN_SIZE.
-                        */
-                       if (nodes_weight(physnode_mask) + ret >= nr_nodes)
-                               end = physnodes[i].end;
-
-                       if (setup_node_range(ret++, &physnodes[i].start,
-                                               end - physnodes[i].start,
-                                               physnodes[i].end) < 0)
-                               node_clear(i, physnode_mask);
+                       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);
                }
        }
-       return ret;
-}
 
-/*
- * Returns the end address of a node so that there is at least `size' amount of
- * non-reserved memory or `max_addr' is reached.
- */
-static u64 __init find_end_of_node(u64 start, u64 max_addr, u64 size)
-{
-       u64 end = start + size;
-
-       while (end - start - memblock_x86_hole_size(start, end) < size) {
-               end += FAKE_NODE_MIN_SIZE;
-               if (end > max_addr) {
-                       end = max_addr;
-                       break;
-               }
+       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 end;
+
+       return 0;
 }
 
 /*
- * Sets up fake nodes of `size' interleaved over physical nodes ranging from
- * `addr' to `max_addr'.  The return value is the number of nodes allocated.
+ * Set nodes, which have memory in @mi, in *@nodemask.
  */
-static int __init split_nodes_size_interleave(u64 addr, u64 max_addr, u64 size)
+static void __init numa_nodemask_from_meminfo(nodemask_t *nodemask,
+                                             const struct numa_meminfo *mi)
 {
-       nodemask_t physnode_mask = NODE_MASK_NONE;
-       u64 min_size;
-       int ret = 0;
        int i;
 
-       if (!size)
-               return -1;
-       /*
-        * The limit on emulated nodes is MAX_NUMNODES, so the size per node is
-        * increased accordingly if the requested size is too small.  This
-        * creates a uniform distribution of node sizes across the entire
-        * machine (but not necessarily over physical nodes).
-        */
-       min_size = (max_addr - addr - memblock_x86_hole_size(addr, max_addr)) /
-                                               MAX_NUMNODES;
-       min_size = max(min_size, FAKE_NODE_MIN_SIZE);
-       if ((min_size & FAKE_NODE_MIN_HASH_MASK) < min_size)
-               min_size = (min_size + FAKE_NODE_MIN_SIZE) &
-                                               FAKE_NODE_MIN_HASH_MASK;
-       if (size < min_size) {
-               pr_err("Fake node size %LuMB too small, increasing to %LuMB\n",
-                       size >> 20, min_size >> 20);
-               size = min_size;
-       }
-       size &= FAKE_NODE_MIN_HASH_MASK;
-
-       for (i = 0; i < MAX_NUMNODES; i++)
-               if (physnodes[i].start != physnodes[i].end)
-                       node_set(i, physnode_mask);
-       /*
-        * Fill physical nodes with fake nodes of size until there is no memory
-        * left on any of them.
-        */
-       while (nodes_weight(physnode_mask)) {
-               for_each_node_mask(i, physnode_mask) {
-                       u64 dma32_end = MAX_DMA32_PFN << PAGE_SHIFT;
-                       u64 end;
-
-                       end = find_end_of_node(physnodes[i].start,
-                                               physnodes[i].end, size);
-                       /*
-                        * If there won't be at least FAKE_NODE_MIN_SIZE of
-                        * non-reserved memory in ZONE_DMA32 for the next node,
-                        * this one must extend to the boundary.
-                        */
-                       if (end < dma32_end && dma32_end - end -
-                           memblock_x86_hole_size(end, dma32_end) < FAKE_NODE_MIN_SIZE)
-                               end = dma32_end;
+       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);
+}
 
-                       /*
-                        * If there won't be enough non-reserved memory for the
-                        * next node, this one must extend to the end of the
-                        * physical node.
-                        */
-                       if (physnodes[i].end - end -
-                           memblock_x86_hole_size(end, physnodes[i].end) < size)
-                               end = physnodes[i].end;
+/**
+ * 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]);
 
-                       /*
-                        * Setup the fake node that will be allocated as bootmem
-                        * later.  If setup_node_range() returns non-zero, there
-                        * is no more memory available on this physical node.
-                        */
-                       if (setup_node_range(ret++, &physnodes[i].start,
-                                               end - physnodes[i].start,
-                                               physnodes[i].end) < 0)
-                               node_clear(i, physnode_mask);
-               }
-       }
-       return ret;
+       /* 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 */
 }
 
-/*
- * Sets up the system RAM area from start_pfn to last_pfn according to the
- * numa=fake command-line option.
- */
-static int __init numa_emulation(unsigned long start_pfn,
-                       unsigned long last_pfn, int acpi, int amd)
+static int __init numa_alloc_distance(void)
 {
-       u64 addr = start_pfn << PAGE_SHIFT;
-       u64 max_addr = last_pfn << PAGE_SHIFT;
-       int num_nodes;
-       int i;
+       nodemask_t nodes_parsed;
+       size_t size;
+       int i, j, cnt = 0;
+       u64 phys;
 
-       /*
-        * If the numa=fake command-line contains a 'M' or 'G', it represents
-        * the fixed node size.  Otherwise, if it is just a single number N,
-        * split the system RAM into N fake nodes.
-        */
-       if (strchr(cmdline, 'M') || strchr(cmdline, 'G')) {
-               u64 size;
+       /* size the new table and allocate it */
+       nodes_parsed = numa_nodes_parsed;
+       numa_nodemask_from_meminfo(&nodes_parsed, &numa_meminfo);
 
-               size = memparse(cmdline, &cmdline);
-               num_nodes = split_nodes_size_interleave(addr, max_addr, size);
-       } else {
-               unsigned long n;
+       for_each_node_mask(i, nodes_parsed)
+               cnt = i;
+       cnt++;
+       size = cnt * cnt * sizeof(numa_distance[0]);
 
-               n = simple_strtoul(cmdline, NULL, 0);
-               num_nodes = split_nodes_interleave(addr, max_addr, n);
+       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");
 
-       if (num_nodes < 0)
-               return num_nodes;
-       memnode_shift = compute_hash_shift(nodes, num_nodes, NULL);
-       if (memnode_shift < 0) {
-               memnode_shift = 0;
-               printk(KERN_ERR "No NUMA hash function found.  NUMA emulation "
-                      "disabled.\n");
-               return -1;
-       }
+       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);
 
-       /*
-        * We need to vacate all active ranges that may have been registered for
-        * the e820 memory map.
-        */
-       remove_all_active_ranges();
-       for_each_node_mask(i, node_possible_map) {
-               memblock_x86_register_active_regions(i, nodes[i].start >> PAGE_SHIFT,
-                                               nodes[i].end >> PAGE_SHIFT);
-               setup_node_bootmem(i, nodes[i].start, nodes[i].end);
-       }
-       setup_physnodes(addr, max_addr, acpi, amd);
-       fake_physnodes(acpi, amd, num_nodes);
-       numa_init_array();
        return 0;
 }
-#endif /* CONFIG_NUMA_EMU */
 
-void __init initmem_init(unsigned long start_pfn, unsigned long last_pfn,
-                               int acpi, int amd)
+/**
+ * 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 accomodate 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)
 {
-       int i;
-
-       nodes_clear(node_possible_map);
-       nodes_clear(node_online_map);
-
-#ifdef CONFIG_NUMA_EMU
-       setup_physnodes(start_pfn << PAGE_SHIFT, last_pfn << PAGE_SHIFT,
-                       acpi, amd);
-       if (cmdline && !numa_emulation(start_pfn, last_pfn, acpi, amd))
+       if (!numa_distance && numa_alloc_distance() < 0)
                return;
-       setup_physnodes(start_pfn << PAGE_SHIFT, last_pfn << PAGE_SHIFT,
-                       acpi, amd);
-       nodes_clear(node_possible_map);
-       nodes_clear(node_online_map);
-#endif
 
-#ifdef CONFIG_ACPI_NUMA
-       if (!numa_off && acpi && !acpi_scan_nodes(start_pfn << PAGE_SHIFT,
-                                                 last_pfn << PAGE_SHIFT))
+       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;
-       nodes_clear(node_possible_map);
-       nodes_clear(node_online_map);
-#endif
+       }
 
-#ifdef CONFIG_AMD_NUMA
-       if (!numa_off && amd && !amd_scan_nodes())
+       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;
-       nodes_clear(node_possible_map);
-       nodes_clear(node_online_map);
-#endif
-       printk(KERN_INFO "%s\n",
-              numa_off ? "NUMA turned off" : "No NUMA configuration found");
+       }
 
-       printk(KERN_INFO "Faking a node at %016lx-%016lx\n",
-              start_pfn << PAGE_SHIFT,
-              last_pfn << PAGE_SHIFT);
-       /* setup dummy node covering all memory */
-       memnode_shift = 63;
-       memnodemap = memnode.embedded_map;
-       memnodemap[0] = 0;
-       node_set_online(0);
-       node_set(0, node_possible_map);
-       for (i = 0; i < nr_cpu_ids; i++)
-               numa_set_node(i, 0);
-       memblock_x86_register_active_regions(0, start_pfn, last_pfn);
-       setup_node_bootmem(0, start_pfn << PAGE_SHIFT, last_pfn << PAGE_SHIFT);
+       numa_distance[from * numa_distance_cnt + to] = distance;
 }
 
-unsigned long __init numa_free_all_bootmem(void)
+int __node_distance(int from, int to)
 {
-       unsigned long pages = 0;
-       int i;
+       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);
 
-       for_each_online_node(i)
-               pages += free_all_bootmem_node(NODE_DATA(i));
+/*
+ * 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;
 
-       pages += free_all_memory_core_early(MAX_NUMNODES);
+       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;
+       }
 
-       return pages;
+       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;
 }
 
-#ifdef CONFIG_NUMA
-
-static __init int find_near_online_node(int node)
+static int __init numa_register_memblks(struct numa_meminfo *mi)
 {
-       int n, val;
-       int min_val = INT_MAX;
-       int best_node = -1;
+       int i, nid;
 
-       for_each_online_node(n) {
-               val = node_distance(node, n);
+       /* 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;
+       }
 
-               if (val < min_val) {
-                       min_val = val;
-                       best_node = n;
+       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 best_node;
+       return 0;
 }
 
-/*
- * Setup early cpu_to_node.
+/**
+ * dummy_numma_init - Fallback dummy NUMA init
  *
- * Populate cpu_to_node[] only if x86_cpu_to_apicid[],
- * and apicid_to_node[] tables have valid entries for a CPU.
- * This means we skip cpu_to_node[] initialisation for NUMA
- * emulation and faking node case (when running a kernel compiled
- * for NUMA on a non NUMA box), which is OK as cpu_to_node[]
- * is already initialized in a round robin manner at numa_init_array,
- * prior to this call, and this initialization is good enough
- * for the fake NUMA cases.
+ * Used if there's no underlying NUMA architecture, NUMA initialization
+ * fails, or NUMA is disabled on the command line.
  *
- * Called before the per_cpu areas are setup.
+ * Must online at least one node and add memory blocks that cover all
+ * allowed memory.  This function must not fail.
  */
-void __init init_cpu_to_node(void)
+static int __init dummy_numa_init(void)
 {
-       int cpu;
-       u16 *cpu_to_apicid = early_per_cpu_ptr(x86_cpu_to_apicid);
-
-       BUG_ON(cpu_to_apicid == NULL);
+       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);
 
-       for_each_possible_cpu(cpu) {
-               int node;
-               u16 apicid = cpu_to_apicid[cpu];
+       node_set(0, numa_nodes_parsed);
+       numa_add_memblk(0, 0, (u64)max_pfn << PAGE_SHIFT);
 
-               if (apicid == BAD_APICID)
-                       continue;
-               node = apicid_to_node[apicid];
-               if (node == NUMA_NO_NODE)
-                       continue;
-               if (!node_online(node))
-                       node = find_near_online_node(node);
-               numa_set_node(cpu, node);
-       }
+       return 0;
 }
-#endif
 
-
-void __cpuinit numa_set_node(int cpu, int node)
+static int __init numa_init(int (*init_func)(void))
 {
-       int *cpu_to_node_map = early_per_cpu_ptr(x86_cpu_to_node_map);
-
-       /* early setting, no percpu area yet */
-       if (cpu_to_node_map) {
-               cpu_to_node_map[cpu] = node;
-               return;
-       }
-
-#ifdef CONFIG_DEBUG_PER_CPU_MAPS
-       if (cpu >= nr_cpu_ids || !cpu_possible(cpu)) {
-               printk(KERN_ERR "numa_set_node: invalid cpu# (%d)\n", cpu);
-               dump_stack();
-               return;
-       }
-#endif
-       per_cpu(x86_cpu_to_node_map, cpu) = node;
+       int i;
+       int ret;
 
-       if (node != NUMA_NO_NODE)
-               set_cpu_numa_node(cpu, node);
-}
+       for (i = 0; i < MAX_LOCAL_APIC; i++)
+               set_apicid_to_node(i, NUMA_NO_NODE);
 
-void __cpuinit numa_clear_node(int cpu)
-{
-       numa_set_node(cpu, 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();
 
-#ifndef CONFIG_DEBUG_PER_CPU_MAPS
+       ret = init_func();
+       if (ret < 0)
+               return ret;
+       ret = numa_cleanup_meminfo(&numa_meminfo);
+       if (ret < 0)
+               return ret;
 
-#ifndef CONFIG_NUMA_EMU
-void __cpuinit numa_add_cpu(int cpu)
-{
-       cpumask_set_cpu(cpu, node_to_cpumask_map[early_cpu_to_node(cpu)]);
-}
+       numa_emulation(&numa_meminfo, numa_distance_cnt);
 
-void __cpuinit numa_remove_cpu(int cpu)
-{
-       cpumask_clear_cpu(cpu, node_to_cpumask_map[early_cpu_to_node(cpu)]);
-}
-#else
-void __cpuinit numa_add_cpu(int cpu)
-{
-       unsigned long addr;
-       u16 apicid;
-       int physnid;
-       int nid = NUMA_NO_NODE;
+       ret = numa_register_memblks(&numa_meminfo);
+       if (ret < 0)
+               return ret;
 
-       apicid = early_per_cpu(x86_cpu_to_apicid, cpu);
-       if (apicid != BAD_APICID)
-               nid = apicid_to_node[apicid];
-       if (nid == NUMA_NO_NODE)
-               nid = early_cpu_to_node(cpu);
-       BUG_ON(nid == NUMA_NO_NODE || !node_online(nid));
-
-       /*
-        * Use the starting address of the emulated node to find which physical
-        * node it is allocated on.
-        */
-       addr = node_start_pfn(nid) << PAGE_SHIFT;
-       for (physnid = 0; physnid < MAX_NUMNODES; physnid++)
-               if (addr >= physnodes[physnid].start &&
-                   addr < physnodes[physnid].end)
-                       break;
+       for (i = 0; i < nr_cpu_ids; i++) {
+               int nid = early_cpu_to_node(i);
 
-       /*
-        * Map the cpu to each emulated node that is allocated on the physical
-        * node of the cpu's apic id.
-        */
-       for_each_online_node(nid) {
-               addr = node_start_pfn(nid) << PAGE_SHIFT;
-               if (addr >= physnodes[physnid].start &&
-                   addr < physnodes[physnid].end)
-                       cpumask_set_cpu(cpu, node_to_cpumask_map[nid]);
+               if (nid == NUMA_NO_NODE)
+                       continue;
+               if (!node_online(nid))
+                       numa_clear_node(i);
        }
+       numa_init_array();
+       return 0;
 }
 
-void __cpuinit numa_remove_cpu(int cpu)
+void __init initmem_init(void)
 {
-       int i;
+       int ret;
 
-       for_each_online_node(i)
-               cpumask_clear_cpu(cpu, node_to_cpumask_map[i]);
-}
-#endif /* !CONFIG_NUMA_EMU */
-
-#else /* CONFIG_DEBUG_PER_CPU_MAPS */
-static struct cpumask __cpuinit *debug_cpumask_set_cpu(int cpu, int enable)
-{
-       int node = early_cpu_to_node(cpu);
-       struct cpumask *mask;
-       char buf[64];
-
-       mask = node_to_cpumask_map[node];
-       if (!mask) {
-               pr_err("node_to_cpumask_map[%i] NULL\n", node);
-               dump_stack();
-               return NULL;
+       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
        }
 
-       cpulist_scnprintf(buf, sizeof(buf), mask);
-       printk(KERN_DEBUG "%s cpu %d node %d: mask now %s\n",
-               enable ? "numa_add_cpu" : "numa_remove_cpu",
-               cpu, node, buf);
-       return mask;
+       numa_init(dummy_numa_init);
 }
 
-/*
- * --------- debug versions of the numa functions ---------
- */
-#ifndef CONFIG_NUMA_EMU
-static void __cpuinit numa_set_cpumask(int cpu, int enable)
-{
-       struct cpumask *mask;
-
-       mask = debug_cpumask_set_cpu(cpu, enable);
-       if (!mask)
-               return;
-
-       if (enable)
-               cpumask_set_cpu(cpu, mask);
-       else
-               cpumask_clear_cpu(cpu, mask);
-}
-#else
-static void __cpuinit numa_set_cpumask(int cpu, int enable)
+unsigned long __init numa_free_all_bootmem(void)
 {
-       int node = early_cpu_to_node(cpu);
-       struct cpumask *mask;
+       unsigned long pages = 0;
        int i;
 
-       for_each_online_node(i) {
-               unsigned long addr;
-
-               addr = node_start_pfn(i) << PAGE_SHIFT;
-               if (addr < physnodes[node].start ||
-                                       addr >= physnodes[node].end)
-                       continue;
-               mask = debug_cpumask_set_cpu(cpu, enable);
-               if (!mask)
-                       return;
-
-               if (enable)
-                       cpumask_set_cpu(cpu, mask);
-               else
-                       cpumask_clear_cpu(cpu, mask);
-       }
-}
-#endif /* CONFIG_NUMA_EMU */
+       for_each_online_node(i)
+               pages += free_all_bootmem_node(NODE_DATA(i));
 
-void __cpuinit numa_add_cpu(int cpu)
-{
-       numa_set_cpumask(cpu, 1);
-}
+       pages += free_all_memory_core_early(MAX_NUMNODES);
 
-void __cpuinit numa_remove_cpu(int cpu)
-{
-       numa_set_cpumask(cpu, 0);
+       return pages;
 }
 
-int __cpu_to_node(int cpu)
+int __cpuinit numa_cpu_node(int cpu)
 {
-       if (early_per_cpu_ptr(x86_cpu_to_node_map)) {
-               printk(KERN_WARNING
-                       "cpu_to_node(%d): usage too early!\n", cpu);
-               dump_stack();
-               return early_per_cpu_ptr(x86_cpu_to_node_map)[cpu];
-       }
-       return per_cpu(x86_cpu_to_node_map, cpu);
-}
-EXPORT_SYMBOL(__cpu_to_node);
+       int apicid = early_per_cpu(x86_cpu_to_apicid, cpu);
 
-/*
- * Same function as cpu_to_node() but used if called before the
- * per_cpu areas are setup.
- */
-int early_cpu_to_node(int cpu)
-{
-       if (early_per_cpu_ptr(x86_cpu_to_node_map))
-               return early_per_cpu_ptr(x86_cpu_to_node_map)[cpu];
-
-       if (!cpu_possible(cpu)) {
-               printk(KERN_WARNING
-                       "early_cpu_to_node(%d): no per_cpu area!\n", cpu);
-               dump_stack();
-               return NUMA_NO_NODE;
-       }
-       return per_cpu(x86_cpu_to_node_map, cpu);
+       if (apicid != BAD_APICID)
+               return __apicid_to_node[apicid];
+       return NUMA_NO_NODE;
 }
-
-/*
- * --------- end of debug versions of the numa functions ---------
- */
-
-#endif /* CONFIG_DEBUG_PER_CPU_MAPS */
diff --git a/arch/x86/mm/numa_emulation.c b/arch/x86/mm/numa_emulation.c
new file mode 100644 (file)
index 0000000..ad091e4
--- /dev/null
@@ -0,0 +1,494 @@
+/*
+ * NUMA emulation
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/topology.h>
+#include <linux/memblock.h>
+#include <asm/dma.h>
+
+#include "numa_internal.h"
+
+static int emu_nid_to_phys[MAX_NUMNODES] __cpuinitdata;
+static char *emu_cmdline __initdata;
+
+void __init numa_emu_cmdline(char *str)
+{
+       emu_cmdline = str;
+}
+
+static int __init emu_find_memblk_by_nid(int nid, const struct numa_meminfo *mi)
+{
+       int i;
+
+       for (i = 0; i < mi->nr_blks; i++)
+               if (mi->blk[i].nid == nid)
+                       return i;
+       return -ENOENT;
+}
+
+/*
+ * Sets up nid to range from @start to @end.  The return value is -errno if
+ * something went wrong, 0 otherwise.
+ */
+static int __init emu_setup_memblk(struct numa_meminfo *ei,
+                                  struct numa_meminfo *pi,
+                                  int nid, int phys_blk, u64 size)
+{
+       struct numa_memblk *eb = &ei->blk[ei->nr_blks];
+       struct numa_memblk *pb = &pi->blk[phys_blk];
+
+       if (ei->nr_blks >= NR_NODE_MEMBLKS) {
+               pr_err("NUMA: Too many emulated memblks, failing emulation\n");
+               return -EINVAL;
+       }
+
+       ei->nr_blks++;
+       eb->start = pb->start;
+       eb->end = pb->start + size;
+       eb->nid = nid;
+
+       if (emu_nid_to_phys[nid] == NUMA_NO_NODE)
+               emu_nid_to_phys[nid] = pb->nid;
+
+       pb->start += size;
+       if (pb->start >= pb->end) {
+               WARN_ON_ONCE(pb->start > pb->end);
+               numa_remove_memblk_from(phys_blk, pi);
+       }
+
+       printk(KERN_INFO "Faking node %d at %016Lx-%016Lx (%LuMB)\n", nid,
+              eb->start, eb->end, (eb->end - eb->start) >> 20);
+       return 0;
+}
+
+/*
+ * Sets up nr_nodes fake nodes interleaved over physical nodes ranging from addr
+ * to max_addr.  The return value is the number of nodes allocated.
+ */
+static int __init split_nodes_interleave(struct numa_meminfo *ei,
+                                        struct numa_meminfo *pi,
+                                        u64 addr, u64 max_addr, int nr_nodes)
+{
+       nodemask_t physnode_mask = NODE_MASK_NONE;
+       u64 size;
+       int big;
+       int nid = 0;
+       int i, ret;
+
+       if (nr_nodes <= 0)
+               return -1;
+       if (nr_nodes > MAX_NUMNODES) {
+               pr_info("numa=fake=%d too large, reducing to %d\n",
+                       nr_nodes, MAX_NUMNODES);
+               nr_nodes = MAX_NUMNODES;
+       }
+
+       size = (max_addr - addr - memblock_x86_hole_size(addr, max_addr)) / nr_nodes;
+       /*
+        * Calculate the number of big nodes that can be allocated as a result
+        * of consolidating the remainder.
+        */
+       big = ((size & ~FAKE_NODE_MIN_HASH_MASK) * nr_nodes) /
+               FAKE_NODE_MIN_SIZE;
+
+       size &= FAKE_NODE_MIN_HASH_MASK;
+       if (!size) {
+               pr_err("Not enough memory for each node.  "
+                       "NUMA emulation disabled.\n");
+               return -1;
+       }
+
+       for (i = 0; i < pi->nr_blks; i++)
+               node_set(pi->blk[i].nid, physnode_mask);
+
+       /*
+        * Continue to fill physical nodes with fake nodes until there is no
+        * memory left on any of them.
+        */
+       while (nodes_weight(physnode_mask)) {
+               for_each_node_mask(i, physnode_mask) {
+                       u64 dma32_end = PFN_PHYS(MAX_DMA32_PFN);
+                       u64 start, limit, end;
+                       int phys_blk;
+
+                       phys_blk = emu_find_memblk_by_nid(i, pi);
+                       if (phys_blk < 0) {
+                               node_clear(i, physnode_mask);
+                               continue;
+                       }
+                       start = pi->blk[phys_blk].start;
+                       limit = pi->blk[phys_blk].end;
+                       end = start + size;
+
+                       if (nid < big)
+                               end += FAKE_NODE_MIN_SIZE;
+
+                       /*
+                        * Continue to add memory to this fake node if its
+                        * non-reserved memory is less than the per-node size.
+                        */
+                       while (end - start -
+                              memblock_x86_hole_size(start, end) < size) {
+                               end += FAKE_NODE_MIN_SIZE;
+                               if (end > limit) {
+                                       end = limit;
+                                       break;
+                               }
+                       }
+
+                       /*
+                        * If there won't be at least FAKE_NODE_MIN_SIZE of
+                        * non-reserved memory in ZONE_DMA32 for the next node,
+                        * this one must extend to the boundary.
+                        */
+                       if (end < dma32_end && dma32_end - end -
+                           memblock_x86_hole_size(end, dma32_end) < FAKE_NODE_MIN_SIZE)
+                               end = dma32_end;
+
+                       /*
+                        * If there won't be enough non-reserved memory for the
+                        * next node, this one must extend to the end of the
+                        * physical node.
+                        */
+                       if (limit - end -
+                           memblock_x86_hole_size(end, limit) < size)
+                               end = limit;
+
+                       ret = emu_setup_memblk(ei, pi, nid++ % nr_nodes,
+                                              phys_blk,
+                                              min(end, limit) - start);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Returns the end address of a node so that there is at least `size' amount of
+ * non-reserved memory or `max_addr' is reached.
+ */
+static u64 __init find_end_of_node(u64 start, u64 max_addr, u64 size)
+{
+       u64 end = start + size;
+
+       while (end - start - memblock_x86_hole_size(start, end) < size) {
+               end += FAKE_NODE_MIN_SIZE;
+               if (end > max_addr) {
+                       end = max_addr;
+                       break;
+               }
+       }
+       return end;
+}
+
+/*
+ * Sets up fake nodes of `size' interleaved over physical nodes ranging from
+ * `addr' to `max_addr'.  The return value is the number of nodes allocated.
+ */
+static int __init split_nodes_size_interleave(struct numa_meminfo *ei,
+                                             struct numa_meminfo *pi,
+                                             u64 addr, u64 max_addr, u64 size)
+{
+       nodemask_t physnode_mask = NODE_MASK_NONE;
+       u64 min_size;
+       int nid = 0;
+       int i, ret;
+
+       if (!size)
+               return -1;
+       /*
+        * The limit on emulated nodes is MAX_NUMNODES, so the size per node is
+        * increased accordingly if the requested size is too small.  This
+        * creates a uniform distribution of node sizes across the entire
+        * machine (but not necessarily over physical nodes).
+        */
+       min_size = (max_addr - addr - memblock_x86_hole_size(addr, max_addr)) /
+                                               MAX_NUMNODES;
+       min_size = max(min_size, FAKE_NODE_MIN_SIZE);
+       if ((min_size & FAKE_NODE_MIN_HASH_MASK) < min_size)
+               min_size = (min_size + FAKE_NODE_MIN_SIZE) &
+                                               FAKE_NODE_MIN_HASH_MASK;
+       if (size < min_size) {
+               pr_err("Fake node size %LuMB too small, increasing to %LuMB\n",
+                       size >> 20, min_size >> 20);
+               size = min_size;
+       }
+       size &= FAKE_NODE_MIN_HASH_MASK;
+
+       for (i = 0; i < pi->nr_blks; i++)
+               node_set(pi->blk[i].nid, physnode_mask);
+
+       /*
+        * Fill physical nodes with fake nodes of size until there is no memory
+        * left on any of them.
+        */
+       while (nodes_weight(physnode_mask)) {
+               for_each_node_mask(i, physnode_mask) {
+                       u64 dma32_end = MAX_DMA32_PFN << PAGE_SHIFT;
+                       u64 start, limit, end;
+                       int phys_blk;
+
+                       phys_blk = emu_find_memblk_by_nid(i, pi);
+                       if (phys_blk < 0) {
+                               node_clear(i, physnode_mask);
+                               continue;
+                       }
+                       start = pi->blk[phys_blk].start;
+                       limit = pi->blk[phys_blk].end;
+
+                       end = find_end_of_node(start, limit, size);
+                       /*
+                        * If there won't be at least FAKE_NODE_MIN_SIZE of
+                        * non-reserved memory in ZONE_DMA32 for the next node,
+                        * this one must extend to the boundary.
+                        */
+                       if (end < dma32_end && dma32_end - end -
+                           memblock_x86_hole_size(end, dma32_end) < FAKE_NODE_MIN_SIZE)
+                               end = dma32_end;
+
+                       /*
+                        * If there won't be enough non-reserved memory for the
+                        * next node, this one must extend to the end of the
+                        * physical node.
+                        */
+                       if (limit - end -
+                           memblock_x86_hole_size(end, limit) < size)
+                               end = limit;
+
+                       ret = emu_setup_memblk(ei, pi, nid++ % MAX_NUMNODES,
+                                              phys_blk,
+                                              min(end, limit) - start);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+       return 0;
+}
+
+/**
+ * numa_emulation - Emulate NUMA nodes
+ * @numa_meminfo: NUMA configuration to massage
+ * @numa_dist_cnt: The size of the physical NUMA distance table
+ *
+ * Emulate NUMA nodes according to the numa=fake kernel parameter.
+ * @numa_meminfo contains the physical memory configuration and is modified
+ * to reflect the emulated configuration on success.  @numa_dist_cnt is
+ * used to determine the size of the physical distance table.
+ *
+ * On success, the following modifications are made.
+ *
+ * - @numa_meminfo is updated to reflect the emulated nodes.
+ *
+ * - __apicid_to_node[] is updated such that APIC IDs are mapped to the
+ *   emulated nodes.
+ *
+ * - NUMA distance table is rebuilt to represent distances between emulated
+ *   nodes.  The distances are determined considering how emulated nodes
+ *   are mapped to physical nodes and match the actual distances.
+ *
+ * - emu_nid_to_phys[] reflects how emulated nodes are mapped to physical
+ *   nodes.  This is used by numa_add_cpu() and numa_remove_cpu().
+ *
+ * If emulation is not enabled or fails, emu_nid_to_phys[] is filled with
+ * identity mapping and no other modification is made.
+ */
+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;
+       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;
+       int i, j, ret;
+
+       if (!emu_cmdline)
+               goto no_emu;
+
+       memset(&ei, 0, sizeof(ei));
+       pi = *numa_meminfo;
+
+       for (i = 0; i < MAX_NUMNODES; i++)
+               emu_nid_to_phys[i] = NUMA_NO_NODE;
+
+       /*
+        * If the numa=fake command-line contains a 'M' or 'G', it represents
+        * the fixed node size.  Otherwise, if it is just a single number N,
+        * split the system RAM into N fake nodes.
+        */
+       if (strchr(emu_cmdline, 'M') || strchr(emu_cmdline, 'G')) {
+               u64 size;
+
+               size = memparse(emu_cmdline, &emu_cmdline);
+               ret = split_nodes_size_interleave(&ei, &pi, 0, max_addr, size);
+       } else {
+               unsigned long n;
+
+               n = simple_strtoul(emu_cmdline, NULL, 0);
+               ret = split_nodes_interleave(&ei, &pi, 0, max_addr, n);
+       }
+
+       if (ret < 0)
+               goto no_emu;
+
+       if (numa_cleanup_meminfo(&ei) < 0) {
+               pr_warning("NUMA: Warning: constructed meminfo invalid, disabling emulation\n");
+               goto no_emu;
+       }
+
+       /* copy the physical distance table */
+       if (numa_dist_cnt) {
+               u64 phys;
+
+               phys = memblock_find_in_range(0,
+                                             (u64)max_pfn_mapped << PAGE_SHIFT,
+                                             phys_size, PAGE_SIZE);
+               if (phys == MEMBLOCK_ERROR) {
+                       pr_warning("NUMA: Warning: can't allocate copy of distance table, disabling emulation\n");
+                       goto no_emu;
+               }
+               memblock_x86_reserve_range(phys, phys + phys_size, "TMP NUMA DIST");
+               phys_dist = __va(phys);
+
+               for (i = 0; i < numa_dist_cnt; i++)
+                       for (j = 0; j < numa_dist_cnt; j++)
+                               phys_dist[i * numa_dist_cnt + j] =
+                                       node_distance(i, j);
+       }
+
+       /*
+        * Determine the max emulated nid and the default phys nid to use
+        * for unmapped nodes.
+        */
+       max_emu_nid = 0;
+       dfl_phys_nid = NUMA_NO_NODE;
+       for (i = 0; i < ARRAY_SIZE(emu_nid_to_phys); i++) {
+               if (emu_nid_to_phys[i] != NUMA_NO_NODE) {
+                       max_emu_nid = i;
+                       if (dfl_phys_nid == NUMA_NO_NODE)
+                               dfl_phys_nid = emu_nid_to_phys[i];
+               }
+       }
+       if (dfl_phys_nid == NUMA_NO_NODE) {
+               pr_warning("NUMA: Warning: can't determine default physical node, disabling emulation\n");
+               goto no_emu;
+       }
+
+       /* commit */
+       *numa_meminfo = ei;
+
+       /*
+        * Transform __apicid_to_node table to use emulated nids by
+        * reverse-mapping phys_nid.  The maps should always exist but fall
+        * back to zero just in case.
+        */
+       for (i = 0; i < ARRAY_SIZE(__apicid_to_node); i++) {
+               if (__apicid_to_node[i] == NUMA_NO_NODE)
+                       continue;
+               for (j = 0; j < ARRAY_SIZE(emu_nid_to_phys); j++)
+                       if (__apicid_to_node[i] == emu_nid_to_phys[j])
+                               break;
+               __apicid_to_node[i] = j < ARRAY_SIZE(emu_nid_to_phys) ? j : 0;
+       }
+
+       /* make sure all emulated nodes are mapped to a physical node */
+       for (i = 0; i < ARRAY_SIZE(emu_nid_to_phys); i++)
+               if (emu_nid_to_phys[i] == NUMA_NO_NODE)
+                       emu_nid_to_phys[i] = dfl_phys_nid;
+
+       /* transform distance table */
+       numa_reset_distance();
+       for (i = 0; i < max_emu_nid + 1; i++) {
+               for (j = 0; j < max_emu_nid + 1; j++) {
+                       int physi = emu_nid_to_phys[i];
+                       int physj = emu_nid_to_phys[j];
+                       int dist;
+
+                       if (physi >= numa_dist_cnt || physj >= numa_dist_cnt)
+                               dist = physi == physj ?
+                                       LOCAL_DISTANCE : REMOTE_DISTANCE;
+                       else
+                               dist = phys_dist[physi * numa_dist_cnt + physj];
+
+                       numa_set_distance(i, j, dist);
+               }
+       }
+
+       /* free the copied physical distance table */
+       if (phys_dist)
+               memblock_x86_free_range(__pa(phys_dist), __pa(phys_dist) + phys_size);
+       return;
+
+no_emu:
+       /* No emulation.  Build identity emu_nid_to_phys[] for numa_add_cpu() */
+       for (i = 0; i < ARRAY_SIZE(emu_nid_to_phys); i++)
+               emu_nid_to_phys[i] = i;
+}
+
+#ifndef CONFIG_DEBUG_PER_CPU_MAPS
+void __cpuinit numa_add_cpu(int cpu)
+{
+       int physnid, nid;
+
+       nid = early_cpu_to_node(cpu);
+       BUG_ON(nid == NUMA_NO_NODE || !node_online(nid));
+
+       physnid = emu_nid_to_phys[nid];
+
+       /*
+        * Map the cpu to each emulated node that is allocated on the physical
+        * node of the cpu's apic id.
+        */
+       for_each_online_node(nid)
+               if (emu_nid_to_phys[nid] == physnid)
+                       cpumask_set_cpu(cpu, node_to_cpumask_map[nid]);
+}
+
+void __cpuinit numa_remove_cpu(int cpu)
+{
+       int i;
+
+       for_each_online_node(i)
+               cpumask_clear_cpu(cpu, node_to_cpumask_map[i]);
+}
+#else  /* !CONFIG_DEBUG_PER_CPU_MAPS */
+static void __cpuinit numa_set_cpumask(int cpu, int enable)
+{
+       struct cpumask *mask;
+       int nid, physnid, i;
+
+       nid = early_cpu_to_node(cpu);
+       if (nid == NUMA_NO_NODE) {
+               /* early_cpu_to_node() already emits a warning and trace */
+               return;
+       }
+
+       physnid = emu_nid_to_phys[nid];
+
+       for_each_online_node(i) {
+               if (emu_nid_to_phys[nid] != physnid)
+                       continue;
+
+               mask = debug_cpumask_set_cpu(cpu, enable);
+               if (!mask)
+                       return;
+
+               if (enable)
+                       cpumask_set_cpu(cpu, mask);
+               else
+                       cpumask_clear_cpu(cpu, mask);
+       }
+}
+
+void __cpuinit numa_add_cpu(int cpu)
+{
+       numa_set_cpumask(cpu, 1);
+}
+
+void __cpuinit numa_remove_cpu(int cpu)
+{
+       numa_set_cpumask(cpu, 0);
+}
+#endif /* !CONFIG_DEBUG_PER_CPU_MAPS */
diff --git a/arch/x86/mm/numa_internal.h b/arch/x86/mm/numa_internal.h
new file mode 100644 (file)
index 0000000..ef2d973
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef __X86_MM_NUMA_INTERNAL_H
+#define __X86_MM_NUMA_INTERNAL_H
+
+#include <linux/types.h>
+#include <asm/numa.h>
+
+struct numa_memblk {
+       u64                     start;
+       u64                     end;
+       int                     nid;
+};
+
+struct numa_meminfo {
+       int                     nr_blks;
+       struct numa_memblk      blk[NR_NODE_MEMBLKS];
+};
+
+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);
+
+#ifdef CONFIG_NUMA_EMU
+void __init numa_emulation(struct numa_meminfo *numa_meminfo,
+                          int numa_dist_cnt);
+#else
+static inline void numa_emulation(struct numa_meminfo *numa_meminfo,
+                                 int numa_dist_cnt)
+{ }
+#endif
+
+#endif /* __X86_MM_NUMA_INTERNAL_H */
index 8b830ca..90825f2 100644 (file)
@@ -57,12 +57,10 @@ static unsigned long direct_pages_count[PG_LEVEL_NUM];
 
 void update_page_count(int level, unsigned long pages)
 {
-       unsigned long flags;
-
        /* Protect against CPA */
-       spin_lock_irqsave(&pgd_lock, flags);
+       spin_lock(&pgd_lock);
        direct_pages_count[level] += pages;
-       spin_unlock_irqrestore(&pgd_lock, flags);
+       spin_unlock(&pgd_lock);
 }
 
 static void split_page_count(int level)
@@ -256,7 +254,6 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
                                   unsigned long pfn)
 {
        pgprot_t forbidden = __pgprot(0);
-       pgprot_t required = __pgprot(0);
 
        /*
         * The BIOS area between 640k and 1Mb needs to be executable for
@@ -282,12 +279,6 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
        if (within(pfn, __pa((unsigned long)__start_rodata) >> PAGE_SHIFT,
                   __pa((unsigned long)__end_rodata) >> PAGE_SHIFT))
                pgprot_val(forbidden) |= _PAGE_RW;
-       /*
-        * .data and .bss should always be writable.
-        */
-       if (within(address, (unsigned long)_sdata, (unsigned long)_edata) ||
-           within(address, (unsigned long)__bss_start, (unsigned long)__bss_stop))
-               pgprot_val(required) |= _PAGE_RW;
 
 #if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA)
        /*
@@ -327,7 +318,6 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
 #endif
 
        prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden));
-       prot = __pgprot(pgprot_val(prot) | pgprot_val(required));
 
        return prot;
 }
@@ -402,7 +392,7 @@ static int
 try_preserve_large_page(pte_t *kpte, unsigned long address,
                        struct cpa_data *cpa)
 {
-       unsigned long nextpage_addr, numpages, pmask, psize, flags, addr, pfn;
+       unsigned long nextpage_addr, numpages, pmask, psize, addr, pfn;
        pte_t new_pte, old_pte, *tmp;
        pgprot_t old_prot, new_prot, req_prot;
        int i, do_split = 1;
@@ -411,7 +401,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
        if (cpa->force_split)
                return 1;
 
-       spin_lock_irqsave(&pgd_lock, flags);
+       spin_lock(&pgd_lock);
        /*
         * Check for races, another CPU might have split this page
         * up already:
@@ -506,14 +496,14 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
        }
 
 out_unlock:
-       spin_unlock_irqrestore(&pgd_lock, flags);
+       spin_unlock(&pgd_lock);
 
        return do_split;
 }
 
 static int split_large_page(pte_t *kpte, unsigned long address)
 {
-       unsigned long flags, pfn, pfninc = 1;
+       unsigned long pfn, pfninc = 1;
        unsigned int i, level;
        pte_t *pbase, *tmp;
        pgprot_t ref_prot;
@@ -527,7 +517,7 @@ static int split_large_page(pte_t *kpte, unsigned long address)
        if (!base)
                return -ENOMEM;
 
-       spin_lock_irqsave(&pgd_lock, flags);
+       spin_lock(&pgd_lock);
        /*
         * Check for races, another CPU might have split this page
         * up for us already:
@@ -599,7 +589,7 @@ out_unlock:
         */
        if (base)
                __free_page(base);
-       spin_unlock_irqrestore(&pgd_lock, flags);
+       spin_unlock(&pgd_lock);
 
        return 0;
 }
index 500242d..0113d19 100644 (file)
@@ -121,14 +121,12 @@ static void pgd_ctor(struct mm_struct *mm, pgd_t *pgd)
 
 static void pgd_dtor(pgd_t *pgd)
 {
-       unsigned long flags; /* can be called from interrupt context */
-
        if (SHARED_KERNEL_PMD)
                return;
 
-       spin_lock_irqsave(&pgd_lock, flags);
+       spin_lock(&pgd_lock);
        pgd_list_del(pgd);
-       spin_unlock_irqrestore(&pgd_lock, flags);
+       spin_unlock(&pgd_lock);
 }
 
 /*
@@ -260,7 +258,6 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
 {
        pgd_t *pgd;
        pmd_t *pmds[PREALLOCATED_PMDS];
-       unsigned long flags;
 
        pgd = (pgd_t *)__get_free_page(PGALLOC_GFP);
 
@@ -280,12 +277,12 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
         * respect to anything walking the pgd_list, so that they
         * never see a partially populated pgd.
         */
-       spin_lock_irqsave(&pgd_lock, flags);
+       spin_lock(&pgd_lock);
 
        pgd_ctor(mm, pgd);
        pgd_prepopulate_pmd(mm, pgd, pmds);
 
-       spin_unlock_irqrestore(&pgd_lock, flags);
+       spin_unlock(&pgd_lock);
 
        return pgd;
 
index ae96e7b..48651c6 100644 (file)
@@ -57,7 +57,7 @@ struct node_memory_chunk_s {
 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_APICID];
+static u8 __initdata apicid_to_pxm[MAX_LOCAL_APIC];
 
 int acpi_numa __initdata;
 
@@ -254,8 +254,8 @@ int __init get_memcfg_from_srat(void)
        printk(KERN_DEBUG "Number of memory chunks in system = %d\n",
                         num_memory_chunks);
 
-       for (i = 0; i < MAX_APICID; i++)
-               apicid_2_node[i] = pxm_to_node(apicid_to_pxm[i]);
+       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];
index 603d285..8e9d339 100644 (file)
 
 int acpi_numa __initdata;
 
-static struct acpi_table_slit *acpi_slit;
-
-static nodemask_t nodes_parsed __initdata;
-static nodemask_t cpu_nodes_parsed __initdata;
-static struct bootnode nodes[MAX_NUMNODES] __initdata;
 static struct bootnode nodes_add[MAX_NUMNODES];
 
-static int num_node_memblks __initdata;
-static struct bootnode node_memblk_range[NR_NODE_MEMBLKS] __initdata;
-static int memblk_nodeid[NR_NODE_MEMBLKS] __initdata;
-
 static __init int setup_node(int pxm)
 {
        return acpi_map_pxm_to_node(pxm);
 }
 
-static __init int conflicting_memblks(unsigned long start, unsigned long end)
-{
-       int i;
-       for (i = 0; i < num_node_memblks; i++) {
-               struct bootnode *nd = &node_memblk_range[i];
-               if (nd->start == nd->end)
-                       continue;
-               if (nd->end > start && nd->start < end)
-                       return memblk_nodeid[i];
-               if (nd->end == end && nd->start == start)
-                       return memblk_nodeid[i];
-       }
-       return -1;
-}
-
-static __init void cutoff_node(int i, unsigned long start, unsigned long end)
-{
-       struct bootnode *nd = &nodes[i];
-
-       if (nd->start < start) {
-               nd->start = start;
-               if (nd->end < nd->start)
-                       nd->start = nd->end;
-       }
-       if (nd->end > end) {
-               nd->end = end;
-               if (nd->start > nd->end)
-                       nd->start = nd->end;
-       }
-}
-
 static __init void bad_srat(void)
 {
-       int i;
        printk(KERN_ERR "SRAT: SRAT not used.\n");
        acpi_numa = -1;
-       for (i = 0; i < MAX_LOCAL_APIC; i++)
-               apicid_to_node[i] = NUMA_NO_NODE;
-       for (i = 0; i < MAX_NUMNODES; i++) {
-               nodes[i].start = nodes[i].end = 0;
-               nodes_add[i].start = nodes_add[i].end = 0;
-       }
-       remove_all_active_ranges();
+       memset(nodes_add, 0, sizeof(nodes_add));
 }
 
 static __init inline int srat_disabled(void)
 {
-       return numa_off || acpi_numa < 0;
+       return acpi_numa < 0;
 }
 
 /* Callback for SLIT parsing */
 void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
 {
-       unsigned length;
-       unsigned long phys;
-
-       length = slit->header.length;
-       phys = memblock_find_in_range(0, max_pfn_mapped<<PAGE_SHIFT, length,
-                PAGE_SIZE);
-
-       if (phys == MEMBLOCK_ERROR)
-               panic(" Can not save slit!\n");
+       int i, j;
 
-       acpi_slit = __va(phys);
-       memcpy(acpi_slit, slit, length);
-       memblock_x86_reserve_range(phys, phys + length, "ACPI SLIT");
+       for (i = 0; i < slit->locality_count; i++)
+               for (j = 0; j < slit->locality_count; j++)
+                       numa_set_distance(pxm_to_node(i), pxm_to_node(j),
+                               slit->entry[slit->locality_count * i + j]);
 }
 
 /* Callback for Proximity Domain -> x2APIC mapping */
@@ -138,8 +84,8 @@ acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa)
                printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node);
                return;
        }
-       apicid_to_node[apic_id] = node;
-       node_set(node, cpu_nodes_parsed);
+       set_apicid_to_node(apic_id, node);
+       node_set(node, numa_nodes_parsed);
        acpi_numa = 1;
        printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u\n",
               pxm, apic_id, node);
@@ -178,8 +124,8 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
                return;
        }
 
-       apicid_to_node[apic_id] = node;
-       node_set(node, cpu_nodes_parsed);
+       set_apicid_to_node(apic_id, node);
+       node_set(node, numa_nodes_parsed);
        acpi_numa = 1;
        printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u\n",
               pxm, apic_id, node);
@@ -241,7 +187,7 @@ update_nodes_add(int node, unsigned long start, unsigned long end)
        }
 
        if (changed) {
-               node_set(node, cpu_nodes_parsed);
+               node_set(node, numa_nodes_parsed);
                printk(KERN_INFO "SRAT: hot plug zone found %Lx - %Lx\n",
                                 nd->start, nd->end);
        }
@@ -251,10 +197,8 @@ update_nodes_add(int node, unsigned long start, unsigned long end)
 void __init
 acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
 {
-       struct bootnode *nd, oldnode;
        unsigned long start, end;
        int node, pxm;
-       int i;
 
        if (srat_disabled())
                return;
@@ -276,300 +220,31 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
                bad_srat();
                return;
        }
-       i = conflicting_memblks(start, end);
-       if (i == node) {
-               printk(KERN_WARNING
-               "SRAT: Warning: PXM %d (%lx-%lx) overlaps with itself (%Lx-%Lx)\n",
-                       pxm, start, end, nodes[i].start, nodes[i].end);
-       } else if (i >= 0) {
-               printk(KERN_ERR
-                      "SRAT: PXM %d (%lx-%lx) overlaps with PXM %d (%Lx-%Lx)\n",
-                      pxm, start, end, node_to_pxm(i),
-                       nodes[i].start, nodes[i].end);
+
+       if (numa_add_memblk(node, start, end) < 0) {
                bad_srat();
                return;
        }
-       nd = &nodes[node];
-       oldnode = *nd;
-       if (!node_test_and_set(node, nodes_parsed)) {
-               nd->start = start;
-               nd->end = end;
-       } else {
-               if (start < nd->start)
-                       nd->start = start;
-               if (nd->end < end)
-                       nd->end = end;
-       }
 
        printk(KERN_INFO "SRAT: Node %u PXM %u %lx-%lx\n", node, pxm,
               start, end);
 
-       if (ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) {
+       if (ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE)
                update_nodes_add(node, start, end);
-               /* restore nodes[node] */
-               *nd = oldnode;
-               if ((nd->start | nd->end) == 0)
-                       node_clear(node, nodes_parsed);
-       }
-
-       node_memblk_range[num_node_memblks].start = start;
-       node_memblk_range[num_node_memblks].end = end;
-       memblk_nodeid[num_node_memblks] = node;
-       num_node_memblks++;
-}
-
-/* Sanity check to catch more bad SRATs (they are amazingly common).
-   Make sure the PXMs cover all memory. */
-static int __init nodes_cover_memory(const struct bootnode *nodes)
-{
-       int i;
-       unsigned long pxmram, e820ram;
-
-       pxmram = 0;
-       for_each_node_mask(i, nodes_parsed) {
-               unsigned long s = nodes[i].start >> PAGE_SHIFT;
-               unsigned long e = nodes[i].end >> PAGE_SHIFT;
-               pxmram += e - s;
-               pxmram -= __absent_pages_in_range(i, s, e);
-               if ((long)pxmram < 0)
-                       pxmram = 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 - pxmram) >= (1<<(20 - PAGE_SHIFT))) {
-               printk(KERN_ERR
-       "SRAT: PXMs only cover %luMB of your %luMB e820 RAM. Not used.\n",
-                       (pxmram << PAGE_SHIFT) >> 20,
-                       (e820ram << PAGE_SHIFT) >> 20);
-               return 0;
-       }
-       return 1;
 }
 
 void __init acpi_numa_arch_fixup(void) {}
 
-#ifdef CONFIG_NUMA_EMU
-void __init acpi_get_nodes(struct bootnode *physnodes, unsigned long start,
-                               unsigned long end)
-{
-       int i;
-
-       for_each_node_mask(i, nodes_parsed) {
-               cutoff_node(i, start, end);
-               physnodes[i].start = nodes[i].start;
-               physnodes[i].end = nodes[i].end;
-       }
-}
-#endif /* CONFIG_NUMA_EMU */
-
-/* Use the information discovered above to actually set up the nodes. */
-int __init acpi_scan_nodes(unsigned long start, unsigned long end)
+int __init x86_acpi_numa_init(void)
 {
-       int i;
-
-       if (acpi_numa <= 0)
-               return -1;
-
-       /* First clean up the node list */
-       for (i = 0; i < MAX_NUMNODES; i++)
-               cutoff_node(i, start, end);
-
-       /*
-        * Join together blocks on the same node, holes between
-        * which don't overlap with memory on other nodes.
-        */
-       for (i = 0; i < num_node_memblks; ++i) {
-               int j, k;
-
-               for (j = i + 1; j < num_node_memblks; ++j) {
-                       unsigned long start, end;
-
-                       if (memblk_nodeid[i] != memblk_nodeid[j])
-                               continue;
-                       start = min(node_memblk_range[i].end,
-                                   node_memblk_range[j].end);
-                       end = max(node_memblk_range[i].start,
-                                 node_memblk_range[j].start);
-                       for (k = 0; k < num_node_memblks; ++k) {
-                               if (memblk_nodeid[i] == memblk_nodeid[k])
-                                       continue;
-                               if (start < node_memblk_range[k].end &&
-                                   end > node_memblk_range[k].start)
-                                       break;
-                       }
-                       if (k < num_node_memblks)
-                               continue;
-                       start = min(node_memblk_range[i].start,
-                                   node_memblk_range[j].start);
-                       end = max(node_memblk_range[i].end,
-                                 node_memblk_range[j].end);
-                       printk(KERN_INFO "SRAT: Node %d "
-                              "[%Lx,%Lx) + [%Lx,%Lx) -> [%lx,%lx)\n",
-                              memblk_nodeid[i],
-                              node_memblk_range[i].start,
-                              node_memblk_range[i].end,
-                              node_memblk_range[j].start,
-                              node_memblk_range[j].end,
-                              start, end);
-                       node_memblk_range[i].start = start;
-                       node_memblk_range[i].end = end;
-                       k = --num_node_memblks - j;
-                       memmove(memblk_nodeid + j, memblk_nodeid + j+1,
-                               k * sizeof(*memblk_nodeid));
-                       memmove(node_memblk_range + j, node_memblk_range + j+1,
-                               k * sizeof(*node_memblk_range));
-                       --j;
-               }
-       }
-
-       memnode_shift = compute_hash_shift(node_memblk_range, num_node_memblks,
-                                          memblk_nodeid);
-       if (memnode_shift < 0) {
-               printk(KERN_ERR
-                    "SRAT: No NUMA node hash function found. Contact maintainer\n");
-               bad_srat();
-               return -1;
-       }
-
-       for (i = 0; i < num_node_memblks; i++)
-               memblock_x86_register_active_regions(memblk_nodeid[i],
-                               node_memblk_range[i].start >> PAGE_SHIFT,
-                               node_memblk_range[i].end >> PAGE_SHIFT);
-
-       /* for out of order entries in SRAT */
-       sort_node_map();
-       if (!nodes_cover_memory(nodes)) {
-               bad_srat();
-               return -1;
-       }
+       int ret;
 
-       /* Account for nodes with cpus and no memory */
-       nodes_or(node_possible_map, nodes_parsed, cpu_nodes_parsed);
-
-       /* Finally register nodes */
-       for_each_node_mask(i, node_possible_map)
-               setup_node_bootmem(i, nodes[i].start, nodes[i].end);
-       /* Try again in case setup_node_bootmem missed one due
-          to missing bootmem */
-       for_each_node_mask(i, node_possible_map)
-               if (!node_online(i))
-                       setup_node_bootmem(i, nodes[i].start, nodes[i].end);
-
-       for (i = 0; i < nr_cpu_ids; i++) {
-               int node = early_cpu_to_node(i);
-
-               if (node == NUMA_NO_NODE)
-                       continue;
-               if (!node_online(node))
-                       numa_clear_node(i);
-       }
-       numa_init_array();
-       return 0;
-}
-
-#ifdef CONFIG_NUMA_EMU
-static int fake_node_to_pxm_map[MAX_NUMNODES] __initdata = {
-       [0 ... MAX_NUMNODES-1] = PXM_INVAL
-};
-static s16 fake_apicid_to_node[MAX_LOCAL_APIC] __initdata = {
-       [0 ... MAX_LOCAL_APIC-1] = NUMA_NO_NODE
-};
-static int __init find_node_by_addr(unsigned long addr)
-{
-       int ret = NUMA_NO_NODE;
-       int i;
-
-       for_each_node_mask(i, nodes_parsed) {
-               /*
-                * Find the real node that this emulated node appears on.  For
-                * the sake of simplicity, we only use a real node's starting
-                * address to determine which emulated node it appears on.
-                */
-               if (addr >= nodes[i].start && addr < nodes[i].end) {
-                       ret = i;
-                       break;
-               }
-       }
-       return ret;
+       ret = acpi_numa_init();
+       if (ret < 0)
+               return ret;
+       return srat_disabled() ? -EINVAL : 0;
 }
 
-/*
- * In NUMA emulation, we need to setup proximity domain (_PXM) to node ID
- * mappings that respect the real ACPI topology but reflect our emulated
- * environment.  For each emulated node, we find which real node it appears on
- * and create PXM to NID mappings for those fake nodes which mirror that
- * locality.  SLIT will now represent the correct distances between emulated
- * nodes as a result of the real topology.
- */
-void __init acpi_fake_nodes(const struct bootnode *fake_nodes, int num_nodes)
-{
-       int i, j;
-
-       for (i = 0; i < num_nodes; i++) {
-               int nid, pxm;
-
-               nid = find_node_by_addr(fake_nodes[i].start);
-               if (nid == NUMA_NO_NODE)
-                       continue;
-               pxm = node_to_pxm(nid);
-               if (pxm == PXM_INVAL)
-                       continue;
-               fake_node_to_pxm_map[i] = pxm;
-               /*
-                * For each apicid_to_node mapping that exists for this real
-                * node, it must now point to the fake node ID.
-                */
-               for (j = 0; j < MAX_LOCAL_APIC; j++)
-                       if (apicid_to_node[j] == nid &&
-                           fake_apicid_to_node[j] == NUMA_NO_NODE)
-                               fake_apicid_to_node[j] = i;
-       }
-
-       /*
-        * If there are apicid-to-node mappings for physical nodes that do not
-        * have a corresponding emulated node, it should default to a guaranteed
-        * value.
-        */
-       for (i = 0; i < MAX_LOCAL_APIC; i++)
-               if (apicid_to_node[i] != NUMA_NO_NODE &&
-                   fake_apicid_to_node[i] == NUMA_NO_NODE)
-                       fake_apicid_to_node[i] = 0;
-
-       for (i = 0; i < num_nodes; i++)
-               __acpi_map_pxm_to_node(fake_node_to_pxm_map[i], i);
-       memcpy(apicid_to_node, fake_apicid_to_node, sizeof(apicid_to_node));
-
-       nodes_clear(nodes_parsed);
-       for (i = 0; i < num_nodes; i++)
-               if (fake_nodes[i].start != fake_nodes[i].end)
-                       node_set(i, nodes_parsed);
-}
-
-static int null_slit_node_compare(int a, int b)
-{
-       return node_to_pxm(a) == node_to_pxm(b);
-}
-#else
-static int null_slit_node_compare(int a, int b)
-{
-       return a == b;
-}
-#endif /* CONFIG_NUMA_EMU */
-
-int __node_distance(int a, int b)
-{
-       int index;
-
-       if (!acpi_slit)
-               return null_slit_node_compare(a, b) ? LOCAL_DISTANCE :
-                                                     REMOTE_DISTANCE;
-       index = acpi_slit->locality_count * node_to_pxm(a);
-       return acpi_slit->entry[index + node_to_pxm(b)];
-}
-
-EXPORT_SYMBOL(__node_distance);
-
 #if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) || defined(CONFIG_ACPI_HOTPLUG_MEMORY)
 int memory_add_physaddr_to_nid(u64 start)
 {
index 6acc724..d6c0418 100644 (file)
@@ -179,12 +179,8 @@ static void flush_tlb_others_ipi(const struct cpumask *cpumask,
        sender = this_cpu_read(tlb_vector_offset);
        f = &flush_state[sender];
 
-       /*
-        * Could avoid this lock when
-        * num_online_cpus() <= NUM_INVALIDATE_TLB_VECTORS, but it is
-        * probably not worth checking this for a cache-hot lock.
-        */
-       raw_spin_lock(&f->tlbstate_lock);
+       if (nr_cpu_ids > NUM_INVALIDATE_TLB_VECTORS)
+               raw_spin_lock(&f->tlbstate_lock);
 
        f->flush_mm = mm;
        f->flush_va = va;
@@ -202,7 +198,8 @@ static void flush_tlb_others_ipi(const struct cpumask *cpumask,
 
        f->flush_mm = NULL;
        f->flush_va = 0;
-       raw_spin_unlock(&f->tlbstate_lock);
+       if (nr_cpu_ids > NUM_INVALIDATE_TLB_VECTORS)
+               raw_spin_unlock(&f->tlbstate_lock);
 }
 
 void native_flush_tlb_others(const struct cpumask *cpumask,
@@ -211,11 +208,10 @@ void native_flush_tlb_others(const struct cpumask *cpumask,
        if (is_uv_system()) {
                unsigned int cpu;
 
-               cpu = get_cpu();
+               cpu = smp_processor_id();
                cpumask = uv_flush_tlb_others(cpumask, mm, va, cpu);
                if (cpumask)
                        flush_tlb_others_ipi(cpumask, mm, va);
-               put_cpu();
                return;
        }
        flush_tlb_others_ipi(cpumask, mm, va);
index e27dffb..026e493 100644 (file)
@@ -350,7 +350,7 @@ static int __init early_fill_mp_bus_info(void)
 
 #define ENABLE_CF8_EXT_CFG      (1ULL << 46)
 
-static void enable_pci_io_ecs(void *unused)
+static void __cpuinit enable_pci_io_ecs(void *unused)
 {
        u64 reg;
        rdmsrl(MSR_AMD64_NB_CFG, reg);
index 85b68ef..67858be 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 
+#include <asm/ce4100.h>
 #include <asm/pci_x86.h>
 
 struct sim_reg {
@@ -254,7 +255,7 @@ int bridge_read(unsigned int devfn, int reg, int len, u32 *value)
 static int ce4100_conf_read(unsigned int seg, unsigned int bus,
                            unsigned int devfn, int reg, int len, u32 *value)
 {
-       int i, retval = 1;
+       int i;
 
        if (bus == 1) {
                for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) {
@@ -306,10 +307,10 @@ struct pci_raw_ops ce4100_pci_conf = {
        .write = ce4100_conf_write,
 };
 
-static int __init ce4100_pci_init(void)
+int __init ce4100_pci_init(void)
 {
        init_sim_regs();
        raw_pci_ops = &ce4100_pci_conf;
-       return 0;
+       /* Indicate caller that it should invoke pci_legacy_init() */
+       return 1;
 }
-subsys_initcall(ce4100_pci_init);
index 25cd4a0..8c4085a 100644 (file)
@@ -20,7 +20,8 @@
 #include <asm/xen/pci.h>
 
 #ifdef CONFIG_ACPI
-static int xen_hvm_register_pirq(u32 gsi, int triggering)
+static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi,
+                                int trigger, int polarity)
 {
        int rc, irq;
        struct physdev_map_pirq map_irq;
@@ -41,7 +42,7 @@ static int xen_hvm_register_pirq(u32 gsi, int triggering)
                return -1;
        }
 
-       if (triggering == ACPI_EDGE_SENSITIVE) {
+       if (trigger == ACPI_EDGE_SENSITIVE) {
                shareable = 0;
                name = "ioapic-edge";
        } else {
@@ -55,12 +56,6 @@ static int xen_hvm_register_pirq(u32 gsi, int triggering)
 
        return irq;
 }
-
-static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi,
-                                int trigger, int polarity)
-{
-       return xen_hvm_register_pirq(gsi, trigger);
-}
 #endif
 
 #if defined(CONFIG_PCI_MSI)
@@ -91,7 +86,7 @@ static void xen_msi_compose_msg(struct pci_dev *pdev, unsigned int pirq,
 
 static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
 {
-       int irq, pirq, ret = 0;
+       int irq, pirq;
        struct msi_desc *msidesc;
        struct msi_msg msg;
 
@@ -99,39 +94,32 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
                __read_msi_msg(msidesc, &msg);
                pirq = MSI_ADDR_EXT_DEST_ID(msg.address_hi) |
                        ((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff);
-               if (xen_irq_from_pirq(pirq) >= 0 && msg.data == XEN_PIRQ_MSI_DATA) {
-                       xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ?
-                                       "msi-x" : "msi", &irq, &pirq, XEN_ALLOC_IRQ);
-                       if (irq < 0)
+               if (msg.data != XEN_PIRQ_MSI_DATA ||
+                   xen_irq_from_pirq(pirq) < 0) {
+                       pirq = xen_allocate_pirq_msi(dev, msidesc);
+                       if (pirq < 0)
                                goto error;
-                       ret = set_irq_msi(irq, msidesc);
-                       if (ret < 0)
-                               goto error_while;
-                       printk(KERN_DEBUG "xen: msi already setup: msi --> irq=%d"
-                                       " pirq=%d\n", irq, pirq);
-                       return 0;
+                       xen_msi_compose_msg(dev, pirq, &msg);
+                       __write_msi_msg(msidesc, &msg);
+                       dev_dbg(&dev->dev, "xen: msi bound to pirq=%d\n", pirq);
+               } else {
+                       dev_dbg(&dev->dev,
+                               "xen: msi already bound to pirq=%d\n", pirq);
                }
-               xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ?
-                               "msi-x" : "msi", &irq, &pirq, (XEN_ALLOC_IRQ | XEN_ALLOC_PIRQ));
-               if (irq < 0 || pirq < 0)
+               irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq, 0,
+                                              (type == PCI_CAP_ID_MSIX) ?
+                                              "msi-x" : "msi");
+               if (irq < 0)
                        goto error;
-               printk(KERN_DEBUG "xen: msi --> irq=%d, pirq=%d\n", irq, pirq);
-               xen_msi_compose_msg(dev, pirq, &msg);
-               ret = set_irq_msi(irq, msidesc);
-               if (ret < 0)
-                       goto error_while;
-               write_msi_msg(irq, &msg);
+               dev_dbg(&dev->dev,
+                       "xen: msi --> pirq=%d --> irq=%d\n", pirq, irq);
        }
        return 0;
 
-error_while:
-       unbind_from_irqhandler(irq, NULL);
 error:
-       if (ret == -ENODEV)
-               dev_err(&dev->dev, "Xen PCI frontend has not registered" \
-                               " MSI/MSI-X support!\n");
-
-       return ret;
+       dev_err(&dev->dev,
+               "Xen PCI frontend has not registered MSI/MSI-X support!\n");
+       return -ENODEV;
 }
 
 /*
@@ -150,35 +138,26 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
                return -ENOMEM;
 
        if (type == PCI_CAP_ID_MSIX)
-               ret = xen_pci_frontend_enable_msix(dev, &v, nvec);
+               ret = xen_pci_frontend_enable_msix(dev, v, nvec);
        else
-               ret = xen_pci_frontend_enable_msi(dev, &v);
+               ret = xen_pci_frontend_enable_msi(dev, v);
        if (ret)
                goto error;
        i = 0;
        list_for_each_entry(msidesc, &dev->msi_list, list) {
-               irq = xen_allocate_pirq(v[i], 0, /* not sharable */
-                       (type == PCI_CAP_ID_MSIX) ?
-                       "pcifront-msi-x" : "pcifront-msi");
-               if (irq < 0) {
-                       ret = -1;
+               irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i], 0,
+                                              (type == PCI_CAP_ID_MSIX) ?
+                                              "pcifront-msi-x" :
+                                              "pcifront-msi");
+               if (irq < 0)
                        goto free;
-               }
-
-               ret = set_irq_msi(irq, msidesc);
-               if (ret)
-                       goto error_while;
                i++;
        }
        kfree(v);
        return 0;
 
-error_while:
-       unbind_from_irqhandler(irq, NULL);
 error:
-       if (ret == -ENODEV)
-               dev_err(&dev->dev, "Xen PCI frontend has not registered" \
-                       " MSI/MSI-X support!\n");
+       dev_err(&dev->dev, "Xen PCI frontend has not registered MSI/MSI-X support!\n");
 free:
        kfree(v);
        return ret;
@@ -193,6 +172,9 @@ static void xen_teardown_msi_irqs(struct pci_dev *dev)
                xen_pci_frontend_disable_msix(dev);
        else
                xen_pci_frontend_disable_msi(dev);
+
+       /* Free the IRQ's and the msidesc using the generic code. */
+       default_teardown_msi_irqs(dev);
 }
 
 static void xen_teardown_msi_irq(unsigned int irq)
@@ -200,47 +182,82 @@ static void xen_teardown_msi_irq(unsigned int irq)
        xen_destroy_irq(irq);
 }
 
+#ifdef CONFIG_XEN_DOM0
 static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
 {
-       int irq, ret;
+       int ret = 0;
        struct msi_desc *msidesc;
 
        list_for_each_entry(msidesc, &dev->msi_list, list) {
-               irq = xen_create_msi_irq(dev, msidesc, type);
-               if (irq < 0)
-                       return -1;
+               struct physdev_map_pirq map_irq;
 
-               ret = set_irq_msi(irq, msidesc);
-               if (ret)
-                       goto error;
-       }
-       return 0;
+               memset(&map_irq, 0, sizeof(map_irq));
+               map_irq.domid = DOMID_SELF;
+               map_irq.type = MAP_PIRQ_TYPE_MSI;
+               map_irq.index = -1;
+               map_irq.pirq = -1;
+               map_irq.bus = dev->bus->number;
+               map_irq.devfn = dev->devfn;
 
-error:
-       xen_destroy_irq(irq);
+               if (type == PCI_CAP_ID_MSIX) {
+                       int pos;
+                       u32 table_offset, bir;
+
+                       pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+
+                       pci_read_config_dword(dev, pos + PCI_MSIX_TABLE,
+                                             &table_offset);
+                       bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
+
+                       map_irq.table_base = pci_resource_start(dev, bir);
+                       map_irq.entry_nr = msidesc->msi_attrib.entry_nr;
+               }
+
+               ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
+               if (ret) {
+                       dev_warn(&dev->dev, "xen map irq failed %d\n", ret);
+                       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");
+               if (ret < 0)
+                       goto out;
+       }
+       ret = 0;
+out:
        return ret;
 }
 #endif
+#endif
 
 static int xen_pcifront_enable_irq(struct pci_dev *dev)
 {
        int rc;
        int share = 1;
+       u8 gsi;
 
-       dev_info(&dev->dev, "Xen PCI enabling IRQ: %d\n", dev->irq);
-
-       if (dev->irq < 0)
-               return -EINVAL;
+       rc = pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &gsi);
+       if (rc < 0) {
+               dev_warn(&dev->dev, "Xen PCI: failed to read interrupt line: %d\n",
+                        rc);
+               return rc;
+       }
 
-       if (dev->irq < NR_IRQS_LEGACY)
+       if (gsi < NR_IRQS_LEGACY)
                share = 0;
 
-       rc = xen_allocate_pirq(dev->irq, share, "pcifront");
+       rc = xen_allocate_pirq(gsi, share, "pcifront");
        if (rc < 0) {
-               dev_warn(&dev->dev, "Xen PCI IRQ: %d, failed to register:%d\n",
-                        dev->irq, rc);
+               dev_warn(&dev->dev, "Xen PCI: failed to register GSI%d: %d\n",
+                        gsi, rc);
                return rc;
        }
+
+       dev->irq = rc;
+       dev_info(&dev->dev, "Xen PCI mapped GSI%d to IRQ%d\n", gsi, dev->irq);
        return 0;
 }
 
index d2c0d51..28071bb 100644 (file)
 #include <linux/serial_reg.h>
 #include <linux/serial_8250.h>
 
+#include <asm/ce4100.h>
+#include <asm/prom.h>
 #include <asm/setup.h>
+#include <asm/i8259.h>
 #include <asm/io.h>
+#include <asm/io_apic.h>
 
 static int ce4100_i8042_detect(void)
 {
        return 0;
 }
 
-static void __init sdv_find_smp_config(void)
-{
-}
-
 #ifdef CONFIG_SERIAL_8250
 
-
 static unsigned int mem_serial_in(struct uart_port *p, int offset)
 {
        offset = offset << p->regshift;
@@ -118,6 +117,15 @@ static void __init sdv_arch_setup(void)
        sdv_serial_fixup();
 }
 
+#ifdef CONFIG_X86_IO_APIC
+static void __cpuinit sdv_pci_init(void)
+{
+       x86_of_pci_init();
+       /* We can't set this earlier, because we need to calibrate the timer */
+       legacy_pic = &null_legacy_pic;
+}
+#endif
+
 /*
  * CE4100 specific x86_init function overrides and early setup
  * calls.
@@ -128,5 +136,11 @@ void __init x86_ce4100_early_setup(void)
        x86_platform.i8042_detect = ce4100_i8042_detect;
        x86_init.resources.probe_roms = x86_init_noop;
        x86_init.mpparse.get_smp_config = x86_init_uint_noop;
-       x86_init.mpparse.find_smp_config = sdv_find_smp_config;
+       x86_init.mpparse.find_smp_config = x86_init_noop;
+       x86_init.pci.init = ce4100_pci_init;
+
+#ifdef CONFIG_X86_IO_APIC
+       x86_init.pci.init_irq = sdv_pci_init;
+       x86_init.mpparse.setup_ioapic_ids = setup_ioapic_ids_from_mpc_nocheck;
+#endif
 }
diff --git a/arch/x86/platform/ce4100/falconfalls.dts b/arch/x86/platform/ce4100/falconfalls.dts
new file mode 100644 (file)
index 0000000..dc701ea
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ * CE4100 on Falcon Falls
+ *
+ * (c) Copyright 2010 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ */
+/dts-v1/;
+/ {
+       model = "intel,falconfalls";
+       compatible = "intel,falconfalls";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       device_type = "cpu";
+                       compatible = "intel,ce4100";
+                       reg = <0>;
+                       lapic = <&lapic0>;
+               };
+       };
+
+       soc@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "intel,ce4100-cp";
+               ranges;
+
+               ioapic1: interrupt-controller@fec00000 {
+                       #interrupt-cells = <2>;
+                       compatible = "intel,ce4100-ioapic";
+                       interrupt-controller;
+                       reg = <0xfec00000 0x1000>;
+               };
+
+               timer@fed00000 {
+                       compatible = "intel,ce4100-hpet";
+                       reg = <0xfed00000 0x200>;
+               };
+
+               lapic0: interrupt-controller@fee00000 {
+                       compatible = "intel,ce4100-lapic";
+                       reg = <0xfee00000 0x1000>;
+               };
+
+               pci@3fc {
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       compatible = "intel,ce4100-pci", "pci";
+                       device_type = "pci";
+                       bus-range = <0 0>;
+                       ranges = <0x2000000 0 0xbffff000 0xbffff000 0 0x1000
+                                 0x2000000 0 0xdffe0000 0xdffe0000 0 0x1000
+                                 0x0000000 0 0x0        0x0        0 0x100>;
+
+                       /* Secondary IO-APIC */
+                       ioapic2: interrupt-controller@0,1 {
+                               #interrupt-cells = <2>;
+                               compatible = "intel,ce4100-ioapic";
+                               interrupt-controller;
+                               reg = <0x100 0x0 0x0 0x0 0x0>;
+                               assigned-addresses = <0x02000000 0x0 0xbffff000 0x0 0x1000>;
+                       };
+
+                       pci@1,0 {
+                               #address-cells = <3>;
+                               #size-cells = <2>;
+                               compatible = "intel,ce4100-pci", "pci";
+                               device_type = "pci";
+                               bus-range = <1 1>;
+                               ranges = <0x2000000 0 0xdffe0000 0x2000000 0 0xdffe0000 0 0x1000>;
+
+                               interrupt-parent = <&ioapic2>;
+
+                               display@2,0 {
+                                       compatible = "pci8086,2e5b.2",
+                                                  "pci8086,2e5b",
+                                                  "pciclass038000",
+                                                  "pciclass0380";
+
+                                       reg = <0x11000 0x0 0x0 0x0 0x0>;
+                                       interrupts = <0 1>;
+                               };
+
+                               multimedia@3,0 {
+                                       compatible = "pci8086,2e5c.2",
+                                                  "pci8086,2e5c",
+                                                  "pciclass048000",
+                                                  "pciclass0480";
+
+                                       reg = <0x11800 0x0 0x0 0x0 0x0>;
+                                       interrupts = <2 1>;
+                               };
+
+                               multimedia@4,0 {
+                                       compatible = "pci8086,2e5d.2",
+                                                  "pci8086,2e5d",
+                                                  "pciclass048000",
+                                                  "pciclass0480";
+
+                                       reg = <0x12000 0x0 0x0 0x0 0x0>;
+                                       interrupts = <4 1>;
+                               };
+
+                               multimedia@4,1 {
+                                       compatible = "pci8086,2e5e.2",
+                                                  "pci8086,2e5e",
+                                                  "pciclass048000",
+                                                  "pciclass0480";
+
+                                       reg = <0x12100 0x0 0x0 0x0 0x0>;
+                                       interrupts = <5 1>;
+                               };
+
+                               sound@6,0 {
+                                       compatible = "pci8086,2e5f.2",
+                                                  "pci8086,2e5f",
+                                                  "pciclass040100",
+                                                  "pciclass0401";
+
+                                       reg = <0x13000 0x0 0x0 0x0 0x0>;
+                                       interrupts = <6 1>;
+                               };
+
+                               sound@6,1 {
+                                       compatible = "pci8086,2e5f.2",
+                                                  "pci8086,2e5f",
+                                                  "pciclass040100",
+                                                  "pciclass0401";
+
+                                       reg = <0x13100 0x0 0x0 0x0 0x0>;
+                                       interrupts = <7 1>;
+                               };
+
+                               sound@6,2 {
+                                       compatible = "pci8086,2e60.2",
+                                                  "pci8086,2e60",
+                                                  "pciclass040100",
+                                                  "pciclass0401";
+
+                                       reg = <0x13200 0x0 0x0 0x0 0x0>;
+                                       interrupts = <8 1>;
+                               };
+
+                               display@8,0 {
+                                       compatible = "pci8086,2e61.2",
+                                                  "pci8086,2e61",
+                                                  "pciclass038000",
+                                                  "pciclass0380";
+
+                                       reg = <0x14000 0x0 0x0 0x0 0x0>;
+                                       interrupts = <9 1>;
+                               };
+
+                               display@8,1 {
+                                       compatible = "pci8086,2e62.2",
+                                                  "pci8086,2e62",
+                                                  "pciclass038000",
+                                                  "pciclass0380";
+
+                                       reg = <0x14100 0x0 0x0 0x0 0x0>;
+                                       interrupts = <10 1>;
+                               };
+
+                               multimedia@8,2 {
+                                       compatible = "pci8086,2e63.2",
+                                                  "pci8086,2e63",
+                                                  "pciclass048000",
+                                                  "pciclass0480";
+
+                                       reg = <0x14200 0x0 0x0 0x0 0x0>;
+                                       interrupts = <11 1>;
+                               };
+
+                               entertainment-encryption@9,0 {
+                                       compatible = "pci8086,2e64.2",
+                                                  "pci8086,2e64",
+                                                  "pciclass101000",
+                                                  "pciclass1010";
+
+                                       reg = <0x14800 0x0 0x0 0x0 0x0>;
+                                       interrupts = <12 1>;
+                               };
+
+                               localbus@a,0 {
+                                       compatible = "pci8086,2e65.2",
+                                                  "pci8086,2e65",
+                                                  "pciclassff0000",
+                                                  "pciclassff00";
+
+                                       reg = <0x15000 0x0 0x0 0x0 0x0>;
+                               };
+
+                               serial@b,0 {
+                                       compatible = "pci8086,2e66.2",
+                                                  "pci8086,2e66",
+                                                  "pciclass070003",
+                                                  "pciclass0700";
+
+                                       reg = <0x15800 0x0 0x0 0x0 0x0>;
+                                       interrupts = <14 1>;
+                               };
+
+                               gpio@b,1 {
+                                       compatible = "pci8086,2e67.2",
+                                                  "pci8086,2e67",
+                                                  "pciclassff0000",
+                                                  "pciclassff00";
+
+                                       #gpio-cells = <2>;
+                                       reg = <0x15900 0x0 0x0 0x0 0x0>;
+                                       interrupts = <15 1>;
+                                       gpio-controller;
+                               };
+
+                               i2c-controller@b,2 {
+                                       #address-cells = <2>;
+                                       #size-cells = <1>;
+                                       compatible = "pci8086,2e68.2",
+                                                  "pci8086,2e68",
+                                                  "pciclass,ff0000",
+                                                  "pciclass,ff00";
+
+                                       reg = <0x15a00 0x0 0x0 0x0 0x0>;
+                                       interrupts = <16 1>;
+                                       ranges = <0 0   0x02000000 0 0xdffe0500 0x100
+                                                 1 0   0x02000000 0 0xdffe0600 0x100
+                                                 2 0   0x02000000 0 0xdffe0700 0x100>;
+
+                                       i2c@0 {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+                                               compatible = "intel,ce4100-i2c-controller";
+                                               reg = <0 0 0x100>;
+                                       };
+
+                                       i2c@1 {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+                                               compatible = "intel,ce4100-i2c-controller";
+                                               reg = <1 0 0x100>;
+
+                                               gpio@26 {
+                                                       #gpio-cells = <2>;
+                                                       compatible = "ti,pcf8575";
+                                                       reg = <0x26>;
+                                                       gpio-controller;
+                                               };
+                                       };
+
+                                       i2c@2 {
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+                                               compatible = "intel,ce4100-i2c-controller";
+                                               reg = <2 0 0x100>;
+
+                                               gpio@26 {
+                                                       #gpio-cells = <2>;
+                                                       compatible = "ti,pcf8575";
+                                                       reg = <0x26>;
+                                                       gpio-controller;
+                                               };
+                                       };
+                               };
+
+                               smard-card@b,3 {
+                                       compatible = "pci8086,2e69.2",
+                                                  "pci8086,2e69",
+                                                  "pciclass070500",
+                                                  "pciclass0705";
+
+                                       reg = <0x15b00 0x0 0x0 0x0 0x0>;
+                                       interrupts = <15 1>;
+                               };
+
+                               spi-controller@b,4 {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+                                       compatible =
+                                               "pci8086,2e6a.2",
+                                               "pci8086,2e6a",
+                                               "pciclass,ff0000",
+                                               "pciclass,ff00";
+
+                                       reg = <0x15c00 0x0 0x0 0x0 0x0>;
+                                       interrupts = <15 1>;
+
+                                       dac@0 {
+                                               compatible = "ti,pcm1755";
+                                               reg = <0>;
+                                               spi-max-frequency = <115200>;
+                                       };
+
+                                       dac@1 {
+                                               compatible = "ti,pcm1609a";
+                                               reg = <1>;
+                                               spi-max-frequency = <115200>;
+                                       };
+
+                                       eeprom@2 {
+                                               compatible = "atmel,at93c46";
+                                               reg = <2>;
+                                               spi-max-frequency = <115200>;
+                                       };
+                               };
+
+                               multimedia@b,7 {
+                                       compatible = "pci8086,2e6d.2",
+                                                  "pci8086,2e6d",
+                                                  "pciclassff0000",
+                                                  "pciclassff00";
+
+                                       reg = <0x15f00 0x0 0x0 0x0 0x0>;
+                               };
+
+                               ethernet@c,0 {
+                                       compatible = "pci8086,2e6e.2",
+                                                  "pci8086,2e6e",
+                                                  "pciclass020000",
+                                                  "pciclass0200";
+
+                                       reg = <0x16000 0x0 0x0 0x0 0x0>;
+                                       interrupts = <21 1>;
+                               };
+
+                               clock@c,1 {
+                                       compatible = "pci8086,2e6f.2",
+                                                  "pci8086,2e6f",
+                                                  "pciclassff0000",
+                                                  "pciclassff00";
+
+                                       reg = <0x16100 0x0 0x0 0x0 0x0>;
+                                       interrupts = <3 1>;
+                               };
+
+                               usb@d,0 {
+                                       compatible = "pci8086,2e70.2",
+                                                  "pci8086,2e70",
+                                                  "pciclass0c0320",
+                                                  "pciclass0c03";
+
+                                       reg = <0x16800 0x0 0x0 0x0 0x0>;
+                                       interrupts = <22 3>;
+                               };
+
+                               usb@d,1 {
+                                       compatible = "pci8086,2e70.2",
+                                                  "pci8086,2e70",
+                                                  "pciclass0c0320",
+                                                  "pciclass0c03";
+
+                                       reg = <0x16900 0x0 0x0 0x0 0x0>;
+                                       interrupts = <22 3>;
+                               };
+
+                               sata@e,0 {
+                                       compatible = "pci8086,2e71.0",
+                                                  "pci8086,2e71",
+                                                  "pciclass010601",
+                                                  "pciclass0106";
+
+                                       reg = <0x17000 0x0 0x0 0x0 0x0>;
+                                       interrupts = <23 3>;
+                               };
+
+                               flash@f,0 {
+                                       compatible = "pci8086,701.1",
+                                                  "pci8086,701",
+                                                  "pciclass050100",
+                                                  "pciclass0501";
+
+                                       reg = <0x17800 0x0 0x0 0x0 0x0>;
+                                       interrupts = <13 1>;
+                               };
+
+                               entertainment-encryption@10,0 {
+                                       compatible = "pci8086,702.1",
+                                                  "pci8086,702",
+                                                  "pciclass101000",
+                                                  "pciclass1010";
+
+                                       reg = <0x18000 0x0 0x0 0x0 0x0>;
+                               };
+
+                               co-processor@11,0 {
+                                       compatible = "pci8086,703.1",
+                                                  "pci8086,703",
+                                                  "pciclass0b4000",
+                                                  "pciclass0b40";
+
+                                       reg = <0x18800 0x0 0x0 0x0 0x0>;
+                                       interrupts = <1 1>;
+                               };
+
+                               multimedia@12,0 {
+                                       compatible = "pci8086,704.0",
+                                                  "pci8086,704",
+                                                  "pciclass048000",
+                                                  "pciclass0480";
+
+                                       reg = <0x19000 0x0 0x0 0x0 0x0>;
+                               };
+                       };
+
+                       isa@1f,0 {
+                               #address-cells = <2>;
+                               #size-cells = <1>;
+                               compatible = "isa";
+                               ranges = <1 0 0 0 0 0x100>;
+
+                               rtc@70 {
+                                       compatible = "intel,ce4100-rtc", "motorola,mc146818";
+                                       interrupts = <8 3>;
+                                       interrupt-parent = <&ioapic1>;
+                                       ctrl-reg = <2>;
+                                       freq-reg = <0x26>;
+                                       reg = <1 0x70 2>;
+                               };
+                       };
+               };
+       };
+};
index ea6529e..5c0207b 100644 (file)
@@ -31,6 +31,7 @@
 #include <asm/apic.h>
 #include <asm/io_apic.h>
 #include <asm/mrst.h>
+#include <asm/mrst-vrtc.h>
 #include <asm/io.h>
 #include <asm/i8259.h>
 #include <asm/intel_scu_ipc.h>
@@ -268,6 +269,7 @@ void __init x86_mrst_early_setup(void)
 
        x86_platform.calibrate_tsc = mrst_calibrate_tsc;
        x86_platform.i8042_detect = mrst_i8042_detect;
+       x86_init.timers.wallclock_init = mrst_rtc_init;
        x86_init.pci.init = pci_mrst_init;
        x86_init.pci.fixup_irqs = x86_init_noop;
 
index 32cd7ed..04cf645 100644 (file)
@@ -100,22 +100,14 @@ int vrtc_set_mmss(unsigned long nowtime)
 
 void __init mrst_rtc_init(void)
 {
-       unsigned long rtc_paddr;
-       void __iomem *virt_base;
+       unsigned long vrtc_paddr = sfi_mrtc_array[0].phys_addr;
 
        sfi_table_parse(SFI_SIG_MRTC, NULL, NULL, sfi_parse_mrtc);
-       if (!sfi_mrtc_num)
+       if (!sfi_mrtc_num || !vrtc_paddr)
                return;
 
-       rtc_paddr = sfi_mrtc_array[0].phys_addr;
-
-       /* vRTC's register address may not be page aligned */
-       set_fixmap_nocache(FIX_LNW_VRTC, rtc_paddr);
-
-       virt_base = (void __iomem *)__fix_to_virt(FIX_LNW_VRTC);
-       virt_base += rtc_paddr & ~PAGE_MASK;
-       vrtc_virt_base = virt_base;
-
+       vrtc_virt_base = (void __iomem *)set_fixmap_offset_nocache(FIX_LNW_VRTC,
+                                                               vrtc_paddr);
        x86_platform.get_wallclock = vrtc_get_time;
        x86_platform.set_wallclock = vrtc_set_mmss;
 }
index e797428..c2a8cab 100644 (file)
@@ -1,4 +1,4 @@
 obj-$(CONFIG_OLPC)             += olpc.o
 obj-$(CONFIG_OLPC_XO1)         += olpc-xo1.o
-obj-$(CONFIG_OLPC_OPENFIRMWARE)        += olpc_ofw.o
-obj-$(CONFIG_OLPC_OPENFIRMWARE_DT)     += olpc_dt.o
+obj-$(CONFIG_OLPC)             += olpc_ofw.o
+obj-$(CONFIG_OF_PROMTREE)      += olpc_dt.o
index dab8746..044bda5 100644 (file)
@@ -140,8 +140,7 @@ void * __init prom_early_alloc(unsigned long size)
                 * wasted bootmem) and hand off chunks of it to callers.
                 */
                res = alloc_bootmem(chunk_size);
-               if (!res)
-                       return NULL;
+               BUG_ON(!res);
                prom_early_allocated += chunk_size;
                memset(res, 0, chunk_size);
                free_mem = chunk_size;
index df58e9c..a7b38d3 100644 (file)
@@ -1364,11 +1364,11 @@ 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 (pnode<<1) of the first uvhub
+                * 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.
                 */
-               bd2->header.base_dest_nodeid = uv_partition_base_pnode << 1;
+               bd2->header.base_dest_nodeid = UV_PNODE_TO_NASID(uv_partition_base_pnode);
                bd2->header.dest_subnodeid = 0x10; /* the LB */
                bd2->header.command = UV_NET_ENDPOINT_INTD;
                bd2->header.int_both = 1;
index 7b24460..374a05d 100644 (file)
@@ -131,7 +131,7 @@ arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
                       unsigned long mmr_offset, int limit)
 {
        const struct cpumask *eligible_cpu = cpumask_of(cpu);
-       struct irq_cfg *cfg = get_irq_chip_data(irq);
+       struct irq_cfg *cfg = irq_get_chip_data(irq);
        unsigned long mmr_value;
        struct uv_IO_APIC_route_entry *entry;
        int mmr_pnode, err;
@@ -148,7 +148,7 @@ arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
        else
                irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
 
-       set_irq_chip_and_handler_name(irq, &uv_irq_chip, handle_percpu_irq,
+       irq_set_chip_and_handler_name(irq, &uv_irq_chip, handle_percpu_irq,
                                      irq_name);
 
        mmr_value = 0;
index 6320376..fe4cf82 100644 (file)
@@ -569,11 +569,13 @@ out_unlock:
 static struct irqaction master_action = {
        .handler =      piix4_master_intr,
        .name =         "PIIX4-8259",
+       .flags =        IRQF_NO_THREAD,
 };
 
 static struct irqaction cascade_action = {
        .handler =      no_action,
        .name =         "cascade",
+       .flags =        IRQF_NO_THREAD,
 };
 
 static inline void set_piix4_virtual_irq_type(void)
@@ -606,7 +608,7 @@ static void __init visws_pre_intr_init(void)
                        chip = &cobalt_irq_type;
 
                if (chip)
-                       set_irq_chip(i, chip);
+                       irq_set_chip(i, chip);
        }
 
        setup_irq(CO_IRQ_8259, &master_action);
index 5b54892..e4343fe 100644 (file)
@@ -48,3 +48,11 @@ config XEN_DEBUG_FS
        help
          Enable statistics output and various tuning options in debugfs.
          Enabling this option may incur a significant performance overhead.
+
+config XEN_DEBUG
+       bool "Enable Xen debug checks"
+       depends on XEN
+       default n
+       help
+         Enable various WARN_ON checks in the Xen MMU code.
+         Enabling this option WILL incur a significant performance overhead.
index 50542ef..49dbd78 100644 (file)
@@ -1284,15 +1284,14 @@ static int init_hvm_pv_info(int *major, int *minor)
 
        xen_setup_features();
 
-       pv_info = xen_info;
-       pv_info.kernel_rpl = 0;
+       pv_info.name = "Xen HVM";
 
        xen_domain_type = XEN_HVM_DOMAIN;
 
        return 0;
 }
 
-void xen_hvm_init_shared_info(void)
+void __ref xen_hvm_init_shared_info(void)
 {
        int cpu;
        struct xen_add_to_physmap xatp;
@@ -1331,6 +1330,8 @@ static int __cpuinit xen_hvm_cpu_notify(struct notifier_block *self,
        switch (action) {
        case CPU_UP_PREPARE:
                per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
+               if (xen_have_vector_callback)
+                       xen_init_lock_cpu(cpu);
                break;
        default:
                break;
@@ -1355,6 +1356,7 @@ static void __init xen_hvm_guest_init(void)
 
        if (xen_feature(XENFEAT_hvm_callback_vector))
                xen_have_vector_callback = 1;
+       xen_hvm_smp_init();
        register_cpu_notifier(&xen_hvm_cpu_notifier);
        xen_unplug_emulated_devices();
        have_vcpu_info_placement = 0;
index 5e92b61..3f6f334 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/module.h>
 #include <linux/gfp.h>
 #include <linux/memblock.h>
+#include <linux/seq_file.h>
 
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
@@ -416,8 +417,12 @@ static pteval_t pte_pfn_to_mfn(pteval_t val)
        if (val & _PAGE_PRESENT) {
                unsigned long pfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT;
                pteval_t flags = val & PTE_FLAGS_MASK;
-               unsigned long mfn = pfn_to_mfn(pfn);
+               unsigned long mfn;
 
+               if (!xen_feature(XENFEAT_auto_translated_physmap))
+                       mfn = get_phys_to_machine(pfn);
+               else
+                       mfn = pfn;
                /*
                 * If there's no mfn for the pfn, then just create an
                 * empty non-present pte.  Unfortunately this loses
@@ -427,8 +432,18 @@ static pteval_t pte_pfn_to_mfn(pteval_t val)
                if (unlikely(mfn == INVALID_P2M_ENTRY)) {
                        mfn = 0;
                        flags = 0;
+               } else {
+                       /*
+                        * Paramount to do this test _after_ the
+                        * INVALID_P2M_ENTRY as INVALID_P2M_ENTRY &
+                        * IDENTITY_FRAME_BIT resolves to true.
+                        */
+                       mfn &= ~FOREIGN_FRAME_BIT;
+                       if (mfn & IDENTITY_FRAME_BIT) {
+                               mfn &= ~IDENTITY_FRAME_BIT;
+                               flags |= _PAGE_IOMAP;
+                       }
                }
-
                val = ((pteval_t)mfn << PAGE_SHIFT) | flags;
        }
 
@@ -532,6 +547,41 @@ pte_t xen_make_pte(pteval_t pte)
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte);
 
+#ifdef CONFIG_XEN_DEBUG
+pte_t xen_make_pte_debug(pteval_t pte)
+{
+       phys_addr_t addr = (pte & PTE_PFN_MASK);
+       phys_addr_t other_addr;
+       bool io_page = false;
+       pte_t _pte;
+
+       if (pte & _PAGE_IOMAP)
+               io_page = true;
+
+       _pte = xen_make_pte(pte);
+
+       if (!addr)
+               return _pte;
+
+       if (io_page &&
+           (xen_initial_domain() || addr >= ISA_END_ADDRESS)) {
+               other_addr = pfn_to_mfn(addr >> PAGE_SHIFT) << PAGE_SHIFT;
+               WARN(addr != other_addr,
+                       "0x%lx is using VM_IO, but it is 0x%lx!\n",
+                       (unsigned long)addr, (unsigned long)other_addr);
+       } else {
+               pteval_t iomap_set = (_pte.pte & PTE_FLAGS_MASK) & _PAGE_IOMAP;
+               other_addr = (_pte.pte & PTE_PFN_MASK);
+               WARN((addr == other_addr) && (!io_page) && (!iomap_set),
+                       "0x%lx is missing VM_IO (and wasn't fixed)!\n",
+                       (unsigned long)addr);
+       }
+
+       return _pte;
+}
+PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte_debug);
+#endif
+
 pgd_t xen_make_pgd(pgdval_t pgd)
 {
        pgd = pte_pfn_to_mfn(pgd);
@@ -986,10 +1036,9 @@ static void xen_pgd_pin(struct mm_struct *mm)
  */
 void xen_mm_pin_all(void)
 {
-       unsigned long flags;
        struct page *page;
 
-       spin_lock_irqsave(&pgd_lock, flags);
+       spin_lock(&pgd_lock);
 
        list_for_each_entry(page, &pgd_list, lru) {
                if (!PagePinned(page)) {
@@ -998,7 +1047,7 @@ void xen_mm_pin_all(void)
                }
        }
 
-       spin_unlock_irqrestore(&pgd_lock, flags);
+       spin_unlock(&pgd_lock);
 }
 
 /*
@@ -1099,10 +1148,9 @@ static void xen_pgd_unpin(struct mm_struct *mm)
  */
 void xen_mm_unpin_all(void)
 {
-       unsigned long flags;
        struct page *page;
 
-       spin_lock_irqsave(&pgd_lock, flags);
+       spin_lock(&pgd_lock);
 
        list_for_each_entry(page, &pgd_list, lru) {
                if (PageSavePinned(page)) {
@@ -1112,7 +1160,7 @@ void xen_mm_unpin_all(void)
                }
        }
 
-       spin_unlock_irqrestore(&pgd_lock, flags);
+       spin_unlock(&pgd_lock);
 }
 
 void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next)
@@ -1443,7 +1491,7 @@ static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
         * early_ioremap fixmap slot, make sure it is RO.
         */
        if (!is_early_ioremap_ptep(ptep) &&
-           pfn >= e820_table_start && pfn < e820_table_end)
+           pfn >= pgt_buf_start && pfn < pgt_buf_end)
                pte = pte_wrprotect(pte);
 
        return pte;
@@ -1942,6 +1990,9 @@ __init void xen_ident_map_ISA(void)
 
 static __init void xen_post_allocator_init(void)
 {
+#ifdef CONFIG_XEN_DEBUG
+       pv_mmu_ops.make_pte = PV_CALLEE_SAVE(xen_make_pte_debug);
+#endif
        pv_mmu_ops.set_pte = xen_set_pte;
        pv_mmu_ops.set_pmd = xen_set_pmd;
        pv_mmu_ops.set_pud = xen_set_pud;
@@ -2074,7 +2125,7 @@ static void xen_zap_pfn_range(unsigned long vaddr, unsigned int order,
                        in_frames[i] = virt_to_mfn(vaddr);
 
                MULTI_update_va_mapping(mcs.mc, vaddr, VOID_PTE, 0);
-               set_phys_to_machine(virt_to_pfn(vaddr), INVALID_P2M_ENTRY);
+               __set_phys_to_machine(virt_to_pfn(vaddr), INVALID_P2M_ENTRY);
 
                if (out_frames)
                        out_frames[i] = virt_to_pfn(vaddr);
@@ -2353,6 +2404,18 @@ EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range);
 
 #ifdef CONFIG_XEN_DEBUG_FS
 
+static int p2m_dump_open(struct inode *inode, struct file *filp)
+{
+       return single_open(filp, p2m_dump_show, NULL);
+}
+
+static const struct file_operations p2m_dump_fops = {
+       .open           = p2m_dump_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static struct dentry *d_mmu_debug;
 
 static int __init xen_mmu_debugfs(void)
@@ -2408,6 +2471,7 @@ static int __init xen_mmu_debugfs(void)
        debugfs_create_u32("prot_commit_batched", 0444, d_mmu_debug,
                           &mmu_stats.prot_commit_batched);
 
+       debugfs_create_file("p2m", 0600, d_mmu_debug, NULL, &p2m_dump_fops);
        return 0;
 }
 fs_initcall(xen_mmu_debugfs);
index ddc81a0..215a3ce 100644 (file)
  * P2M_PER_PAGE depends on the architecture, as a mfn is always
  * unsigned long (8 bytes on 64-bit, 4 bytes on 32), leading to
  * 512 and 1024 entries respectively. 
+ *
+ * In short, these structures contain the Machine Frame Number (MFN) of the PFN.
+ *
+ * However not all entries are filled with MFNs. Specifically for all other
+ * leaf entries, or for the top  root, or middle one, for which there is a void
+ * entry, we assume it is  "missing". So (for example)
+ *  pfn_to_mfn(0x90909090)=INVALID_P2M_ENTRY.
+ *
+ * We also have the possibility of setting 1-1 mappings on certain regions, so
+ * that:
+ *  pfn_to_mfn(0xc0000)=0xc0000
+ *
+ * The benefit of this is, that we can assume for non-RAM regions (think
+ * PCI BARs, or ACPI spaces), we can create mappings easily b/c we
+ * get the PFN value to match the MFN.
+ *
+ * For this to work efficiently we have one new page p2m_identity and
+ * allocate (via reserved_brk) any other pages we need to cover the sides
+ * (1GB or 4MB boundary violations). All entries in p2m_identity are set to
+ * INVALID_P2M_ENTRY type (Xen toolstack only recognizes that and MFNs,
+ * no other fancy value).
+ *
+ * On lookup we spot that the entry points to p2m_identity and return the
+ * identity value instead of dereferencing and returning INVALID_P2M_ENTRY.
+ * If the entry points to an allocated page, we just proceed as before and
+ * return the PFN.  If the PFN has IDENTITY_FRAME_BIT set we unmask that in
+ * appropriate functions (pfn_to_mfn).
+ *
+ * The reason for having the IDENTITY_FRAME_BIT instead of just returning the
+ * PFN is that we could find ourselves where pfn_to_mfn(pfn)==pfn for a
+ * non-identity pfn. To protect ourselves against we elect to set (and get) the
+ * IDENTITY_FRAME_BIT on all identity mapped PFNs.
+ *
+ * This simplistic diagram is used to explain the more subtle piece of code.
+ * There is also a digram of the P2M at the end that can help.
+ * Imagine your E820 looking as so:
+ *
+ *                    1GB                                           2GB
+ * /-------------------+---------\/----\         /----------\    /---+-----\
+ * | System RAM        | Sys RAM ||ACPI|         | reserved |    | Sys RAM |
+ * \-------------------+---------/\----/         \----------/    \---+-----/
+ *                               ^- 1029MB                       ^- 2001MB
+ *
+ * [1029MB = 263424 (0x40500), 2001MB = 512256 (0x7D100),
+ *  2048MB = 524288 (0x80000)]
+ *
+ * And dom0_mem=max:3GB,1GB is passed in to the guest, meaning memory past 1GB
+ * is actually not present (would have to kick the balloon driver to put it in).
+ *
+ * When we are told to set the PFNs for identity mapping (see patch: "xen/setup:
+ * Set identity mapping for non-RAM E820 and E820 gaps.") we pass in the start
+ * of the PFN and the end PFN (263424 and 512256 respectively). The first step
+ * is to reserve_brk a top leaf page if the p2m[1] is missing. The top leaf page
+ * covers 512^2 of page estate (1GB) and in case the start or end PFN is not
+ * aligned on 512^2*PAGE_SIZE (1GB) we loop on aligned 1GB PFNs from start pfn
+ * to end pfn.  We reserve_brk top leaf pages if they are missing (means they
+ * point to p2m_mid_missing).
+ *
+ * With the E820 example above, 263424 is not 1GB aligned so we allocate a
+ * reserve_brk page which will cover the PFNs estate from 0x40000 to 0x80000.
+ * Each entry in the allocate page is "missing" (points to p2m_missing).
+ *
+ * Next stage is to determine if we need to do a more granular boundary check
+ * on the 4MB (or 2MB depending on architecture) off the start and end pfn's.
+ * We check if the start pfn and end pfn violate that boundary check, and if
+ * so reserve_brk a middle (p2m[x][y]) leaf page. This way we have a much finer
+ * granularity of setting which PFNs are missing and which ones are identity.
+ * In our example 263424 and 512256 both fail the check so we reserve_brk two
+ * pages. Populate them with INVALID_P2M_ENTRY (so they both have "missing"
+ * values) and assign them to p2m[1][2] and p2m[1][488] respectively.
+ *
+ * At this point we would at minimum reserve_brk one page, but could be up to
+ * three. Each call to set_phys_range_identity has at maximum a three page
+ * cost. If we were to query the P2M at this stage, all those entries from
+ * start PFN through end PFN (so 1029MB -> 2001MB) would return
+ * INVALID_P2M_ENTRY ("missing").
+ *
+ * The next step is to walk from the start pfn to the end pfn setting
+ * the IDENTITY_FRAME_BIT on each PFN. This is done in set_phys_range_identity.
+ * If we find that the middle leaf is pointing to p2m_missing we can swap it
+ * over to p2m_identity - this way covering 4MB (or 2MB) PFN space.  At this
+ * point we do not need to worry about boundary aligment (so no need to
+ * reserve_brk a middle page, figure out which PFNs are "missing" and which
+ * ones are identity), as that has been done earlier.  If we find that the
+ * middle leaf is not occupied by p2m_identity or p2m_missing, we dereference
+ * that page (which covers 512 PFNs) and set the appropriate PFN with
+ * IDENTITY_FRAME_BIT. In our example 263424 and 512256 end up there, and we
+ * set from p2m[1][2][256->511] and p2m[1][488][0->256] with
+ * IDENTITY_FRAME_BIT set.
+ *
+ * All other regions that are void (or not filled) either point to p2m_missing
+ * (considered missing) or have the default value of INVALID_P2M_ENTRY (also
+ * considered missing). In our case, p2m[1][2][0->255] and p2m[1][488][257->511]
+ * contain the INVALID_P2M_ENTRY value and are considered "missing."
+ *
+ * This is what the p2m ends up looking (for the E820 above) with this
+ * fabulous drawing:
+ *
+ *    p2m         /--------------\
+ *  /-----\       | &mfn_list[0],|                           /-----------------\
+ *  |  0  |------>| &mfn_list[1],|    /---------------\      | ~0, ~0, ..      |
+ *  |-----|       |  ..., ~0, ~0 |    | ~0, ~0, [x]---+----->| IDENTITY [@256] |
+ *  |  1  |---\   \--------------/    | [p2m_identity]+\     | IDENTITY [@257] |
+ *  |-----|    \                      | [p2m_identity]+\\    | ....            |
+ *  |  2  |--\  \-------------------->|  ...          | \\   \----------------/
+ *  |-----|   \                       \---------------/  \\
+ *  |  3  |\   \                                          \\  p2m_identity
+ *  |-----| \   \-------------------->/---------------\   /-----------------\
+ *  | ..  +->+                        | [p2m_identity]+-->| ~0, ~0, ~0, ... |
+ *  \-----/ /                         | [p2m_identity]+-->| ..., ~0         |
+ *         / /---------------\        | ....          |   \-----------------/
+ *        /  | IDENTITY[@0]  |      /-+-[x], ~0, ~0.. |
+ *       /   | IDENTITY[@256]|<----/  \---------------/
+ *      /    | ~0, ~0, ....  |
+ *     |     \---------------/
+ *     |
+ *     p2m_missing             p2m_missing
+ * /------------------\     /------------\
+ * | [p2m_mid_missing]+---->| ~0, ~0, ~0 |
+ * | [p2m_mid_missing]+---->| ..., ~0    |
+ * \------------------/     \------------/
+ *
+ * where ~0 is INVALID_P2M_ENTRY. IDENTITY is (PFN | IDENTITY_BIT)
  */
 
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/hash.h>
 #include <linux/sched.h>
+#include <linux/seq_file.h>
 
 #include <asm/cache.h>
 #include <asm/setup.h>
@@ -59,9 +183,15 @@ static RESERVE_BRK_ARRAY(unsigned long **, p2m_top, P2M_TOP_PER_PAGE);
 static RESERVE_BRK_ARRAY(unsigned long, p2m_top_mfn, P2M_TOP_PER_PAGE);
 static RESERVE_BRK_ARRAY(unsigned long *, p2m_top_mfn_p, P2M_TOP_PER_PAGE);
 
+static RESERVE_BRK_ARRAY(unsigned long, p2m_identity, P2M_PER_PAGE);
+
 RESERVE_BRK(p2m_mid, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID_PER_PAGE)));
 RESERVE_BRK(p2m_mid_mfn, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID_PER_PAGE)));
 
+/* We might hit two boundary violations at the start and end, at max each
+ * boundary violation will require three middle nodes. */
+RESERVE_BRK(p2m_mid_identity, PAGE_SIZE * 2 * 3);
+
 static inline unsigned p2m_top_index(unsigned long pfn)
 {
        BUG_ON(pfn >= MAX_P2M_PFN);
@@ -136,7 +266,7 @@ static void p2m_init(unsigned long *p2m)
  * - After resume we're called from within stop_machine, but the mfn
  *   tree should alreay be completely allocated.
  */
-void xen_build_mfn_list_list(void)
+void __ref xen_build_mfn_list_list(void)
 {
        unsigned long pfn;
 
@@ -221,6 +351,9 @@ void __init xen_build_dynamic_phys_to_machine(void)
        p2m_top = extend_brk(PAGE_SIZE, PAGE_SIZE);
        p2m_top_init(p2m_top);
 
+       p2m_identity = extend_brk(PAGE_SIZE, PAGE_SIZE);
+       p2m_init(p2m_identity);
+
        /*
         * The domain builder gives us a pre-constructed p2m array in
         * mfn_list for all the pages initially given to us, so we just
@@ -241,21 +374,15 @@ void __init xen_build_dynamic_phys_to_machine(void)
                 * As long as the mfn_list has enough entries to completely
                 * fill a p2m page, pointing into the array is ok. But if
                 * not the entries beyond the last pfn will be undefined.
-                * And guessing that the 'what-ever-there-is' does not take it
-                * too kindly when changing it to invalid markers, a new page
-                * is allocated, initialized and filled with the valid part.
                 */
                if (unlikely(pfn + P2M_PER_PAGE > max_pfn)) {
                        unsigned long p2midx;
-                       unsigned long *p2m = extend_brk(PAGE_SIZE, PAGE_SIZE);
-                       p2m_init(p2m);
-
-                       for (p2midx = 0; pfn + p2midx < max_pfn; p2midx++) {
-                               p2m[p2midx] = mfn_list[pfn + p2midx];
-                       }
-                       p2m_top[topidx][mididx] = p2m;
-               } else
-                       p2m_top[topidx][mididx] = &mfn_list[pfn];
+
+                       p2midx = max_pfn % P2M_PER_PAGE;
+                       for ( ; p2midx < P2M_PER_PAGE; p2midx++)
+                               mfn_list[pfn + p2midx] = INVALID_P2M_ENTRY;
+               }
+               p2m_top[topidx][mididx] = &mfn_list[pfn];
        }
 
        m2p_override_init();
@@ -272,6 +399,14 @@ unsigned long get_phys_to_machine(unsigned long pfn)
        mididx = p2m_mid_index(pfn);
        idx = p2m_index(pfn);
 
+       /*
+        * The INVALID_P2M_ENTRY is filled in both p2m_*identity
+        * and in p2m_*missing, so returning the INVALID_P2M_ENTRY
+        * would be wrong.
+        */
+       if (p2m_top[topidx][mididx] == p2m_identity)
+               return IDENTITY_FRAME(pfn);
+
        return p2m_top[topidx][mididx][idx];
 }
 EXPORT_SYMBOL_GPL(get_phys_to_machine);
@@ -341,9 +476,11 @@ static bool alloc_p2m(unsigned long pfn)
                        p2m_top_mfn_p[topidx] = mid_mfn;
        }
 
-       if (p2m_top[topidx][mididx] == p2m_missing) {
+       if (p2m_top[topidx][mididx] == p2m_identity ||
+           p2m_top[topidx][mididx] == p2m_missing) {
                /* p2m leaf page is missing */
                unsigned long *p2m;
+               unsigned long *p2m_orig = p2m_top[topidx][mididx];
 
                p2m = alloc_p2m_page();
                if (!p2m)
@@ -351,7 +488,7 @@ static bool alloc_p2m(unsigned long pfn)
 
                p2m_init(p2m);
 
-               if (cmpxchg(&mid[mididx], p2m_missing, p2m) != p2m_missing)
+               if (cmpxchg(&mid[mididx], p2m_orig, p2m) != p2m_orig)
                        free_p2m_page(p2m);
                else
                        mid_mfn[mididx] = virt_to_mfn(p2m);
@@ -360,11 +497,91 @@ static bool alloc_p2m(unsigned long pfn)
        return true;
 }
 
+bool __early_alloc_p2m(unsigned long pfn)
+{
+       unsigned topidx, mididx, idx;
+
+       topidx = p2m_top_index(pfn);
+       mididx = p2m_mid_index(pfn);
+       idx = p2m_index(pfn);
+
+       /* Pfff.. No boundary cross-over, lets get out. */
+       if (!idx)
+               return false;
+
+       WARN(p2m_top[topidx][mididx] == p2m_identity,
+               "P2M[%d][%d] == IDENTITY, should be MISSING (or alloced)!\n",
+               topidx, mididx);
+
+       /*
+        * Could be done by xen_build_dynamic_phys_to_machine..
+        */
+       if (p2m_top[topidx][mididx] != p2m_missing)
+               return false;
+
+       /* Boundary cross-over for the edges: */
+       if (idx) {
+               unsigned long *p2m = extend_brk(PAGE_SIZE, PAGE_SIZE);
+
+               p2m_init(p2m);
+
+               p2m_top[topidx][mididx] = p2m;
+
+       }
+       return idx != 0;
+}
+unsigned long set_phys_range_identity(unsigned long pfn_s,
+                                     unsigned long pfn_e)
+{
+       unsigned long pfn;
+
+       if (unlikely(pfn_s >= MAX_P2M_PFN || pfn_e >= MAX_P2M_PFN))
+               return 0;
+
+       if (unlikely(xen_feature(XENFEAT_auto_translated_physmap)))
+               return pfn_e - pfn_s;
+
+       if (pfn_s > pfn_e)
+               return 0;
+
+       for (pfn = (pfn_s & ~(P2M_MID_PER_PAGE * P2M_PER_PAGE - 1));
+               pfn < ALIGN(pfn_e, (P2M_MID_PER_PAGE * P2M_PER_PAGE));
+               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);
+
+                       p2m_mid_init(mid);
+
+                       p2m_top[topidx] = mid;
+               }
+       }
+
+       __early_alloc_p2m(pfn_s);
+       __early_alloc_p2m(pfn_e);
+
+       for (pfn = pfn_s; pfn < pfn_e; pfn++)
+               if (!__set_phys_to_machine(pfn, IDENTITY_FRAME(pfn)))
+                       break;
+
+       if (!WARN((pfn - pfn_s) != (pfn_e - pfn_s),
+               "Identity mapping failed. We are %ld short of 1-1 mappings!\n",
+               (pfn_e - pfn_s) - (pfn - pfn_s)))
+               printk(KERN_DEBUG "1-1 mapping on %lx->%lx\n", pfn_s, pfn);
+
+       return pfn - pfn_s;
+}
+
 /* Try to install p2m mapping; fail if intermediate bits missing */
 bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
 {
        unsigned topidx, mididx, idx;
 
+       if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
+               BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
+               return true;
+       }
        if (unlikely(pfn >= MAX_P2M_PFN)) {
                BUG_ON(mfn != INVALID_P2M_ENTRY);
                return true;
@@ -374,6 +591,21 @@ bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
        mididx = p2m_mid_index(pfn);
        idx = p2m_index(pfn);
 
+       /* For sparse holes were the p2m leaf has real PFN along with
+        * PCI holes, stick in the PFN as the MFN value.
+        */
+       if (mfn != INVALID_P2M_ENTRY && (mfn & IDENTITY_FRAME_BIT)) {
+               if (p2m_top[topidx][mididx] == p2m_identity)
+                       return true;
+
+               /* Swap over from MISSING to IDENTITY if needed. */
+               if (p2m_top[topidx][mididx] == p2m_missing) {
+                       WARN_ON(cmpxchg(&p2m_top[topidx][mididx], p2m_missing,
+                               p2m_identity) != p2m_missing);
+                       return true;
+               }
+       }
+
        if (p2m_top[topidx][mididx] == p2m_missing)
                return mfn == INVALID_P2M_ENTRY;
 
@@ -384,11 +616,6 @@ bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
 
 bool set_phys_to_machine(unsigned long pfn, unsigned long mfn)
 {
-       if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
-               BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
-               return true;
-       }
-
        if (unlikely(!__set_phys_to_machine(pfn, mfn)))  {
                if (!alloc_p2m(pfn))
                        return false;
@@ -427,7 +654,7 @@ int m2p_add_override(unsigned long mfn, struct page *page)
 {
        unsigned long flags;
        unsigned long pfn;
-       unsigned long address;
+       unsigned long uninitialized_var(address);
        unsigned level;
        pte_t *ptep = NULL;
 
@@ -461,7 +688,7 @@ int m2p_remove_override(struct page *page)
        unsigned long flags;
        unsigned long mfn;
        unsigned long pfn;
-       unsigned long address;
+       unsigned long uninitialized_var(address);
        unsigned level;
        pte_t *ptep = NULL;
 
@@ -526,3 +753,80 @@ unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn)
        return ret;
 }
 EXPORT_SYMBOL_GPL(m2p_find_override_pfn);
+
+#ifdef CONFIG_XEN_DEBUG_FS
+
+int p2m_dump_show(struct seq_file *m, void *v)
+{
+       static const char * const level_name[] = { "top", "middle",
+                                               "entry", "abnormal" };
+       static const char * const type_name[] = { "identity", "missing",
+                                               "pfn", "abnormal"};
+#define TYPE_IDENTITY 0
+#define TYPE_MISSING 1
+#define TYPE_PFN 2
+#define TYPE_UNKNOWN 3
+       unsigned long pfn, prev_pfn_type = 0, prev_pfn_level = 0;
+       unsigned int uninitialized_var(prev_level);
+       unsigned int uninitialized_var(prev_type);
+
+       if (!p2m_top)
+               return 0;
+
+       for (pfn = 0; pfn < MAX_DOMAIN_PAGES; pfn++) {
+               unsigned topidx = p2m_top_index(pfn);
+               unsigned mididx = p2m_mid_index(pfn);
+               unsigned idx = p2m_index(pfn);
+               unsigned lvl, type;
+
+               lvl = 4;
+               type = TYPE_UNKNOWN;
+               if (p2m_top[topidx] == p2m_mid_missing) {
+                       lvl = 0; type = TYPE_MISSING;
+               } else if (p2m_top[topidx] == NULL) {
+                       lvl = 0; type = TYPE_UNKNOWN;
+               } else if (p2m_top[topidx][mididx] == NULL) {
+                       lvl = 1; type = TYPE_UNKNOWN;
+               } else if (p2m_top[topidx][mididx] == p2m_identity) {
+                       lvl = 1; type = TYPE_IDENTITY;
+               } else if (p2m_top[topidx][mididx] == p2m_missing) {
+                       lvl = 1; type = TYPE_MISSING;
+               } else if (p2m_top[topidx][mididx][idx] == 0) {
+                       lvl = 2; type = TYPE_UNKNOWN;
+               } else if (p2m_top[topidx][mididx][idx] == IDENTITY_FRAME(pfn)) {
+                       lvl = 2; type = TYPE_IDENTITY;
+               } else if (p2m_top[topidx][mididx][idx] == INVALID_P2M_ENTRY) {
+                       lvl = 2; type = TYPE_MISSING;
+               } else if (p2m_top[topidx][mididx][idx] == pfn) {
+                       lvl = 2; type = TYPE_PFN;
+               } else if (p2m_top[topidx][mididx][idx] != pfn) {
+                       lvl = 2; type = TYPE_PFN;
+               }
+               if (pfn == 0) {
+                       prev_level = lvl;
+                       prev_type = type;
+               }
+               if (pfn == MAX_DOMAIN_PAGES-1) {
+                       lvl = 3;
+                       type = TYPE_UNKNOWN;
+               }
+               if (prev_type != type) {
+                       seq_printf(m, " [0x%lx->0x%lx] %s\n",
+                               prev_pfn_type, pfn, type_name[prev_type]);
+                       prev_pfn_type = pfn;
+                       prev_type = type;
+               }
+               if (prev_level != lvl) {
+                       seq_printf(m, " [0x%lx->0x%lx] level %s\n",
+                               prev_pfn_level, pfn, level_name[prev_level]);
+                       prev_pfn_level = pfn;
+                       prev_level = lvl;
+               }
+       }
+       return 0;
+#undef TYPE_IDENTITY
+#undef TYPE_MISSING
+#undef TYPE_PFN
+#undef TYPE_UNKNOWN
+}
+#endif
index b5a7f92..fa0269a 100644 (file)
@@ -52,6 +52,8 @@ phys_addr_t xen_extra_mem_start, xen_extra_mem_size;
 
 static __init void xen_add_extra_mem(unsigned long pages)
 {
+       unsigned long pfn;
+
        u64 size = (u64)pages * PAGE_SIZE;
        u64 extra_start = xen_extra_mem_start + xen_extra_mem_size;
 
@@ -66,6 +68,9 @@ static __init void xen_add_extra_mem(unsigned long pages)
        xen_extra_mem_size += size;
 
        xen_max_p2m_pfn = PFN_DOWN(extra_start + size);
+
+       for (pfn = PFN_DOWN(extra_start); pfn <= xen_max_p2m_pfn; pfn++)
+               __set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
 }
 
 static unsigned long __init xen_release_chunk(phys_addr_t start_addr,
@@ -104,7 +109,7 @@ static unsigned long __init xen_release_chunk(phys_addr_t start_addr,
                WARN(ret != 1, "Failed to release memory %lx-%lx err=%d\n",
                     start, end, ret);
                if (ret == 1) {
-                       set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
+                       __set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
                        len++;
                }
        }
@@ -138,12 +143,55 @@ static unsigned long __init xen_return_unused_memory(unsigned long max_pfn,
        return released;
 }
 
+static unsigned long __init xen_set_identity(const struct e820entry *list,
+                                            ssize_t map_size)
+{
+       phys_addr_t last = xen_initial_domain() ? 0 : ISA_END_ADDRESS;
+       phys_addr_t start_pci = last;
+       const struct e820entry *entry;
+       unsigned long identity = 0;
+       int i;
+
+       for (i = 0, entry = list; i < map_size; i++, entry++) {
+               phys_addr_t start = entry->addr;
+               phys_addr_t end = start + entry->size;
+
+               if (start < last)
+                       start = last;
+
+               if (end <= start)
+                       continue;
+
+               /* Skip over the 1MB region. */
+               if (last > end)
+                       continue;
+
+               if (entry->type == E820_RAM) {
+                       if (start > start_pci)
+                               identity += set_phys_range_identity(
+                                               PFN_UP(start_pci), PFN_DOWN(start));
+
+                       /* Without saving 'last' we would gooble RAM too
+                        * at the end of the loop. */
+                       last = end;
+                       start_pci = end;
+                       continue;
+               }
+               start_pci = min(start, start_pci);
+               last = end;
+       }
+       if (last > start_pci)
+               identity += set_phys_range_identity(
+                                       PFN_UP(start_pci), PFN_DOWN(last));
+       return identity;
+}
 /**
  * machine_specific_memory_setup - Hook for machine specific memory setup.
  **/
 char * __init xen_memory_setup(void)
 {
        static struct e820entry map[E820MAX] __initdata;
+       static struct e820entry map_raw[E820MAX] __initdata;
 
        unsigned long max_pfn = xen_start_info->nr_pages;
        unsigned long long mem_end;
@@ -151,6 +199,7 @@ char * __init xen_memory_setup(void)
        struct xen_memory_map memmap;
        unsigned long extra_pages = 0;
        unsigned long extra_limit;
+       unsigned long identity_pages = 0;
        int i;
        int op;
 
@@ -176,11 +225,17 @@ char * __init xen_memory_setup(void)
        }
        BUG_ON(rc);
 
+       memcpy(map_raw, map, sizeof(map));
        e820.nr_map = 0;
        xen_extra_mem_start = mem_end;
        for (i = 0; i < memmap.nr_entries; i++) {
-               unsigned long long end = map[i].addr + map[i].size;
+               unsigned long long end;
+
+               /* Guard against non-page aligned E820 entries. */
+               if (map[i].type == E820_RAM)
+                       map[i].size -= (map[i].size + map[i].addr) % PAGE_SIZE;
 
+               end = map[i].addr + map[i].size;
                if (map[i].type == E820_RAM && end > mem_end) {
                        /* RAM off the end - may be partially included */
                        u64 delta = min(map[i].size, end - mem_end);
@@ -189,6 +244,15 @@ char * __init xen_memory_setup(void)
                        end -= delta;
 
                        extra_pages += PFN_DOWN(delta);
+                       /*
+                        * Set RAM below 4GB that is not for us to be unusable.
+                        * This prevents "System RAM" address space from being
+                        * used as potential resource for I/O address (happens
+                        * when 'allocate_resource' is called).
+                        */
+                       if (delta &&
+                               (xen_initial_domain() && end < 0x100000000ULL))
+                               e820_add_region(end, delta, E820_UNUSABLE);
                }
 
                if (map[i].size > 0 && end > xen_extra_mem_start)
@@ -246,6 +310,13 @@ char * __init xen_memory_setup(void)
 
        xen_add_extra_mem(extra_pages);
 
+       /*
+        * Set P2M for all non-RAM pages and E820 gaps to be identity
+        * type PFNs. We supply it with the non-sanitized version
+        * of the E820.
+        */
+       identity_pages = xen_set_identity(map_raw, memmap.nr_entries);
+       printk(KERN_INFO "Set %ld page(s) to 1-1 mapping.\n", identity_pages);
        return "Xen";
 }
 
@@ -350,6 +421,7 @@ void __init xen_arch_setup(void)
        boot_cpu_data.hlt_works_ok = 1;
 #endif
        pm_idle = default_idle;
+       boot_option_idle_override = IDLE_HALT;
 
        fiddle_vdso();
 }
index 72a4c79..3061244 100644 (file)
@@ -509,3 +509,41 @@ void __init xen_smp_init(void)
        xen_fill_possible_map();
        xen_init_spinlocks();
 }
+
+static void __init xen_hvm_smp_prepare_cpus(unsigned int max_cpus)
+{
+       native_smp_prepare_cpus(max_cpus);
+       WARN_ON(xen_smp_intr_init(0));
+
+       if (!xen_have_vector_callback)
+               return;
+       xen_init_lock_cpu(0);
+       xen_init_spinlocks();
+}
+
+static int __cpuinit xen_hvm_cpu_up(unsigned int cpu)
+{
+       int rc;
+       rc = native_cpu_up(cpu);
+       WARN_ON (xen_smp_intr_init(cpu));
+       return rc;
+}
+
+static void xen_hvm_cpu_die(unsigned int cpu)
+{
+       unbind_from_irqhandler(per_cpu(xen_resched_irq, cpu), NULL);
+       unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu), NULL);
+       unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu), NULL);
+       unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu), NULL);
+       native_cpu_die(cpu);
+}
+
+void __init xen_hvm_smp_init(void)
+{
+       smp_ops.smp_prepare_cpus = xen_hvm_smp_prepare_cpus;
+       smp_ops.smp_send_reschedule = xen_smp_send_reschedule;
+       smp_ops.cpu_up = xen_hvm_cpu_up;
+       smp_ops.cpu_die = xen_hvm_cpu_die;
+       smp_ops.send_call_func_ipi = xen_smp_send_call_function_ipi;
+       smp_ops.send_call_func_single_ipi = xen_smp_send_call_function_single_ipi;
+}
index 9bbd63a..45329c8 100644 (file)
@@ -12,7 +12,7 @@
 #include "xen-ops.h"
 #include "mmu.h"
 
-void xen_pre_suspend(void)
+void xen_arch_pre_suspend(void)
 {
        xen_start_info->store_mfn = mfn_to_pfn(xen_start_info->store_mfn);
        xen_start_info->console.domU.mfn =
@@ -26,8 +26,9 @@ void xen_pre_suspend(void)
                BUG();
 }
 
-void xen_hvm_post_suspend(int suspend_cancelled)
+void xen_arch_hvm_post_suspend(int suspend_cancelled)
 {
+#ifdef CONFIG_XEN_PVHVM
        int cpu;
        xen_hvm_init_shared_info();
        xen_callback_vector();
@@ -37,9 +38,10 @@ void xen_hvm_post_suspend(int suspend_cancelled)
                        xen_setup_runstate_info(cpu);
                }
        }
+#endif
 }
 
-void xen_post_suspend(int suspend_cancelled)
+void xen_arch_post_suspend(int suspend_cancelled)
 {
        xen_build_mfn_list_list();
 
index 067759e..2e2d370 100644 (file)
@@ -397,7 +397,9 @@ void xen_setup_timer(int cpu)
                name = "<timer kasprintf failed>";
 
        irq = bind_virq_to_irqhandler(VIRQ_TIMER, cpu, xen_timer_interrupt,
-                                     IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING|IRQF_TIMER,
+                                     IRQF_DISABLED|IRQF_PERCPU|
+                                     IRQF_NOBALANCING|IRQF_TIMER|
+                                     IRQF_FORCE_RESUME,
                                      name, NULL);
 
        evt = &per_cpu(xen_clock_events, cpu);
index 1a5ff24..aaa7291 100644 (file)
@@ -28,9 +28,9 @@ ENTRY(startup_xen)
        __FINIT
 
 .pushsection .text
-       .align PAGE_SIZE_asm
+       .align PAGE_SIZE
 ENTRY(hypercall_page)
-       .skip PAGE_SIZE_asm
+       .skip PAGE_SIZE
 .popsection
 
        ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS,       .asciz "linux")
index 9d41bf9..3112f55 100644 (file)
@@ -64,10 +64,12 @@ void xen_setup_vcpu_info_placement(void);
 
 #ifdef CONFIG_SMP
 void xen_smp_init(void);
+void __init xen_hvm_smp_init(void);
 
 extern cpumask_var_t xen_cpu_initialized_map;
 #else
 static inline void xen_smp_init(void) {}
+static inline void xen_hvm_smp_init(void) {}
 #endif
 
 #ifdef CONFIG_PARAVIRT_SPINLOCKS
index e39edf5..249619e 100644 (file)
 #error "Please don't include <asm/rwsem.h> directly, use <linux/rwsem.h> instead."
 #endif
 
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <asm/atomic.h>
-#include <asm/system.h>
-
-/*
- * the semaphore definition
- */
-struct rw_semaphore {
-       signed long             count;
 #define RWSEM_UNLOCKED_VALUE           0x00000000
 #define RWSEM_ACTIVE_BIAS              0x00000001
 #define RWSEM_ACTIVE_MASK              0x0000ffff
 #define RWSEM_WAITING_BIAS             (-0x00010000)
 #define RWSEM_ACTIVE_READ_BIAS         RWSEM_ACTIVE_BIAS
 #define RWSEM_ACTIVE_WRITE_BIAS                (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
-       spinlock_t              wait_lock;
-       struct list_head        wait_list;
-};
-
-#define __RWSEM_INITIALIZER(name) \
-       { RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \
-         LIST_HEAD_INIT((name).wait_list) }
-
-#define DECLARE_RWSEM(name)            \
-       struct rw_semaphore name = __RWSEM_INITIALIZER(name)
-
-extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
-extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
-extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem);
-extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
-
-static inline void init_rwsem(struct rw_semaphore *sem)
-{
-       sem->count = RWSEM_UNLOCKED_VALUE;
-       spin_lock_init(&sem->wait_lock);
-       INIT_LIST_HEAD(&sem->wait_list);
-}
 
 /*
  * lock for reading
@@ -160,9 +128,4 @@ static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
        return atomic_add_return(delta, (atomic_t *)(&sem->count));
 }
 
-static inline int rwsem_is_locked(struct rw_semaphore *sem)
-{
-       return (sem->count != 0);
-}
-
 #endif /* _XTENSA_RWSEM_H */
index 19df764..f3e5eb4 100644 (file)
@@ -96,16 +96,12 @@ again:
                update_process_times(user_mode(get_irq_regs()));
 #endif
 
-               write_seqlock(&xtime_lock);
-
-               do_timer(1); /* Linux handler in kernel/timer.c */
+               xtime_update(1); /* Linux handler in kernel/time/timekeeping */
 
                /* Note that writing CCOMPARE clears the interrupt. */
 
                next += CCOUNT_PER_JIFFY;
                set_linux_timer(next);
-
-               write_sequnlock(&xtime_lock);
        }
 
        /* Allow platform to do something useful (Wdog). */
index 2f4002f..518dd42 100644 (file)
@@ -352,7 +352,7 @@ void blk_start_queue(struct request_queue *q)
        WARN_ON(!irqs_disabled());
 
        queue_flag_clear(QUEUE_FLAG_STOPPED, q);
-       __blk_run_queue(q);
+       __blk_run_queue(q, false);
 }
 EXPORT_SYMBOL(blk_start_queue);
 
@@ -403,13 +403,14 @@ EXPORT_SYMBOL(blk_sync_queue);
 /**
  * __blk_run_queue - run a single device queue
  * @q: The queue to run
+ * @force_kblockd: Don't run @q->request_fn directly.  Use kblockd.
  *
  * Description:
  *    See @blk_run_queue. This variant must be called with the queue lock
  *    held and interrupts disabled.
  *
  */
-void __blk_run_queue(struct request_queue *q)
+void __blk_run_queue(struct request_queue *q, bool force_kblockd)
 {
        blk_remove_plug(q);
 
@@ -423,7 +424,7 @@ void __blk_run_queue(struct request_queue *q)
         * Only recurse once to avoid overrunning the stack, let the unplug
         * handling reinvoke the handler shortly if we already got there.
         */
-       if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) {
+       if (!force_kblockd && !queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) {
                q->request_fn(q);
                queue_flag_clear(QUEUE_FLAG_REENTER, q);
        } else {
@@ -446,7 +447,7 @@ void blk_run_queue(struct request_queue *q)
        unsigned long flags;
 
        spin_lock_irqsave(q->queue_lock, flags);
-       __blk_run_queue(q);
+       __blk_run_queue(q, false);
        spin_unlock_irqrestore(q->queue_lock, flags);
 }
 EXPORT_SYMBOL(blk_run_queue);
@@ -1053,7 +1054,7 @@ void blk_insert_request(struct request_queue *q, struct request *rq,
 
        drive_stat_acct(rq, 1);
        __elv_add_request(q, rq, where, 0);
-       __blk_run_queue(q);
+       __blk_run_queue(q, false);
        spin_unlock_irqrestore(q->queue_lock, flags);
 }
 EXPORT_SYMBOL(blk_insert_request);
@@ -2610,13 +2611,6 @@ int kblockd_schedule_work(struct request_queue *q, struct work_struct *work)
 }
 EXPORT_SYMBOL(kblockd_schedule_work);
 
-int kblockd_schedule_delayed_work(struct request_queue *q,
-                       struct delayed_work *dwork, unsigned long delay)
-{
-       return queue_delayed_work(kblockd_workqueue, dwork, delay);
-}
-EXPORT_SYMBOL(kblockd_schedule_delayed_work);
-
 int __init blk_dev_init(void)
 {
        BUILD_BUG_ON(__REQ_NR_BITS > 8 *
index 54b123d..b27d020 100644 (file)
@@ -66,10 +66,12 @@ static void blk_flush_complete_seq_end_io(struct request_queue *q,
 
        /*
         * Moving a request silently to empty queue_head may stall the
-        * queue.  Kick the queue in those cases.
+        * queue.  Kick the queue in those cases.  This function is called
+        * from request completion path and calling directly into
+        * request_fn may confuse the driver.  Always use kblockd.
         */
        if (was_empty && next_rq)
-               __blk_run_queue(q);
+               __blk_run_queue(q, true);
 }
 
 static void pre_flush_end_io(struct request *rq, int error)
@@ -130,7 +132,7 @@ static struct request *queue_next_fseq(struct request_queue *q)
                BUG();
        }
 
-       elv_insert(q, rq, ELEVATOR_INSERT_FRONT);
+       elv_insert(q, rq, ELEVATOR_INSERT_REQUEUE);
        return rq;
 }
 
index 1a320d2..bd3e8df 100644 (file)
@@ -109,7 +109,6 @@ struct bio_batch
        atomic_t                done;
        unsigned long           flags;
        struct completion       *wait;
-       bio_end_io_t            *end_io;
 };
 
 static void bio_batch_end_io(struct bio *bio, int err)
@@ -122,17 +121,14 @@ static void bio_batch_end_io(struct bio *bio, int err)
                else
                        clear_bit(BIO_UPTODATE, &bb->flags);
        }
-       if (bb) {
-               if (bb->end_io)
-                       bb->end_io(bio, err);
-               atomic_inc(&bb->done);
-               complete(bb->wait);
-       }
+       if (bb)
+               if (atomic_dec_and_test(&bb->done))
+                       complete(bb->wait);
        bio_put(bio);
 }
 
 /**
- * blkdev_issue_zeroout generate number of zero filed write bios
+ * blkdev_issue_zeroout generate number of zero filed write bios
  * @bdev:      blockdev to issue
  * @sector:    start sector
  * @nr_sects:  number of sectors to write
@@ -150,13 +146,12 @@ int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
        int ret;
        struct bio *bio;
        struct bio_batch bb;
-       unsigned int sz, issued = 0;
+       unsigned int sz;
        DECLARE_COMPLETION_ONSTACK(wait);
 
-       atomic_set(&bb.done, 0);
+       atomic_set(&bb.done, 1);
        bb.flags = 1 << BIO_UPTODATE;
        bb.wait = &wait;
-       bb.end_io = NULL;
 
 submit:
        ret = 0;
@@ -185,12 +180,12 @@ submit:
                                break;
                }
                ret = 0;
-               issued++;
+               atomic_inc(&bb.done);
                submit_bio(WRITE, bio);
        }
 
        /* Wait for bios in-flight */
-       while (issued != atomic_read(&bb.done))
+       if (!atomic_dec_and_test(&bb.done))
                wait_for_completion(&wait);
 
        if (!test_bit(BIO_UPTODATE, &bb.flags))
index 381b09b..e36cc10 100644 (file)
@@ -20,6 +20,11 @@ static int throtl_quantum = 32;
 /* Throttling is performed over 100ms slice and after that slice is renewed */
 static unsigned long throtl_slice = HZ/10;     /* 100 ms */
 
+/* A workqueue to queue throttle related work */
+static struct workqueue_struct *kthrotld_workqueue;
+static void throtl_schedule_delayed_work(struct throtl_data *td,
+                               unsigned long delay);
+
 struct throtl_rb_root {
        struct rb_root rb;
        struct rb_node *left;
@@ -168,7 +173,15 @@ static struct throtl_grp * throtl_find_alloc_tg(struct throtl_data *td,
         * tree of blkg (instead of traversing through hash list all
         * the time.
         */
-       tg = tg_of_blkg(blkiocg_lookup_group(blkcg, key));
+
+       /*
+        * This is the common case when there are no blkio cgroups.
+        * Avoid lookup in this case
+        */
+       if (blkcg == &blkio_root_cgroup)
+               tg = &td->root_tg;
+       else
+               tg = tg_of_blkg(blkiocg_lookup_group(blkcg, key));
 
        /* Fill in device details for root group */
        if (tg && !tg->blkg.dev && bdi->dev && dev_name(bdi->dev)) {
@@ -337,10 +350,9 @@ static void throtl_schedule_next_dispatch(struct throtl_data *td)
        update_min_dispatch_time(st);
 
        if (time_before_eq(st->min_disptime, jiffies))
-               throtl_schedule_delayed_work(td->queue, 0);
+               throtl_schedule_delayed_work(td, 0);
        else
-               throtl_schedule_delayed_work(td->queue,
-                               (st->min_disptime - jiffies));
+               throtl_schedule_delayed_work(td, (st->min_disptime - jiffies));
 }
 
 static inline void
@@ -807,10 +819,10 @@ void blk_throtl_work(struct work_struct *work)
 }
 
 /* Call with queue lock held */
-void throtl_schedule_delayed_work(struct request_queue *q, unsigned long delay)
+static void
+throtl_schedule_delayed_work(struct throtl_data *td, unsigned long delay)
 {
 
-       struct throtl_data *td = q->td;
        struct delayed_work *dwork = &td->throtl_work;
 
        if (total_nr_queued(td) > 0) {
@@ -819,12 +831,11 @@ void throtl_schedule_delayed_work(struct request_queue *q, unsigned long delay)
                 * Cancel that and schedule a new one.
                 */
                __cancel_delayed_work(dwork);
-               kblockd_schedule_delayed_work(q, dwork, delay);
+               queue_delayed_work(kthrotld_workqueue, dwork, delay);
                throtl_log(td, "schedule work. delay=%lu jiffies=%lu",
                                delay, jiffies);
        }
 }
-EXPORT_SYMBOL(throtl_schedule_delayed_work);
 
 static void
 throtl_destroy_tg(struct throtl_data *td, struct throtl_grp *tg)
@@ -912,7 +923,7 @@ static void throtl_update_blkio_group_read_bps(void *key,
        smp_mb__after_atomic_inc();
 
        /* Schedule a work now to process the limit change */
-       throtl_schedule_delayed_work(td->queue, 0);
+       throtl_schedule_delayed_work(td, 0);
 }
 
 static void throtl_update_blkio_group_write_bps(void *key,
@@ -926,7 +937,7 @@ static void throtl_update_blkio_group_write_bps(void *key,
        smp_mb__before_atomic_inc();
        atomic_inc(&td->limits_changed);
        smp_mb__after_atomic_inc();
-       throtl_schedule_delayed_work(td->queue, 0);
+       throtl_schedule_delayed_work(td, 0);
 }
 
 static void throtl_update_blkio_group_read_iops(void *key,
@@ -940,7 +951,7 @@ static void throtl_update_blkio_group_read_iops(void *key,
        smp_mb__before_atomic_inc();
        atomic_inc(&td->limits_changed);
        smp_mb__after_atomic_inc();
-       throtl_schedule_delayed_work(td->queue, 0);
+       throtl_schedule_delayed_work(td, 0);
 }
 
 static void throtl_update_blkio_group_write_iops(void *key,
@@ -954,7 +965,7 @@ static void throtl_update_blkio_group_write_iops(void *key,
        smp_mb__before_atomic_inc();
        atomic_inc(&td->limits_changed);
        smp_mb__after_atomic_inc();
-       throtl_schedule_delayed_work(td->queue, 0);
+       throtl_schedule_delayed_work(td, 0);
 }
 
 void throtl_shutdown_timer_wq(struct request_queue *q)
@@ -1127,6 +1138,10 @@ void blk_throtl_exit(struct request_queue *q)
 
 static int __init throtl_init(void)
 {
+       kthrotld_workqueue = alloc_workqueue("kthrotld", WQ_MEM_RECLAIM, 0);
+       if (!kthrotld_workqueue)
+               panic("Failed to create kthrotld\n");
+
        blkio_policy_register(&blkio_policy_throtl);
        return 0;
 }
index 501ffdf..ea83a4f 100644 (file)
@@ -599,7 +599,7 @@ cfq_group_slice(struct cfq_data *cfqd, struct cfq_group *cfqg)
 }
 
 static inline unsigned
-cfq_scaled_group_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+cfq_scaled_cfqq_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
        unsigned slice = cfq_prio_to_slice(cfqd, cfqq);
        if (cfqd->cfq_latency) {
@@ -631,7 +631,7 @@ cfq_scaled_group_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 static inline void
 cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
-       unsigned slice = cfq_scaled_group_slice(cfqd, cfqq);
+       unsigned slice = cfq_scaled_cfqq_slice(cfqd, cfqq);
 
        cfqq->slice_start = jiffies;
        cfqq->slice_end = jiffies + slice;
@@ -1671,7 +1671,7 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
         */
        if (timed_out) {
                if (cfq_cfqq_slice_new(cfqq))
-                       cfqq->slice_resid = cfq_scaled_group_slice(cfqd, cfqq);
+                       cfqq->slice_resid = cfq_scaled_cfqq_slice(cfqd, cfqq);
                else
                        cfqq->slice_resid = cfqq->slice_end - jiffies;
                cfq_log_cfqq(cfqd, cfqq, "resid=%ld", cfqq->slice_resid);
@@ -3355,7 +3355,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                            cfqd->busy_queues > 1) {
                                cfq_del_timer(cfqd, cfqq);
                                cfq_clear_cfqq_wait_request(cfqq);
-                               __blk_run_queue(cfqd->queue);
+                               __blk_run_queue(cfqd->queue, false);
                        } else {
                                cfq_blkiocg_update_idle_time_stats(
                                                &cfqq->cfqg->blkg);
@@ -3370,7 +3370,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
                 * this new queue is RT and the current one is BE
                 */
                cfq_preempt_queue(cfqd, cfqq);
-               __blk_run_queue(cfqd->queue);
+               __blk_run_queue(cfqd->queue, false);
        }
 }
 
@@ -3432,6 +3432,10 @@ static bool cfq_should_wait_busy(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
        struct cfq_io_context *cic = cfqd->active_cic;
 
+       /* If the queue already has requests, don't wait */
+       if (!RB_EMPTY_ROOT(&cfqq->sort_list))
+               return false;
+
        /* If there are other queues in the group, don't wait */
        if (cfqq->cfqg->nr_cfqq > 1)
                return false;
@@ -3727,7 +3731,7 @@ static void cfq_kick_queue(struct work_struct *work)
        struct request_queue *q = cfqd->queue;
 
        spin_lock_irq(q->queue_lock);
-       __blk_run_queue(cfqd->queue);
+       __blk_run_queue(cfqd->queue, false);
        spin_unlock_irq(q->queue_lock);
 }
 
index 2569512..236e93c 100644 (file)
@@ -602,7 +602,7 @@ void elv_quiesce_start(struct request_queue *q)
         */
        elv_drain_elevator(q);
        while (q->rq.elvpriv) {
-               __blk_run_queue(q);
+               __blk_run_queue(q, false);
                spin_unlock_irq(q->queue_lock);
                msleep(10);
                spin_lock_irq(q->queue_lock);
@@ -651,7 +651,7 @@ void elv_insert(struct request_queue *q, struct request *rq, int where)
                 *   with anything.  There's no point in delaying queue
                 *   processing.
                 */
-               __blk_run_queue(q);
+               __blk_run_queue(q, false);
                break;
 
        case ELEVATOR_INSERT_SORT:
index 6a5b772..cbf1112 100644 (file)
@@ -1355,7 +1355,7 @@ int invalidate_partition(struct gendisk *disk, int partno)
        struct block_device *bdev = bdget_disk(disk, partno);
        if (bdev) {
                fsync_bdev(bdev);
-               res = __invalidate_device(bdev);
+               res = __invalidate_device(bdev, true);
                bdput(bdev);
        }
        return res;
index 9049d46..1124cd2 100644 (file)
@@ -294,9 +294,11 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
                        return -EINVAL;
                if (get_user(n, (int __user *) arg))
                        return -EFAULT;
-               if (!(mode & FMODE_EXCL) &&
-                   blkdev_get(bdev, mode | FMODE_EXCL, &bdev) < 0)
-                       return -EBUSY;
+               if (!(mode & FMODE_EXCL)) {
+                       bdgrab(bdev);
+                       if (blkdev_get(bdev, mode | FMODE_EXCL, &bdev) < 0)
+                               return -EBUSY;
+               }
                ret = set_blocksize(bdev, n);
                if (!(mode & FMODE_EXCL))
                        blkdev_put(bdev, mode | FMODE_EXCL);
index 54784bb..edc2586 100644 (file)
@@ -416,10 +416,15 @@ struct acpi_gpe_handler_info {
        u8 originally_enabled;  /* True if GPE was originally enabled */
 };
 
+struct acpi_gpe_notify_object {
+       struct acpi_namespace_node *node;
+       struct acpi_gpe_notify_object *next;
+};
+
 union acpi_gpe_dispatch_info {
        struct acpi_namespace_node *method_node;        /* Method node for this GPE level */
        struct acpi_gpe_handler_info *handler;  /* Installed GPE handler */
-       struct acpi_namespace_node *device_node;        /* Parent _PRW device for implicit notify */
+       struct acpi_gpe_notify_object device;   /* List of _PRW devices for implicit notify */
 };
 
 /*
index 14988a8..f472521 100644 (file)
@@ -457,6 +457,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
        acpi_status status;
        struct acpi_gpe_event_info *local_gpe_event_info;
        struct acpi_evaluate_info *info;
+       struct acpi_gpe_notify_object *notify_object;
 
        ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method);
 
@@ -508,10 +509,18 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
                 * from this thread -- because handlers may in turn run other
                 * control methods.
                 */
-               status =
-                   acpi_ev_queue_notify_request(local_gpe_event_info->dispatch.
-                                                device_node,
-                                                ACPI_NOTIFY_DEVICE_WAKE);
+               status = acpi_ev_queue_notify_request(
+                               local_gpe_event_info->dispatch.device.node,
+                               ACPI_NOTIFY_DEVICE_WAKE);
+
+               notify_object = local_gpe_event_info->dispatch.device.next;
+               while (ACPI_SUCCESS(status) && notify_object) {
+                       status = acpi_ev_queue_notify_request(
+                                       notify_object->node,
+                                       ACPI_NOTIFY_DEVICE_WAKE);
+                       notify_object = notify_object->next;
+               }
+
                break;
 
        case ACPI_GPE_DISPATCH_METHOD:
index e9562a7..52aaff3 100644 (file)
@@ -198,7 +198,9 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device,
        acpi_status status = AE_BAD_PARAMETER;
        struct acpi_gpe_event_info *gpe_event_info;
        struct acpi_namespace_node *device_node;
+       struct acpi_gpe_notify_object *notify_object;
        acpi_cpu_flags flags;
+       u8 gpe_dispatch_mask;
 
        ACPI_FUNCTION_TRACE(acpi_setup_gpe_for_wake);
 
@@ -212,37 +214,62 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device,
                return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
 
+       flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+       /* Ensure that we have a valid GPE number */
+
+       gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+       if (!gpe_event_info) {
+               goto unlock_and_exit;
+       }
+
+       if (wake_device == ACPI_ROOT_OBJECT) {
+               goto out;
+       }
+
+       /*
+        * If there is no method or handler for this GPE, then the
+        * wake_device will be notified whenever this GPE fires (aka
+        * "implicit notify") Note: The GPE is assumed to be
+        * level-triggered (for windows compatibility).
+        */
+       gpe_dispatch_mask = gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK;
+       if (gpe_dispatch_mask != ACPI_GPE_DISPATCH_NONE
+           && gpe_dispatch_mask != ACPI_GPE_DISPATCH_NOTIFY) {
+               goto out;
+       }
+
        /* Validate wake_device is of type Device */
 
        device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device);
        if (device_node->type != ACPI_TYPE_DEVICE) {
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
+               goto unlock_and_exit;
        }
 
-       flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+       if (gpe_dispatch_mask == ACPI_GPE_DISPATCH_NONE) {
+               gpe_event_info->flags = (ACPI_GPE_DISPATCH_NOTIFY |
+                                        ACPI_GPE_LEVEL_TRIGGERED);
+               gpe_event_info->dispatch.device.node = device_node;
+               gpe_event_info->dispatch.device.next = NULL;
+       } else {
+               /* There are multiple devices to notify implicitly. */
 
-       /* Ensure that we have a valid GPE number */
-
-       gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
-       if (gpe_event_info) {
-               /*
-                * If there is no method or handler for this GPE, then the
-                * wake_device will be notified whenever this GPE fires (aka
-                * "implicit notify") Note: The GPE is assumed to be
-                * level-triggered (for windows compatibility).
-                */
-               if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
-                   ACPI_GPE_DISPATCH_NONE) {
-                       gpe_event_info->flags =
-                           (ACPI_GPE_DISPATCH_NOTIFY |
-                            ACPI_GPE_LEVEL_TRIGGERED);
-                       gpe_event_info->dispatch.device_node = device_node;
+               notify_object = ACPI_ALLOCATE_ZEROED(sizeof(*notify_object));
+               if (!notify_object) {
+                       status = AE_NO_MEMORY;
+                       goto unlock_and_exit;
                }
 
-               gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
-               status = AE_OK;
+               notify_object->node = device_node;
+               notify_object->next = gpe_event_info->dispatch.device.next;
+               gpe_event_info->dispatch.device.next = notify_object;
        }
 
+ out:
+       gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
+       status = AE_OK;
+
+ unlock_and_exit:
        acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
        return_ACPI_STATUS(status);
 }
index 5df67f1..384f7ab 100644 (file)
@@ -26,7 +26,9 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf,
                        size_t count, loff_t *ppos)
 {
        static char *buf;
-       static int uncopied_bytes;
+       static u32 max_size;
+       static u32 uncopied_bytes;
+
        struct acpi_table_header table;
        acpi_status status;
 
@@ -37,19 +39,24 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf,
                if (copy_from_user(&table, user_buf,
                                   sizeof(struct acpi_table_header)))
                        return -EFAULT;
-               uncopied_bytes = table.length;
-               buf = kzalloc(uncopied_bytes, GFP_KERNEL);
+               uncopied_bytes = max_size = table.length;
+               buf = kzalloc(max_size, GFP_KERNEL);
                if (!buf)
                        return -ENOMEM;
        }
 
-       if (uncopied_bytes < count) {
-               kfree(buf);
+       if (buf == NULL)
+               return -EINVAL;
+
+       if ((*ppos > max_size) ||
+           (*ppos + count > max_size) ||
+           (*ppos + count < count) ||
+           (count > uncopied_bytes))
                return -EINVAL;
-       }
 
        if (copy_from_user(buf + (*ppos), user_buf, count)) {
                kfree(buf);
+               buf = NULL;
                return -EFAULT;
        }
 
@@ -59,6 +66,7 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf,
        if (!uncopied_bytes) {
                status = acpi_install_method(buf);
                kfree(buf);
+               buf = NULL;
                if (ACPI_FAILURE(status))
                        return -EINVAL;
                add_taint(TAINT_OVERRIDDEN_ACPI_TABLE);
index 5eb25eb..3b5c318 100644 (file)
@@ -274,7 +274,7 @@ acpi_table_parse_srat(enum acpi_srat_type id,
 
 int __init acpi_numa_init(void)
 {
-       int ret = 0;
+       int cnt = 0;
 
        /*
         * Should not limit number with cpu num that is from NR_CPUS or nr_cpus=
@@ -288,7 +288,7 @@ int __init acpi_numa_init(void)
                                     acpi_parse_x2apic_affinity, 0);
                acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
                                     acpi_parse_processor_affinity, 0);
-               ret = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
+               cnt = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
                                            acpi_parse_memory_affinity,
                                            NR_NODE_MEMBLKS);
        }
@@ -297,7 +297,10 @@ int __init acpi_numa_init(void)
        acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit);
 
        acpi_numa_arch_fixup();
-       return ret;
+
+       if (cnt <= 0)
+               return cnt ?: -ENOENT;
+       return 0;
 }
 
 int acpi_get_pxm(acpi_handle h)
index b093181..4a67530 100644 (file)
@@ -636,17 +636,21 @@ EXPORT_SYMBOL(acpi_os_write_port);
 acpi_status
 acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
 {
-       u32 dummy;
        void __iomem *virt_addr;
-       int size = width / 8, unmap = 0;
+       unsigned int size = width / 8;
+       bool unmap = false;
+       u32 dummy;
 
        rcu_read_lock();
        virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
-       rcu_read_unlock();
        if (!virt_addr) {
+               rcu_read_unlock();
                virt_addr = acpi_os_ioremap(phys_addr, size);
-               unmap = 1;
+               if (!virt_addr)
+                       return AE_BAD_ADDRESS;
+               unmap = true;
        }
+
        if (!value)
                value = &dummy;
 
@@ -666,6 +670,8 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
 
        if (unmap)
                iounmap(virt_addr);
+       else
+               rcu_read_unlock();
 
        return AE_OK;
 }
@@ -674,14 +680,17 @@ acpi_status
 acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
 {
        void __iomem *virt_addr;
-       int size = width / 8, unmap = 0;
+       unsigned int size = width / 8;
+       bool unmap = false;
 
        rcu_read_lock();
        virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
-       rcu_read_unlock();
        if (!virt_addr) {
+               rcu_read_unlock();
                virt_addr = acpi_os_ioremap(phys_addr, size);
-               unmap = 1;
+               if (!virt_addr)
+                       return AE_BAD_ADDRESS;
+               unmap = true;
        }
 
        switch (width) {
@@ -700,6 +709,8 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
 
        if (unmap)
                iounmap(virt_addr);
+       else
+               rcu_read_unlock();
 
        return AE_OK;
 }
@@ -1578,9 +1589,9 @@ acpi_status __init acpi_os_initialize(void)
 
 acpi_status __init acpi_os_initialize1(void)
 {
-       kacpid_wq = create_workqueue("kacpid");
-       kacpi_notify_wq = create_workqueue("kacpi_notify");
-       kacpi_hotplug_wq = create_workqueue("kacpi_hotplug");
+       kacpid_wq = alloc_workqueue("kacpid", 0, 1);
+       kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1);
+       kacpi_hotplug_wq = alloc_workqueue("kacpi_hotplug", 0, 1);
        BUG_ON(!kacpid_wq);
        BUG_ON(!kacpi_notify_wq);
        BUG_ON(!kacpi_hotplug_wq);
index 42d3d72..5af3479 100644 (file)
@@ -82,6 +82,11 @@ long acpi_is_video_device(struct acpi_device *device)
        if (!device)
                return 0;
 
+       /* Is this device able to support video switching ? */
+       if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) ||
+           ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy)))
+               video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
+
        /* Is this device able to retrieve a video ROM ? */
        if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy)))
                video_caps |= ACPI_VIDEO_ROM_AVAILABLE;
index ed65014..7bfbe40 100644 (file)
@@ -86,8 +86,12 @@ int __init acpi_wakeup_device_init(void)
                struct acpi_device *dev = container_of(node,
                                                       struct acpi_device,
                                                       wakeup_list);
-               if (device_can_wakeup(&dev->dev))
+               if (device_can_wakeup(&dev->dev)) {
+                       /* Button GPEs are supposed to be always enabled. */
+                       acpi_enable_gpe(dev->wakeup.gpe_device,
+                                       dev->wakeup.gpe_number);
                        device_set_wakeup_enable(&dev->dev, true);
+               }
        }
        mutex_unlock(&acpi_device_lock);
        return 0;
index 3288263..b8d96ce 100644 (file)
@@ -260,6 +260,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x1d02), board_ahci }, /* PBG AHCI */
        { PCI_VDEVICE(INTEL, 0x1d04), board_ahci }, /* PBG RAID */
        { PCI_VDEVICE(INTEL, 0x1d06), board_ahci }, /* PBG RAID */
+       { PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */
 
        /* JMicron 360/1/3/5/6, match class to avoid IDE function */
        { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -379,6 +380,8 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv },        /* 6145 */
        { PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv },        /* 6121 */
        { PCI_DEVICE(0x1b4b, 0x9123),
+         .class = PCI_CLASS_STORAGE_SATA_AHCI,
+         .class_mask = 0xffffff,
          .driver_data = board_ahci_yes_fbs },                  /* 88se9128 */
 
        /* Promise */
index a31fe96..d4e52e2 100644 (file)
@@ -4138,6 +4138,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
         * device and controller are SATA.
         */
        { "PIONEER DVD-RW  DVRTD08",    "1.00", ATA_HORKAGE_NOSETXFER },
+       { "PIONEER DVD-RW  DVR-212D",   "1.28", ATA_HORKAGE_NOSETXFER },
 
        /* End Marker */
        { }
index 5defc74..600f635 100644 (file)
@@ -1099,9 +1099,9 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
                struct request_queue *q = sdev->request_queue;
                void *buf;
 
-               /* set the min alignment and padding */
-               blk_queue_update_dma_alignment(sdev->request_queue,
-                                              ATA_DMA_PAD_SZ - 1);
+               sdev->sector_size = ATA_SECT_SIZE;
+
+               /* set DMA padding */
                blk_queue_update_dma_pad(sdev->request_queue,
                                         ATA_DMA_PAD_SZ - 1);
 
@@ -1115,13 +1115,25 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
 
                blk_queue_dma_drain(q, atapi_drain_needed, buf, ATAPI_MAX_DRAIN);
        } else {
-               /* ATA devices must be sector aligned */
                sdev->sector_size = ata_id_logical_sector_size(dev->id);
-               blk_queue_update_dma_alignment(sdev->request_queue,
-                                              sdev->sector_size - 1);
                sdev->manage_start_stop = 1;
        }
 
+       /*
+        * ata_pio_sectors() expects buffer for each sector to not cross
+        * page boundary.  Enforce it by requiring buffers to be sector
+        * aligned, which works iff sector_size is not larger than
+        * PAGE_SIZE.  ATAPI devices also need the alignment as
+        * IDENTIFY_PACKET is executed as ATA_PROT_PIO.
+        */
+       if (sdev->sector_size > PAGE_SIZE)
+               ata_dev_printk(dev, KERN_WARNING,
+                       "sector_size=%u > PAGE_SIZE, PIO may malfunction\n",
+                       sdev->sector_size);
+
+       blk_queue_update_dma_alignment(sdev->request_queue,
+                                      sdev->sector_size - 1);
+
        if (dev->flags & ATA_DFLAG_AN)
                set_bit(SDEV_EVT_MEDIA_CHANGE, sdev->supported_events);
 
index d7e57db..538ec38 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "pata_hpt366"
-#define DRV_VERSION    "0.6.9"
+#define DRV_VERSION    "0.6.10"
 
 struct hpt_clock {
        u8      xfer_mode;
@@ -160,8 +160,8 @@ static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr,
 
        while (list[i] != NULL) {
                if (!strcmp(list[i], model_num)) {
-                       printk(KERN_WARNING DRV_NAME ": %s is not supported for %s.\n",
-                               modestr, list[i]);
+                       pr_warning(DRV_NAME ": %s is not supported for %s.\n",
+                                  modestr, list[i]);
                        return 1;
                }
                i++;
index efdd18b..4c5b518 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "pata_hpt37x"
-#define DRV_VERSION    "0.6.18"
+#define DRV_VERSION    "0.6.22"
 
 struct hpt_clock {
        u8      xfer_speed;
@@ -229,8 +229,8 @@ static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr,
 
        while (list[i] != NULL) {
                if (!strcmp(list[i], model_num)) {
-                       printk(KERN_WARNING DRV_NAME ": %s is not supported for %s.\n",
-                               modestr, list[i]);
+                       pr_warning(DRV_NAME ": %s is not supported for %s.\n",
+                                  modestr, list[i]);
                        return 1;
                }
                i++;
@@ -642,7 +642,6 @@ static struct ata_port_operations hpt372_port_ops = {
 static struct ata_port_operations hpt374_fn1_port_ops = {
        .inherits       = &hpt372_port_ops,
        .cable_detect   = hpt374_fn1_cable_detect,
-       .prereset       = hpt37x_pre_reset,
 };
 
 /**
@@ -803,7 +802,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                .udma_mask = ATA_UDMA6,
                .port_ops = &hpt302_port_ops
        };
-       /* HPT374 - UDMA100, function 1 uses different prereset method */
+       /* HPT374 - UDMA100, function 1 uses different cable_detect method */
        static const struct ata_port_info info_hpt374_fn0 = {
                .flags = ATA_FLAG_SLAVE_POSS,
                .pio_mask = ATA_PIO4,
@@ -838,7 +837,8 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
        if (rc)
                return rc;
 
-       if (dev->device == PCI_DEVICE_ID_TTI_HPT366) {
+       switch (dev->device) {
+       case PCI_DEVICE_ID_TTI_HPT366:
                /* May be a later chip in disguise. Check */
                /* Older chips are in the HPT366 driver. Ignore them */
                if (rev < 3)
@@ -863,54 +863,50 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                        chip_table = &hpt372;
                        break;
                default:
-                       printk(KERN_ERR "pata_hpt37x: Unknown HPT366 subtype, "
+                       pr_err(DRV_NAME ": Unknown HPT366 subtype, "
                               "please report (%d).\n", rev);
                        return -ENODEV;
                }
-       } else {
-               switch (dev->device) {
-               case PCI_DEVICE_ID_TTI_HPT372:
-                       /* 372N if rev >= 2 */
-                       if (rev >= 2)
-                               return -ENODEV;
-                       ppi[0] = &info_hpt372;
-                       chip_table = &hpt372a;
-                       break;
-               case PCI_DEVICE_ID_TTI_HPT302:
-                       /* 302N if rev > 1 */
-                       if (rev > 1)
-                               return -ENODEV;
-                       ppi[0] = &info_hpt302;
-                       /* Check this */
-                       chip_table = &hpt302;
-                       break;
-               case PCI_DEVICE_ID_TTI_HPT371:
-                       if (rev > 1)
-                               return -ENODEV;
-                       ppi[0] = &info_hpt302;
-                       chip_table = &hpt371;
-                       /*
-                        * Single channel device, master is not present
-                        * but the BIOS (or us for non x86) must mark it
-                        * absent
-                        */
-                       pci_read_config_byte(dev, 0x50, &mcr1);
-                       mcr1 &= ~0x04;
-                       pci_write_config_byte(dev, 0x50, mcr1);
-                       break;
-               case PCI_DEVICE_ID_TTI_HPT374:
-                       chip_table = &hpt374;
-                       if (!(PCI_FUNC(dev->devfn) & 1))
-                               *ppi = &info_hpt374_fn0;
-                       else
-                               *ppi = &info_hpt374_fn1;
-                       break;
-               default:
-                       printk(KERN_ERR
-                              "pata_hpt37x: PCI table is bogus, please report (%d).\n",
-                              dev->device);
-                               return -ENODEV;
-               }
+               break;
+       case PCI_DEVICE_ID_TTI_HPT372:
+               /* 372N if rev >= 2 */
+               if (rev >= 2)
+                       return -ENODEV;
+               ppi[0] = &info_hpt372;
+               chip_table = &hpt372a;
+               break;
+       case PCI_DEVICE_ID_TTI_HPT302:
+               /* 302N if rev > 1 */
+               if (rev > 1)
+                       return -ENODEV;
+               ppi[0] = &info_hpt302;
+               /* Check this */
+               chip_table = &hpt302;
+               break;
+       case PCI_DEVICE_ID_TTI_HPT371:
+               if (rev > 1)
+                       return -ENODEV;
+               ppi[0] = &info_hpt302;
+               chip_table = &hpt371;
+               /*
+                * Single channel device, master is not present but the BIOS
+                * (or us for non x86) must mark it absent
+                */
+               pci_read_config_byte(dev, 0x50, &mcr1);
+               mcr1 &= ~0x04;
+               pci_write_config_byte(dev, 0x50, mcr1);
+               break;
+       case PCI_DEVICE_ID_TTI_HPT374:
+               chip_table = &hpt374;
+               if (!(PCI_FUNC(dev->devfn) & 1))
+                       *ppi = &info_hpt374_fn0;
+               else
+                       *ppi = &info_hpt374_fn1;
+               break;
+       default:
+               pr_err(DRV_NAME ": PCI table is bogus, please report (%d).\n",
+                      dev->device);
+               return -ENODEV;
        }
        /* Ok so this is a chip we support */
 
@@ -957,8 +953,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                u8 sr;
                u32 total = 0;
 
-               printk(KERN_WARNING
-                      "pata_hpt37x: BIOS has not set timing clocks.\n");
+               pr_warning(DRV_NAME ": BIOS has not set timing clocks.\n");
 
                /* This is the process the HPT371 BIOS is reported to use */
                for (i = 0; i < 128; i++) {
@@ -1014,7 +1009,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                                               (f_high << 16) | f_low | 0x100);
                }
                if (adjust == 8) {
-                       printk(KERN_ERR "pata_hpt37x: DPLL did not stabilize!\n");
+                       pr_err(DRV_NAME ": DPLL did not stabilize!\n");
                        return -ENODEV;
                }
                if (dpll == 3)
@@ -1022,8 +1017,8 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                else
                        private_data = (void *)hpt37x_timings_50;
 
-               printk(KERN_INFO "pata_hpt37x: bus clock %dMHz, using %dMHz DPLL.\n",
-                      MHz[clock_slot], MHz[dpll]);
+               pr_info(DRV_NAME ": bus clock %dMHz, using %dMHz DPLL.\n",
+                       MHz[clock_slot], MHz[dpll]);
        } else {
                private_data = (void *)chip_table->clocks[clock_slot];
                /*
@@ -1036,8 +1031,9 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
                        ppi[0] = &info_hpt370_33;
                if (clock_slot < 2 && ppi[0] == &info_hpt370a)
                        ppi[0] = &info_hpt370a_33;
-               printk(KERN_INFO "pata_hpt37x: %s using %dMHz bus clock.\n",
-                      chip_table->name, MHz[clock_slot]);
+
+               pr_info(DRV_NAME ": %s using %dMHz bus clock.\n",
+                       chip_table->name, MHz[clock_slot]);
        }
 
        /* Now kick off ATA set up */
index d2239bb..eca68ca 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "pata_hpt3x2n"
-#define DRV_VERSION    "0.3.13"
+#define DRV_VERSION    "0.3.14"
 
 enum {
        HPT_PCI_FAST    =       (1 << 31),
@@ -418,7 +418,7 @@ static int hpt3x2n_pci_clock(struct pci_dev *pdev)
                u16 sr;
                u32 total = 0;
 
-               printk(KERN_WARNING "pata_hpt3x2n: BIOS clock data not set.\n");
+               pr_warning(DRV_NAME ": BIOS clock data not set.\n");
 
                /* This is the process the HPT371 BIOS is reported to use */
                for (i = 0; i < 128; i++) {
@@ -528,8 +528,7 @@ hpt372n:
                ppi[0] = &info_hpt372n;
                break;
        default:
-               printk(KERN_ERR
-                      "pata_hpt3x2n: PCI table is bogus please report (%d).\n",
+               pr_err(DRV_NAME ": PCI table is bogus, please report (%d).\n",
                       dev->device);
                return -ENODEV;
        }
@@ -579,12 +578,11 @@ hpt372n:
                pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low);
        }
        if (adjust == 8) {
-               printk(KERN_ERR "pata_hpt3x2n: DPLL did not stabilize!\n");
+               pr_err(DRV_NAME ": DPLL did not stabilize!\n");
                return -ENODEV;
        }
 
-       printk(KERN_INFO "pata_hpt37x: bus clock %dMHz, using 66MHz DPLL.\n",
-              pci_mhz);
+       pr_info(DRV_NAME ": bus clock %dMHz, using 66MHz DPLL.\n", pci_mhz);
 
        /*
         * Set our private data up. We only need a few flags
index 8cc536e..d7d8026 100644 (file)
@@ -610,7 +610,7 @@ static struct scsi_host_template mpc52xx_ata_sht = {
 };
 
 static struct ata_port_operations mpc52xx_ata_port_ops = {
-       .inherits               = &ata_sff_port_ops,
+       .inherits               = &ata_bmdma_port_ops,
        .sff_dev_select         = mpc52xx_ata_dev_select,
        .set_piomode            = mpc52xx_ata_set_piomode,
        .set_dmamode            = mpc52xx_ata_set_dmamode,
index bca9cb8..487a547 100644 (file)
@@ -151,7 +151,7 @@ static int fetch_stats(struct atm_dev *dev,struct idt77105_stats __user *arg,int
        spin_unlock_irqrestore(&idt77105_priv_lock, flags);
        if (arg == NULL)
                return 0;
-       return copy_to_user(arg, &PRIV(dev)->stats,
+       return copy_to_user(arg, &stats,
                    sizeof(struct idt77105_stats)) ? -EFAULT : 0;
 }
 
index 73fb1c4..25ef1a4 100644 (file)
@@ -866,8 +866,9 @@ static int popen(struct atm_vcc *vcc)
        }
 
        skb = alloc_skb(sizeof(*header), GFP_ATOMIC);
-       if (!skb && net_ratelimit()) {
-               dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n");
+       if (!skb) {
+               if (net_ratelimit())
+                       dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n");
                return -ENOMEM;
        }
        header = (void *)skb_put(skb, sizeof(*header));
index 656493a..42615b4 100644 (file)
@@ -407,12 +407,15 @@ static int rpm_suspend(struct device *dev, int rpmflags)
                goto out;
        }
 
+       /* Maybe the parent is now able to suspend. */
        if (parent && !parent->power.ignore_children && !dev->power.irq_safe) {
-               spin_unlock_irq(&dev->power.lock);
+               spin_unlock(&dev->power.lock);
 
-               pm_request_idle(parent);
+               spin_lock(&parent->power.lock);
+               rpm_idle(parent, RPM_ASYNC);
+               spin_unlock(&parent->power.lock);
 
-               spin_lock_irq(&dev->power.lock);
+               spin_lock(&dev->power.lock);
        }
 
  out:
index d7f463d..40528ba 100644 (file)
@@ -39,4 +39,4 @@ obj-$(CONFIG_XEN_BLKDEV_FRONTEND)     += xen-blkfront.o
 obj-$(CONFIG_BLK_DEV_DRBD)     += drbd/
 obj-$(CONFIG_BLK_DEV_RBD)     += rbd.o
 
-swim_mod-objs  := swim.o swim_asm.o
+swim_mod-y     := swim.o swim_asm.o
index e76d997..06ea82c 100644 (file)
@@ -3,4 +3,4 @@
 #
 
 obj-$(CONFIG_ATA_OVER_ETH)     += aoe.o
-aoe-objs := aoeblk.o aoechr.o aoecmd.o aoedev.o aoemain.o aoenet.o
+aoe-y := aoeblk.o aoechr.o aoecmd.o aoedev.o aoemain.o aoenet.o
index 516d5bb..9279272 100644 (file)
@@ -2833,7 +2833,7 @@ static int cciss_revalidate(struct gendisk *disk)
        sector_t total_size;
        InquiryData_struct *inq_buff = NULL;
 
-       for (logvol = 0; logvol < CISS_MAX_LUN; logvol++) {
+       for (logvol = 0; logvol <= h->highest_lun; logvol++) {
                if (!h->drv[logvol])
                        continue;
                if (memcmp(h->drv[logvol]->LunID, drv->LunID,
index b9ba04f..77fc76f 100644 (file)
@@ -3281,7 +3281,7 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g,
                        struct block_device *bdev = opened_bdev[cnt];
                        if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
                                continue;
-                       __invalidate_device(bdev);
+                       __invalidate_device(bdev, true);
                }
                mutex_unlock(&open_lock);
        } else {
index 44e18c0..dbf31ec 100644 (file)
@@ -78,7 +78,6 @@
 
 #include <asm/uaccess.h>
 
-static DEFINE_MUTEX(loop_mutex);
 static LIST_HEAD(loop_devices);
 static DEFINE_MUTEX(loop_devices_mutex);
 
@@ -1501,11 +1500,9 @@ static int lo_open(struct block_device *bdev, fmode_t mode)
 {
        struct loop_device *lo = bdev->bd_disk->private_data;
 
-       mutex_lock(&loop_mutex);
        mutex_lock(&lo->lo_ctl_mutex);
        lo->lo_refcnt++;
        mutex_unlock(&lo->lo_ctl_mutex);
-       mutex_unlock(&loop_mutex);
 
        return 0;
 }
@@ -1515,7 +1512,6 @@ static int lo_release(struct gendisk *disk, fmode_t mode)
        struct loop_device *lo = disk->private_data;
        int err;
 
-       mutex_lock(&loop_mutex);
        mutex_lock(&lo->lo_ctl_mutex);
 
        if (--lo->lo_refcnt)
@@ -1540,7 +1536,6 @@ static int lo_release(struct gendisk *disk, fmode_t mode)
 out:
        mutex_unlock(&lo->lo_ctl_mutex);
 out_unlocked:
-       mutex_unlock(&loop_mutex);
        return 0;
 }
 
@@ -1641,6 +1636,9 @@ out:
 
 static void loop_free(struct loop_device *lo)
 {
+       if (!lo->lo_queue->queue_lock)
+               lo->lo_queue->queue_lock = &lo->lo_queue->__queue_lock;
+
        blk_cleanup_queue(lo->lo_queue);
        put_disk(lo->lo_disk);
        list_del(&lo->lo_list);
index a32fb41..e6fc716 100644 (file)
@@ -53,7 +53,6 @@
 #define DBG_BLKDEV      0x0100
 #define DBG_RX          0x0200
 #define DBG_TX          0x0400
-static DEFINE_MUTEX(nbd_mutex);
 static unsigned int debugflags;
 #endif /* NDEBUG */
 
@@ -718,11 +717,9 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
        dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n",
                        lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg);
 
-       mutex_lock(&nbd_mutex);
        mutex_lock(&lo->tx_lock);
        error = __nbd_ioctl(bdev, lo, cmd, arg);
        mutex_unlock(&lo->tx_lock);
-       mutex_unlock(&nbd_mutex);
 
        return error;
 }
index d7aa39e..9cb8668 100644 (file)
@@ -120,6 +120,10 @@ static DEFINE_SPINLOCK(minor_lock);
 #define EXTENDED (1<<EXT_SHIFT)
 #define VDEV_IS_EXTENDED(dev) ((dev)&(EXTENDED))
 #define BLKIF_MINOR_EXT(dev) ((dev)&(~EXTENDED))
+#define EMULATED_HD_DISK_MINOR_OFFSET (0)
+#define EMULATED_HD_DISK_NAME_OFFSET (EMULATED_HD_DISK_MINOR_OFFSET / 256)
+#define EMULATED_SD_DISK_MINOR_OFFSET (EMULATED_HD_DISK_MINOR_OFFSET + (4 * 16))
+#define EMULATED_SD_DISK_NAME_OFFSET (EMULATED_HD_DISK_NAME_OFFSET + 4)
 
 #define DEV_NAME       "xvd"   /* name in /dev */
 
@@ -281,7 +285,7 @@ static int blkif_queue_request(struct request *req)
        info->shadow[id].request = req;
 
        ring_req->id = id;
-       ring_req->sector_number = (blkif_sector_t)blk_rq_pos(req);
+       ring_req->u.rw.sector_number = (blkif_sector_t)blk_rq_pos(req);
        ring_req->handle = info->handle;
 
        ring_req->operation = rq_data_dir(req) ?
@@ -317,7 +321,7 @@ static int blkif_queue_request(struct request *req)
                                rq_data_dir(req) );
 
                info->shadow[id].frame[i] = mfn_to_pfn(buffer_mfn);
-               ring_req->seg[i] =
+               ring_req->u.rw.seg[i] =
                                (struct blkif_request_segment) {
                                        .gref       = ref,
                                        .first_sect = fsect,
@@ -434,6 +438,65 @@ static void xlvbd_flush(struct blkfront_info *info)
               info->feature_flush ? "enabled" : "disabled");
 }
 
+static int xen_translate_vdev(int vdevice, int *minor, unsigned int *offset)
+{
+       int major;
+       major = BLKIF_MAJOR(vdevice);
+       *minor = BLKIF_MINOR(vdevice);
+       switch (major) {
+               case XEN_IDE0_MAJOR:
+                       *offset = (*minor / 64) + EMULATED_HD_DISK_NAME_OFFSET;
+                       *minor = ((*minor / 64) * PARTS_PER_DISK) +
+                               EMULATED_HD_DISK_MINOR_OFFSET;
+                       break;
+               case XEN_IDE1_MAJOR:
+                       *offset = (*minor / 64) + 2 + EMULATED_HD_DISK_NAME_OFFSET;
+                       *minor = (((*minor / 64) + 2) * PARTS_PER_DISK) +
+                               EMULATED_HD_DISK_MINOR_OFFSET;
+                       break;
+               case XEN_SCSI_DISK0_MAJOR:
+                       *offset = (*minor / PARTS_PER_DISK) + EMULATED_SD_DISK_NAME_OFFSET;
+                       *minor = *minor + EMULATED_SD_DISK_MINOR_OFFSET;
+                       break;
+               case XEN_SCSI_DISK1_MAJOR:
+               case XEN_SCSI_DISK2_MAJOR:
+               case XEN_SCSI_DISK3_MAJOR:
+               case XEN_SCSI_DISK4_MAJOR:
+               case XEN_SCSI_DISK5_MAJOR:
+               case XEN_SCSI_DISK6_MAJOR:
+               case XEN_SCSI_DISK7_MAJOR:
+                       *offset = (*minor / PARTS_PER_DISK) + 
+                               ((major - XEN_SCSI_DISK1_MAJOR + 1) * 16) +
+                               EMULATED_SD_DISK_NAME_OFFSET;
+                       *minor = *minor +
+                               ((major - XEN_SCSI_DISK1_MAJOR + 1) * 16 * PARTS_PER_DISK) +
+                               EMULATED_SD_DISK_MINOR_OFFSET;
+                       break;
+               case XEN_SCSI_DISK8_MAJOR:
+               case XEN_SCSI_DISK9_MAJOR:
+               case XEN_SCSI_DISK10_MAJOR:
+               case XEN_SCSI_DISK11_MAJOR:
+               case XEN_SCSI_DISK12_MAJOR:
+               case XEN_SCSI_DISK13_MAJOR:
+               case XEN_SCSI_DISK14_MAJOR:
+               case XEN_SCSI_DISK15_MAJOR:
+                       *offset = (*minor / PARTS_PER_DISK) + 
+                               ((major - XEN_SCSI_DISK8_MAJOR + 8) * 16) +
+                               EMULATED_SD_DISK_NAME_OFFSET;
+                       *minor = *minor +
+                               ((major - XEN_SCSI_DISK8_MAJOR + 8) * 16 * PARTS_PER_DISK) +
+                               EMULATED_SD_DISK_MINOR_OFFSET;
+                       break;
+               case XENVBD_MAJOR:
+                       *offset = *minor / PARTS_PER_DISK;
+                       break;
+               default:
+                       printk(KERN_WARNING "blkfront: your disk configuration is "
+                                       "incorrect, please use an xvd device instead\n");
+                       return -ENODEV;
+       }
+       return 0;
+}
 
 static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
                               struct blkfront_info *info,
@@ -441,7 +504,7 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
 {
        struct gendisk *gd;
        int nr_minors = 1;
-       int err = -ENODEV;
+       int err;
        unsigned int offset;
        int minor;
        int nr_parts;
@@ -456,12 +519,20 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
        }
 
        if (!VDEV_IS_EXTENDED(info->vdevice)) {
-               minor = BLKIF_MINOR(info->vdevice);
-               nr_parts = PARTS_PER_DISK;
+               err = xen_translate_vdev(info->vdevice, &minor, &offset);
+               if (err)
+                       return err;             
+               nr_parts = PARTS_PER_DISK;
        } else {
                minor = BLKIF_MINOR_EXT(info->vdevice);
                nr_parts = PARTS_PER_EXT_DISK;
+               offset = minor / nr_parts;
+               if (xen_hvm_domain() && offset <= EMULATED_HD_DISK_NAME_OFFSET + 4)
+                       printk(KERN_WARNING "blkfront: vdevice 0x%x might conflict with "
+                                       "emulated IDE disks,\n\t choose an xvd device name"
+                                       "from xvde on\n", info->vdevice);
        }
+       err = -ENODEV;
 
        if ((minor % nr_parts) == 0)
                nr_minors = nr_parts;
@@ -475,8 +546,6 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
        if (gd == NULL)
                goto release;
 
-       offset = minor / nr_parts;
-
        if (nr_minors > 1) {
                if (offset < 26)
                        sprintf(gd->disk_name, "%s%c", DEV_NAME, 'a' + offset);
@@ -615,7 +684,7 @@ static void blkif_completion(struct blk_shadow *s)
 {
        int i;
        for (i = 0; i < s->req.nr_segments; i++)
-               gnttab_end_foreign_access(s->req.seg[i].gref, 0, 0UL);
+               gnttab_end_foreign_access(s->req.u.rw.seg[i].gref, 0, 0UL);
 }
 
 static irqreturn_t blkif_interrupt(int irq, void *dev_id)
@@ -932,7 +1001,7 @@ static int blkif_recover(struct blkfront_info *info)
                /* Rewrite any grant references invalidated by susp/resume. */
                for (j = 0; j < req->nr_segments; j++)
                        gnttab_grant_foreign_access_ref(
-                               req->seg[j].gref,
+                               req->u.rw.seg[j].gref,
                                info->xbdev->otherend_id,
                                pfn_to_mfn(info->shadow[req->id].frame[j]),
                                rq_data_dir(info->shadow[req->id].request));
index 949ed09..6dcd55a 100644 (file)
@@ -39,6 +39,11 @@ static struct usb_device_id ath3k_table[] = {
        /* Atheros AR3011 with sflash firmware*/
        { USB_DEVICE(0x0CF3, 0x3002) },
 
+       /* Atheros AR9285 Malbec with sflash firmware */
+       { USB_DEVICE(0x03F0, 0x311D) },
+
+       /* Atheros AR5BBU12 with sflash firmware */
+       { USB_DEVICE(0x0489, 0xE02C) },
        { }     /* Terminating entry */
 };
 
@@ -47,46 +52,40 @@ MODULE_DEVICE_TABLE(usb, ath3k_table);
 #define USB_REQ_DFU_DNLOAD     1
 #define BULK_SIZE              4096
 
-struct ath3k_data {
-       struct usb_device *udev;
-       u8 *fw_data;
-       u32 fw_size;
-       u32 fw_sent;
-};
-
-static int ath3k_load_firmware(struct ath3k_data *data,
-                               unsigned char *firmware,
-                               int count)
+static int ath3k_load_firmware(struct usb_device *udev,
+                               const struct firmware *firmware)
 {
        u8 *send_buf;
        int err, pipe, len, size, sent = 0;
+       int count = firmware->size;
 
-       BT_DBG("ath3k %p udev %p", data, data->udev);
+       BT_DBG("udev %p", udev);
 
-       pipe = usb_sndctrlpipe(data->udev, 0);
+       pipe = usb_sndctrlpipe(udev, 0);
 
-       if ((usb_control_msg(data->udev, pipe,
+       send_buf = kmalloc(BULK_SIZE, GFP_ATOMIC);
+       if (!send_buf) {
+               BT_ERR("Can't allocate memory chunk for firmware");
+               return -ENOMEM;
+       }
+
+       memcpy(send_buf, firmware->data, 20);
+       if ((err = usb_control_msg(udev, pipe,
                                USB_REQ_DFU_DNLOAD,
                                USB_TYPE_VENDOR, 0, 0,
-                               firmware, 20, USB_CTRL_SET_TIMEOUT)) < 0) {
+                               send_buf, 20, USB_CTRL_SET_TIMEOUT)) < 0) {
                BT_ERR("Can't change to loading configuration err");
-               return -EBUSY;
+               goto error;
        }
        sent += 20;
        count -= 20;
 
-       send_buf = kmalloc(BULK_SIZE, GFP_ATOMIC);
-       if (!send_buf) {
-               BT_ERR("Can't allocate memory chunk for firmware");
-               return -ENOMEM;
-       }
-
        while (count) {
                size = min_t(uint, count, BULK_SIZE);
-               pipe = usb_sndbulkpipe(data->udev, 0x02);
-               memcpy(send_buf, firmware + sent, size);
+               pipe = usb_sndbulkpipe(udev, 0x02);
+               memcpy(send_buf, firmware->data + sent, size);
 
-               err = usb_bulk_msg(data->udev, pipe, send_buf, size,
+               err = usb_bulk_msg(udev, pipe, send_buf, size,
                                        &len, 3000);
 
                if (err || (len != size)) {
@@ -112,57 +111,28 @@ static int ath3k_probe(struct usb_interface *intf,
 {
        const struct firmware *firmware;
        struct usb_device *udev = interface_to_usbdev(intf);
-       struct ath3k_data *data;
-       int size;
 
        BT_DBG("intf %p id %p", intf, id);
 
        if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
                return -ENODEV;
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       data->udev = udev;
-
        if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
-               kfree(data);
                return -EIO;
        }
 
-       size = max_t(uint, firmware->size, 4096);
-       data->fw_data = kmalloc(size, GFP_KERNEL);
-       if (!data->fw_data) {
+       if (ath3k_load_firmware(udev, firmware)) {
                release_firmware(firmware);
-               kfree(data);
-               return -ENOMEM;
-       }
-
-       memcpy(data->fw_data, firmware->data, firmware->size);
-       data->fw_size = firmware->size;
-       data->fw_sent = 0;
-       release_firmware(firmware);
-
-       usb_set_intfdata(intf, data);
-       if (ath3k_load_firmware(data, data->fw_data, data->fw_size)) {
-               usb_set_intfdata(intf, NULL);
-               kfree(data->fw_data);
-               kfree(data);
                return -EIO;
        }
+       release_firmware(firmware);
 
        return 0;
 }
 
 static void ath3k_disconnect(struct usb_interface *intf)
 {
-       struct ath3k_data *data = usb_get_intfdata(intf);
-
        BT_DBG("ath3k_disconnect intf %p", intf);
-
-       kfree(data->fw_data);
-       kfree(data);
 }
 
 static struct usb_driver ath3k_driver = {
index 1da773f..700a384 100644 (file)
@@ -102,6 +102,12 @@ static struct usb_device_id blacklist_table[] = {
        /* Atheros 3011 with sflash firmware */
        { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
 
+       /* Atheros AR9285 Malbec with sflash firmware */
+       { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
+
+       /* Atheros AR5BBU12 with sflash firmware */
+       { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
+
        /* Broadcom BCM2035 */
        { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
        { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
@@ -826,7 +832,7 @@ static void btusb_work(struct work_struct *work)
 
        if (hdev->conn_hash.sco_num > 0) {
                if (!test_bit(BTUSB_DID_ISO_RESUME, &data->flags)) {
-                       err = usb_autopm_get_interface(data->isoc);
+                       err = usb_autopm_get_interface(data->isoc ? data->isoc : data->intf);
                        if (err < 0) {
                                clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
                                usb_kill_anchored_urbs(&data->isoc_anchor);
@@ -855,7 +861,7 @@ static void btusb_work(struct work_struct *work)
 
                __set_isoc_interface(hdev, 0);
                if (test_and_clear_bit(BTUSB_DID_ISO_RESUME, &data->flags))
-                       usb_autopm_put_interface(data->isoc);
+                       usb_autopm_put_interface(data->isoc ? data->isoc : data->intf);
        }
 }
 
@@ -1038,8 +1044,6 @@ static int btusb_probe(struct usb_interface *intf,
 
        usb_set_intfdata(intf, data);
 
-       usb_enable_autosuspend(interface_to_usbdev(intf));
-
        return 0;
 }
 
index 14033a3..e2c48a7 100644 (file)
@@ -409,7 +409,8 @@ int register_cdrom(struct cdrom_device_info *cdi)
        }
 
        ENSURE(drive_status, CDC_DRIVE_STATUS );
-       ENSURE(media_changed, CDC_MEDIA_CHANGED);
+       if (cdo->check_events == NULL && cdo->media_changed == NULL)
+               *change_capability = ~(CDC_MEDIA_CHANGED | CDC_SELECT_DISC);
        ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY);
        ENSURE(lock_door, CDC_LOCK);
        ENSURE(select_speed, CDC_SELECT_SPEED);
index 5bc765d..8238f89 100644 (file)
@@ -30,6 +30,7 @@ obj-$(CONFIG_SYNCLINK_GT)     += synclink_gt.o
 obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
 obj-$(CONFIG_SX)               += sx.o generic_serial.o
 obj-$(CONFIG_RIO)              += rio/ generic_serial.o
+obj-$(CONFIG_VIRTIO_CONSOLE)   += virtio_console.o
 obj-$(CONFIG_RAW_DRIVER)       += raw.o
 obj-$(CONFIG_SGI_SNSC)         += snsc.o snsc_event.o
 obj-$(CONFIG_MSPEC)            += mspec.o
index fcd867d..d8b1b57 100644 (file)
@@ -50,7 +50,7 @@ config AGP_ATI
 
 config AGP_AMD
        tristate "AMD Irongate, 761, and 762 chipset support"
-       depends on AGP && (X86_32 || ALPHA)
+       depends on AGP && X86_32
        help
          This option gives you AGP support for the GLX component of
          X on AMD Irongate, 761, and 762 chipsets.
index b1b4362..45681c0 100644 (file)
@@ -41,22 +41,8 @@ static int amd_create_page_map(struct amd_page_map *page_map)
        if (page_map->real == NULL)
                return -ENOMEM;
 
-#ifndef CONFIG_X86
-       SetPageReserved(virt_to_page(page_map->real));
-       global_cache_flush();
-       page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real),
-                                           PAGE_SIZE);
-       if (page_map->remapped == NULL) {
-               ClearPageReserved(virt_to_page(page_map->real));
-               free_page((unsigned long) page_map->real);
-               page_map->real = NULL;
-               return -ENOMEM;
-       }
-       global_cache_flush();
-#else
        set_memory_uc((unsigned long)page_map->real, 1);
        page_map->remapped = page_map->real;
-#endif
 
        for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) {
                writel(agp_bridge->scratch_page, page_map->remapped+i);
@@ -68,12 +54,7 @@ static int amd_create_page_map(struct amd_page_map *page_map)
 
 static void amd_free_page_map(struct amd_page_map *page_map)
 {
-#ifndef CONFIG_X86
-       iounmap(page_map->remapped);
-       ClearPageReserved(virt_to_page(page_map->real));
-#else
        set_memory_wb((unsigned long)page_map->real, 1);
-#endif
        free_page((unsigned long) page_map->real);
 }
 
index 9252e85..780498d 100644 (file)
@@ -773,18 +773,23 @@ int __init agp_amd64_init(void)
 #else
                        printk(KERN_INFO PFX "You can boot with agp=try_unsupported\n");
 #endif
+                       pci_unregister_driver(&agp_amd64_pci_driver);
                        return -ENODEV;
                }
 
                /* First check that we have at least one AMD64 NB */
-               if (!pci_dev_present(amd_nb_misc_ids))
+               if (!pci_dev_present(amd_nb_misc_ids)) {
+                       pci_unregister_driver(&agp_amd64_pci_driver);
                        return -ENODEV;
+               }
 
                /* Look for any AGP bridge */
                agp_amd64_pci_driver.id_table = agp_amd64_pci_promisc_table;
                err = driver_attach(&agp_amd64_pci_driver.driver);
-               if (err == 0 && agp_bridges_found == 0)
+               if (err == 0 && agp_bridges_found == 0) {
+                       pci_unregister_driver(&agp_amd64_pci_driver);
                        err = -ENODEV;
+               }
        }
        return err;
 }
index 857df10..b0a0dcc 100644 (file)
@@ -773,21 +773,15 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
 
        dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name);
 
-       /*
-       * If the device has not been properly setup, the following will catch
-       * the problem and should stop the system from crashing.
-       * 20030610 - hamish@zot.org
-       */
-       if (pci_enable_device(pdev)) {
-               dev_err(&pdev->dev, "can't enable PCI device\n");
-               agp_put_bridge(bridge);
-               return -ENODEV;
-       }
-
        /*
        * The following fixes the case where the BIOS has "forgotten" to
        * provide an address range for the GART.
        * 20030610 - hamish@zot.org
+       * This happens before pci_enable_device() intentionally;
+       * calling pci_enable_device() before assigning the resource
+       * will result in the GART being disabled on machines with such
+       * BIOSs (the GART ends up with a BAR starting at 0, which
+       * conflicts a lot of other devices).
        */
        r = &pdev->resource[0];
        if (!r->start && r->end) {
@@ -798,6 +792,17 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
                }
        }
 
+       /*
+       * If the device has not been properly setup, the following will catch
+       * the problem and should stop the system from crashing.
+       * 20030610 - hamish@zot.org
+       */
+       if (pci_enable_device(pdev)) {
+               dev_err(&pdev->dev, "can't enable PCI device\n");
+               agp_put_bridge(bridge);
+               return -ENODEV;
+       }
+
        /* Fill in the mode register */
        if (cap_ptr) {
                pci_read_config_dword(pdev,
index c195bfe..5feebe2 100644 (file)
 #define INTEL_GMCH_GMS_STOLEN_352M     (0xd << 4)
 
 #define I915_IFPADDR    0x60
+#define I830_HIC        0x70
 
 /* Intel 965G registers */
 #define I965_MSAC 0x62
index fab3d32..0d09b53 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/pagemap.h>
 #include <linux/agp_backend.h>
+#include <linux/delay.h>
 #include <asm/smp.h>
 #include "agp.h"
 #include "intel-agp.h"
@@ -70,12 +71,8 @@ static struct _intel_private {
        u32 __iomem *gtt;               /* I915G */
        bool clear_fake_agp; /* on first access via agp, fill with scratch */
        int num_dcache_entries;
-       union {
-               void __iomem *i9xx_flush_page;
-               void *i8xx_flush_page;
-       };
+       void __iomem *i9xx_flush_page;
        char *i81x_gtt_table;
-       struct page *i8xx_page;
        struct resource ifp_resource;
        int resource_valid;
        struct page *scratch_page;
@@ -722,28 +719,6 @@ static int intel_fake_agp_fetch_size(void)
 
 static void i830_cleanup(void)
 {
-       if (intel_private.i8xx_flush_page) {
-               kunmap(intel_private.i8xx_flush_page);
-               intel_private.i8xx_flush_page = NULL;
-       }
-
-       __free_page(intel_private.i8xx_page);
-       intel_private.i8xx_page = NULL;
-}
-
-static void intel_i830_setup_flush(void)
-{
-       /* return if we've already set the flush mechanism up */
-       if (intel_private.i8xx_page)
-               return;
-
-       intel_private.i8xx_page = alloc_page(GFP_KERNEL);
-       if (!intel_private.i8xx_page)
-               return;
-
-       intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page);
-       if (!intel_private.i8xx_flush_page)
-               i830_cleanup();
 }
 
 /* The chipset_flush interface needs to get data that has already been
@@ -758,14 +733,27 @@ static void intel_i830_setup_flush(void)
  */
 static void i830_chipset_flush(void)
 {
-       unsigned int *pg = intel_private.i8xx_flush_page;
+       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+       /* Forcibly evict everything from the CPU write buffers.
+        * clflush appears to be insufficient.
+        */
+       wbinvd_on_all_cpus();
+
+       /* Now we've only seen documents for this magic bit on 855GM,
+        * we hope it exists for the other gen2 chipsets...
+        *
+        * Also works as advertised on my 845G.
+        */
+       writel(readl(intel_private.registers+I830_HIC) | (1<<31),
+              intel_private.registers+I830_HIC);
 
-       memset(pg, 0, 1024);
+       while (readl(intel_private.registers+I830_HIC) & (1<<31)) {
+               if (time_after(jiffies, timeout))
+                       break;
 
-       if (cpu_has_clflush)
-               clflush_cache_range(pg, 1024);
-       else if (wbinvd_on_all_cpus() != 0)
-               printk(KERN_ERR "Timed out waiting for cache flush.\n");
+               udelay(50);
+       }
 }
 
 static void i830_write_entry(dma_addr_t addr, unsigned int entry,
@@ -849,8 +837,6 @@ static int i830_setup(void)
 
        intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE;
 
-       intel_i830_setup_flush();
-
        return 0;
 }
 
index e397df3..1640244 100644 (file)
@@ -183,16 +183,16 @@ bfin_jc_circ_write(const unsigned char *buf, int count)
 }
 
 #ifndef CONFIG_BFIN_JTAG_COMM_CONSOLE
-# define acquire_console_sem()
-# define release_console_sem()
+# define console_lock()
+# define console_unlock()
 #endif
 static int
 bfin_jc_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
        int i;
-       acquire_console_sem();
+       console_lock();
        i = bfin_jc_circ_write(buf, count);
-       release_console_sem();
+       console_unlock();
        wake_up_process(bfin_jc_kthread);
        return i;
 }
index b6ae6e9..62787e3 100644 (file)
@@ -320,6 +320,7 @@ static int unload_when_empty = 1;
 static int add_smi(struct smi_info *smi);
 static int try_smi_init(struct smi_info *smi);
 static void cleanup_one_si(struct smi_info *to_clean);
+static void cleanup_ipmi_si(void);
 
 static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list);
 static int register_xaction_notifier(struct notifier_block *nb)
@@ -899,6 +900,14 @@ static void sender(void                *send_info,
        printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec);
 #endif
 
+       /*
+        * last_timeout_jiffies is updated here to avoid
+        * smi_timeout() handler passing very large time_diff
+        * value to smi_event_handler() that causes
+        * the send command to abort.
+        */
+       smi_info->last_timeout_jiffies = jiffies;
+
        mod_timer(&smi_info->si_timer, jiffies + SI_TIMEOUT_JIFFIES);
 
        if (smi_info->thread)
@@ -3450,16 +3459,7 @@ static int __devinit init_ipmi_si(void)
        mutex_lock(&smi_infos_lock);
        if (unload_when_empty && list_empty(&smi_infos)) {
                mutex_unlock(&smi_infos_lock);
-#ifdef CONFIG_PCI
-               if (pci_registered)
-                       pci_unregister_driver(&ipmi_pci_driver);
-#endif
-
-#ifdef CONFIG_PPC_OF
-               if (of_registered)
-                       of_unregister_platform_driver(&ipmi_of_platform_driver);
-#endif
-               driver_unregister(&ipmi_driver.driver);
+               cleanup_ipmi_si();
                printk(KERN_WARNING PFX
                       "Unable to find any System Interface(s)\n");
                return -ENODEV;
index e6d7562..33dc229 100644 (file)
@@ -53,6 +53,8 @@ MODULE_LICENSE("GPL");
 
 #define RTC_BITS 55 /* 55 bits for this implementation */
 
+static struct k_clock sgi_clock;
+
 extern unsigned long sn_rtc_cycles_per_second;
 
 #define RTC_COUNTER_ADDR        ((long *)LOCAL_MMR_ADDR(SH_RTC))
@@ -487,7 +489,7 @@ static int sgi_clock_get(clockid_t clockid, struct timespec *tp)
        return 0;
 };
 
-static int sgi_clock_set(clockid_t clockid, struct timespec *tp)
+static int sgi_clock_set(const clockid_t clockid, const struct timespec *tp)
 {
 
        u64 nsec;
@@ -763,15 +765,21 @@ static int sgi_timer_set(struct k_itimer *timr, int flags,
        return err;
 }
 
+static int sgi_clock_getres(const clockid_t which_clock, struct timespec *tp)
+{
+       tp->tv_sec = 0;
+       tp->tv_nsec = sgi_clock_period;
+       return 0;
+}
+
 static struct k_clock sgi_clock = {
-       .res = 0,
-       .clock_set = sgi_clock_set,
-       .clock_get = sgi_clock_get,
-       .timer_create = sgi_timer_create,
-       .nsleep = do_posix_clock_nonanosleep,
-       .timer_set = sgi_timer_set,
-       .timer_del = sgi_timer_del,
-       .timer_get = sgi_timer_get
+       .clock_set      = sgi_clock_set,
+       .clock_get      = sgi_clock_get,
+       .clock_getres   = sgi_clock_getres,
+       .timer_create   = sgi_timer_create,
+       .timer_set      = sgi_timer_set,
+       .timer_del      = sgi_timer_del,
+       .timer_get      = sgi_timer_get
 };
 
 /**
@@ -831,8 +839,8 @@ static int __init mmtimer_init(void)
                        (unsigned long) node);
        }
 
-       sgi_clock_period = sgi_clock.res = NSEC_PER_SEC / sn_rtc_cycles_per_second;
-       register_posix_clock(CLOCK_SGI_CYCLE, &sgi_clock);
+       sgi_clock_period = NSEC_PER_SEC / sn_rtc_cycles_per_second;
+       posix_timers_register_clock(CLOCK_SGI_CYCLE, &sgi_clock);
 
        printk(KERN_INFO "%s: v%s, %ld MHz\n", MMTIMER_DESC, MMTIMER_VERSION,
               sn_rtc_cycles_per_second/(unsigned long)1E6);
index 777181a..bcbbc71 100644 (file)
@@ -830,8 +830,7 @@ static void monitor_card(unsigned long p)
                            test_bit(IS_ANY_T1, &dev->flags))) {
                                DEBUGP(4, dev, "Perform AUTOPPS\n");
                                set_bit(IS_AUTOPPS_ACT, &dev->flags);
-                               ptsreq.protocol = ptsreq.protocol =
-                                   (0x01 << dev->proto);
+                               ptsreq.protocol = (0x01 << dev->proto);
                                ptsreq.flags = 0x01;
                                ptsreq.pts1 = 0x00;
                                ptsreq.pts2 = 0x00;
index 94b8eb4..444155a 100644 (file)
@@ -78,7 +78,6 @@ static void signalled_reboot_callback(void *callback_data)
 static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data)
 {
        struct ipw_dev *ipw = priv_data;
-       struct resource *io_resource;
        int ret;
 
        p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
@@ -92,9 +91,12 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data)
        if (ret)
                return ret;
 
-       io_resource = request_region(p_dev->resource[0]->start,
-                               resource_size(p_dev->resource[0]),
-                               IPWIRELESS_PCCARD_NAME);
+       if (!request_region(p_dev->resource[0]->start,
+                           resource_size(p_dev->resource[0]),
+                           IPWIRELESS_PCCARD_NAME)) {
+               ret = -EBUSY;
+               goto exit;
+       }
 
        p_dev->resource[2]->flags |=
                WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE;
@@ -105,22 +107,25 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data)
 
        ret = pcmcia_map_mem_page(p_dev, p_dev->resource[2], p_dev->card_addr);
        if (ret != 0)
-               goto exit2;
+               goto exit1;
 
        ipw->is_v2_card = resource_size(p_dev->resource[2]) == 0x100;
 
-       ipw->attr_memory = ioremap(p_dev->resource[2]->start,
+       ipw->common_memory = ioremap(p_dev->resource[2]->start,
                                resource_size(p_dev->resource[2]));
-       request_mem_region(p_dev->resource[2]->start,
-                       resource_size(p_dev->resource[2]),
-                       IPWIRELESS_PCCARD_NAME);
+       if (!request_mem_region(p_dev->resource[2]->start,
+                               resource_size(p_dev->resource[2]),
+                               IPWIRELESS_PCCARD_NAME)) {
+               ret = -EBUSY;
+               goto exit2;
+       }
 
        p_dev->resource[3]->flags |= WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM |
                                        WIN_ENABLE;
        p_dev->resource[3]->end = 0; /* this used to be 0x1000 */
        ret = pcmcia_request_window(p_dev, p_dev->resource[3], 0);
        if (ret != 0)
-               goto exit2;
+               goto exit3;
 
        ret = pcmcia_map_mem_page(p_dev, p_dev->resource[3], 0);
        if (ret != 0)
@@ -128,23 +133,28 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data)
 
        ipw->attr_memory = ioremap(p_dev->resource[3]->start,
                                resource_size(p_dev->resource[3]));
-       request_mem_region(p_dev->resource[3]->start,
-                       resource_size(p_dev->resource[3]),
-                       IPWIRELESS_PCCARD_NAME);
+       if (!request_mem_region(p_dev->resource[3]->start,
+                               resource_size(p_dev->resource[3]),
+                               IPWIRELESS_PCCARD_NAME)) {
+               ret = -EBUSY;
+               goto exit4;
+       }
 
        return 0;
 
+exit4:
+       iounmap(ipw->attr_memory);
 exit3:
+       release_mem_region(p_dev->resource[2]->start,
+                       resource_size(p_dev->resource[2]));
 exit2:
-       if (ipw->common_memory) {
-               release_mem_region(p_dev->resource[2]->start,
-                               resource_size(p_dev->resource[2]));
-               iounmap(ipw->common_memory);
-       }
+       iounmap(ipw->common_memory);
 exit1:
-       release_resource(io_resource);
+       release_region(p_dev->resource[0]->start,
+                      resource_size(p_dev->resource[0]));
+exit:
        pcmcia_disable_device(p_dev);
-       return -1;
+       return ret;
 }
 
 static int config_ipwireless(struct ipw_dev *ipw)
@@ -219,6 +229,8 @@ exit:
 
 static void release_ipwireless(struct ipw_dev *ipw)
 {
+       release_region(ipw->link->resource[0]->start,
+                      resource_size(ipw->link->resource[0]));
        if (ipw->common_memory) {
                release_mem_region(ipw->link->resource[2]->start,
                                resource_size(ipw->link->resource[2]));
index 36e0fa1..1f46f1c 100644 (file)
@@ -364,14 +364,12 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip,
                    tpm_protected_ordinal_duration[ordinal &
                                                   TPM_PROTECTED_ORDINAL_MASK];
 
-       if (duration_idx != TPM_UNDEFINED) {
+       if (duration_idx != TPM_UNDEFINED)
                duration = chip->vendor.duration[duration_idx];
-               /* if duration is 0, it's because chip->vendor.duration wasn't */
-               /* filled yet, so we set the lowest timeout just to give enough */
-               /* time for tpm_get_timeouts() to succeed */
-               return (duration <= 0 ? HZ : duration);
-       } else
+       if (duration <= 0)
                return 2 * 60 * HZ;
+       else
+               return duration;
 }
 EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);
 
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
new file mode 100644 (file)
index 0000000..84b164d
--- /dev/null
@@ -0,0 +1,1858 @@
+/*
+ * Copyright (C) 2006, 2007, 2009 Rusty Russell, IBM Corporation
+ * Copyright (C) 2009, 2010, 2011 Red Hat, Inc.
+ * Copyright (C) 2009, 2010, 2011 Amit Shah <amit.shah@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/cdev.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/virtio.h>
+#include <linux/virtio_console.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include "../tty/hvc/hvc_console.h"
+
+/*
+ * This is a global struct for storing common data for all the devices
+ * this driver handles.
+ *
+ * Mainly, it has a linked list for all the consoles in one place so
+ * that callbacks from hvc for get_chars(), put_chars() work properly
+ * across multiple devices and multiple ports per device.
+ */
+struct ports_driver_data {
+       /* Used for registering chardevs */
+       struct class *class;
+
+       /* Used for exporting per-port information to debugfs */
+       struct dentry *debugfs_dir;
+
+       /* List of all the devices we're handling */
+       struct list_head portdevs;
+
+       /* Number of devices this driver is handling */
+       unsigned int index;
+
+       /*
+        * This is used to keep track of the number of hvc consoles
+        * spawned by this driver.  This number is given as the first
+        * argument to hvc_alloc().  To correctly map an initial
+        * console spawned via hvc_instantiate to the console being
+        * hooked up via hvc_alloc, we need to pass the same vtermno.
+        *
+        * We also just assume the first console being initialised was
+        * the first one that got used as the initial console.
+        */
+       unsigned int next_vtermno;
+
+       /* All the console devices handled by this driver */
+       struct list_head consoles;
+};
+static struct ports_driver_data pdrvdata;
+
+DEFINE_SPINLOCK(pdrvdata_lock);
+
+/* This struct holds information that's relevant only for console ports */
+struct console {
+       /* We'll place all consoles in a list in the pdrvdata struct */
+       struct list_head list;
+
+       /* The hvc device associated with this console port */
+       struct hvc_struct *hvc;
+
+       /* The size of the console */
+       struct winsize ws;
+
+       /*
+        * This number identifies the number that we used to register
+        * with hvc in hvc_instantiate() and hvc_alloc(); this is the
+        * number passed on by the hvc callbacks to us to
+        * differentiate between the other console ports handled by
+        * this driver
+        */
+       u32 vtermno;
+};
+
+struct port_buffer {
+       char *buf;
+
+       /* size of the buffer in *buf above */
+       size_t size;
+
+       /* used length of the buffer */
+       size_t len;
+       /* offset in the buf from which to consume data */
+       size_t offset;
+};
+
+/*
+ * This is a per-device struct that stores data common to all the
+ * ports for that device (vdev->priv).
+ */
+struct ports_device {
+       /* Next portdev in the list, head is in the pdrvdata struct */
+       struct list_head list;
+
+       /*
+        * Workqueue handlers where we process deferred work after
+        * notification
+        */
+       struct work_struct control_work;
+
+       struct list_head ports;
+
+       /* To protect the list of ports */
+       spinlock_t ports_lock;
+
+       /* To protect the vq operations for the control channel */
+       spinlock_t cvq_lock;
+
+       /* The current config space is stored here */
+       struct virtio_console_config config;
+
+       /* The virtio device we're associated with */
+       struct virtio_device *vdev;
+
+       /*
+        * A couple of virtqueues for the control channel: one for
+        * guest->host transfers, one for host->guest transfers
+        */
+       struct virtqueue *c_ivq, *c_ovq;
+
+       /* Array of per-port IO virtqueues */
+       struct virtqueue **in_vqs, **out_vqs;
+
+       /* Used for numbering devices for sysfs and debugfs */
+       unsigned int drv_index;
+
+       /* Major number for this device.  Ports will be created as minors. */
+       int chr_major;
+};
+
+/* This struct holds the per-port data */
+struct port {
+       /* Next port in the list, head is in the ports_device */
+       struct list_head list;
+
+       /* Pointer to the parent virtio_console device */
+       struct ports_device *portdev;
+
+       /* The current buffer from which data has to be fed to readers */
+       struct port_buffer *inbuf;
+
+       /*
+        * To protect the operations on the in_vq associated with this
+        * port.  Has to be a spinlock because it can be called from
+        * interrupt context (get_char()).
+        */
+       spinlock_t inbuf_lock;
+
+       /* Protect the operations on the out_vq. */
+       spinlock_t outvq_lock;
+
+       /* The IO vqs for this port */
+       struct virtqueue *in_vq, *out_vq;
+
+       /* File in the debugfs directory that exposes this port's information */
+       struct dentry *debugfs_file;
+
+       /*
+        * The entries in this struct will be valid if this port is
+        * hooked up to an hvc console
+        */
+       struct console cons;
+
+       /* Each port associates with a separate char device */
+       struct cdev *cdev;
+       struct device *dev;
+
+       /* Reference-counting to handle port hot-unplugs and file operations */
+       struct kref kref;
+
+       /* A waitqueue for poll() or blocking read operations */
+       wait_queue_head_t waitqueue;
+
+       /* The 'name' of the port that we expose via sysfs properties */
+       char *name;
+
+       /* We can notify apps of host connect / disconnect events via SIGIO */
+       struct fasync_struct *async_queue;
+
+       /* The 'id' to identify the port with the Host */
+       u32 id;
+
+       bool outvq_full;
+
+       /* Is the host device open */
+       bool host_connected;
+
+       /* We should allow only one process to open a port */
+       bool guest_connected;
+};
+
+/* This is the very early arch-specified put chars function. */
+static int (*early_put_chars)(u32, const char *, int);
+
+static struct port *find_port_by_vtermno(u32 vtermno)
+{
+       struct port *port;
+       struct console *cons;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pdrvdata_lock, flags);
+       list_for_each_entry(cons, &pdrvdata.consoles, list) {
+               if (cons->vtermno == vtermno) {
+                       port = container_of(cons, struct port, cons);
+                       goto out;
+               }
+       }
+       port = NULL;
+out:
+       spin_unlock_irqrestore(&pdrvdata_lock, flags);
+       return port;
+}
+
+static struct port *find_port_by_devt_in_portdev(struct ports_device *portdev,
+                                                dev_t dev)
+{
+       struct port *port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&portdev->ports_lock, flags);
+       list_for_each_entry(port, &portdev->ports, list)
+               if (port->cdev->dev == dev)
+                       goto out;
+       port = NULL;
+out:
+       spin_unlock_irqrestore(&portdev->ports_lock, flags);
+
+       return port;
+}
+
+static struct port *find_port_by_devt(dev_t dev)
+{
+       struct ports_device *portdev;
+       struct port *port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pdrvdata_lock, flags);
+       list_for_each_entry(portdev, &pdrvdata.portdevs, list) {
+               port = find_port_by_devt_in_portdev(portdev, dev);
+               if (port)
+                       goto out;
+       }
+       port = NULL;
+out:
+       spin_unlock_irqrestore(&pdrvdata_lock, flags);
+       return port;
+}
+
+static struct port *find_port_by_id(struct ports_device *portdev, u32 id)
+{
+       struct port *port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&portdev->ports_lock, flags);
+       list_for_each_entry(port, &portdev->ports, list)
+               if (port->id == id)
+                       goto out;
+       port = NULL;
+out:
+       spin_unlock_irqrestore(&portdev->ports_lock, flags);
+
+       return port;
+}
+
+static struct port *find_port_by_vq(struct ports_device *portdev,
+                                   struct virtqueue *vq)
+{
+       struct port *port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&portdev->ports_lock, flags);
+       list_for_each_entry(port, &portdev->ports, list)
+               if (port->in_vq == vq || port->out_vq == vq)
+                       goto out;
+       port = NULL;
+out:
+       spin_unlock_irqrestore(&portdev->ports_lock, flags);
+       return port;
+}
+
+static bool is_console_port(struct port *port)
+{
+       if (port->cons.hvc)
+               return true;
+       return false;
+}
+
+static inline bool use_multiport(struct ports_device *portdev)
+{
+       /*
+        * This condition can be true when put_chars is called from
+        * early_init
+        */
+       if (!portdev->vdev)
+               return 0;
+       return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
+}
+
+static void free_buf(struct port_buffer *buf)
+{
+       kfree(buf->buf);
+       kfree(buf);
+}
+
+static struct port_buffer *alloc_buf(size_t buf_size)
+{
+       struct port_buffer *buf;
+
+       buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+       if (!buf)
+               goto fail;
+       buf->buf = kzalloc(buf_size, GFP_KERNEL);
+       if (!buf->buf)
+               goto free_buf;
+       buf->len = 0;
+       buf->offset = 0;
+       buf->size = buf_size;
+       return buf;
+
+free_buf:
+       kfree(buf);
+fail:
+       return NULL;
+}
+
+/* Callers should take appropriate locks */
+static void *get_inbuf(struct port *port)
+{
+       struct port_buffer *buf;
+       struct virtqueue *vq;
+       unsigned int len;
+
+       vq = port->in_vq;
+       buf = virtqueue_get_buf(vq, &len);
+       if (buf) {
+               buf->len = len;
+               buf->offset = 0;
+       }
+       return buf;
+}
+
+/*
+ * Create a scatter-gather list representing our input buffer and put
+ * it in the queue.
+ *
+ * Callers should take appropriate locks.
+ */
+static int add_inbuf(struct virtqueue *vq, struct port_buffer *buf)
+{
+       struct scatterlist sg[1];
+       int ret;
+
+       sg_init_one(sg, buf->buf, buf->size);
+
+       ret = virtqueue_add_buf(vq, sg, 0, 1, buf);
+       virtqueue_kick(vq);
+       return ret;
+}
+
+/* Discard any unread data this port has. Callers lockers. */
+static void discard_port_data(struct port *port)
+{
+       struct port_buffer *buf;
+       struct virtqueue *vq;
+       unsigned int len;
+       int ret;
+
+       if (!port->portdev) {
+               /* Device has been unplugged.  vqs are already gone. */
+               return;
+       }
+       vq = port->in_vq;
+       if (port->inbuf)
+               buf = port->inbuf;
+       else
+               buf = virtqueue_get_buf(vq, &len);
+
+       ret = 0;
+       while (buf) {
+               if (add_inbuf(vq, buf) < 0) {
+                       ret++;
+                       free_buf(buf);
+               }
+               buf = virtqueue_get_buf(vq, &len);
+       }
+       port->inbuf = NULL;
+       if (ret)
+               dev_warn(port->dev, "Errors adding %d buffers back to vq\n",
+                        ret);
+}
+
+static bool port_has_data(struct port *port)
+{
+       unsigned long flags;
+       bool ret;
+
+       spin_lock_irqsave(&port->inbuf_lock, flags);
+       if (port->inbuf) {
+               ret = true;
+               goto out;
+       }
+       port->inbuf = get_inbuf(port);
+       if (port->inbuf) {
+               ret = true;
+               goto out;
+       }
+       ret = false;
+out:
+       spin_unlock_irqrestore(&port->inbuf_lock, flags);
+       return ret;
+}
+
+static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id,
+                                 unsigned int event, unsigned int value)
+{
+       struct scatterlist sg[1];
+       struct virtio_console_control cpkt;
+       struct virtqueue *vq;
+       unsigned int len;
+
+       if (!use_multiport(portdev))
+               return 0;
+
+       cpkt.id = port_id;
+       cpkt.event = event;
+       cpkt.value = value;
+
+       vq = portdev->c_ovq;
+
+       sg_init_one(sg, &cpkt, sizeof(cpkt));
+       if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt) >= 0) {
+               virtqueue_kick(vq);
+               while (!virtqueue_get_buf(vq, &len))
+                       cpu_relax();
+       }
+       return 0;
+}
+
+static ssize_t send_control_msg(struct port *port, unsigned int event,
+                               unsigned int value)
+{
+       /* Did the port get unplugged before userspace closed it? */
+       if (port->portdev)
+               return __send_control_msg(port->portdev, port->id, event, value);
+       return 0;
+}
+
+/* Callers must take the port->outvq_lock */
+static void reclaim_consumed_buffers(struct port *port)
+{
+       void *buf;
+       unsigned int len;
+
+       if (!port->portdev) {
+               /* Device has been unplugged.  vqs are already gone. */
+               return;
+       }
+       while ((buf = virtqueue_get_buf(port->out_vq, &len))) {
+               kfree(buf);
+               port->outvq_full = false;
+       }
+}
+
+static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
+                       bool nonblock)
+{
+       struct scatterlist sg[1];
+       struct virtqueue *out_vq;
+       ssize_t ret;
+       unsigned long flags;
+       unsigned int len;
+
+       out_vq = port->out_vq;
+
+       spin_lock_irqsave(&port->outvq_lock, flags);
+
+       reclaim_consumed_buffers(port);
+
+       sg_init_one(sg, in_buf, in_count);
+       ret = virtqueue_add_buf(out_vq, sg, 1, 0, in_buf);
+
+       /* Tell Host to go! */
+       virtqueue_kick(out_vq);
+
+       if (ret < 0) {
+               in_count = 0;
+               goto done;
+       }
+
+       if (ret == 0)
+               port->outvq_full = true;
+
+       if (nonblock)
+               goto done;
+
+       /*
+        * Wait till the host acknowledges it pushed out the data we
+        * sent.  This is done for data from the hvc_console; the tty
+        * operations are performed with spinlocks held so we can't
+        * sleep here.  An alternative would be to copy the data to a
+        * buffer and relax the spinning requirement.  The downside is
+        * we need to kmalloc a GFP_ATOMIC buffer each time the
+        * console driver writes something out.
+        */
+       while (!virtqueue_get_buf(out_vq, &len))
+               cpu_relax();
+done:
+       spin_unlock_irqrestore(&port->outvq_lock, flags);
+       /*
+        * We're expected to return the amount of data we wrote -- all
+        * of it
+        */
+       return in_count;
+}
+
+/*
+ * Give out the data that's requested from the buffer that we have
+ * queued up.
+ */
+static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count,
+                           bool to_user)
+{
+       struct port_buffer *buf;
+       unsigned long flags;
+
+       if (!out_count || !port_has_data(port))
+               return 0;
+
+       buf = port->inbuf;
+       out_count = min(out_count, buf->len - buf->offset);
+
+       if (to_user) {
+               ssize_t ret;
+
+               ret = copy_to_user(out_buf, buf->buf + buf->offset, out_count);
+               if (ret)
+                       return -EFAULT;
+       } else {
+               memcpy(out_buf, buf->buf + buf->offset, out_count);
+       }
+
+       buf->offset += out_count;
+
+       if (buf->offset == buf->len) {
+               /*
+                * We're done using all the data in this buffer.
+                * Re-queue so that the Host can send us more data.
+                */
+               spin_lock_irqsave(&port->inbuf_lock, flags);
+               port->inbuf = NULL;
+
+               if (add_inbuf(port->in_vq, buf) < 0)
+                       dev_warn(port->dev, "failed add_buf\n");
+
+               spin_unlock_irqrestore(&port->inbuf_lock, flags);
+       }
+       /* Return the number of bytes actually copied */
+       return out_count;
+}
+
+/* The condition that must be true for polling to end */
+static bool will_read_block(struct port *port)
+{
+       if (!port->guest_connected) {
+               /* Port got hot-unplugged. Let's exit. */
+               return false;
+       }
+       return !port_has_data(port) && port->host_connected;
+}
+
+static bool will_write_block(struct port *port)
+{
+       bool ret;
+
+       if (!port->guest_connected) {
+               /* Port got hot-unplugged. Let's exit. */
+               return false;
+       }
+       if (!port->host_connected)
+               return true;
+
+       spin_lock_irq(&port->outvq_lock);
+       /*
+        * Check if the Host has consumed any buffers since we last
+        * sent data (this is only applicable for nonblocking ports).
+        */
+       reclaim_consumed_buffers(port);
+       ret = port->outvq_full;
+       spin_unlock_irq(&port->outvq_lock);
+
+       return ret;
+}
+
+static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
+                             size_t count, loff_t *offp)
+{
+       struct port *port;
+       ssize_t ret;
+
+       port = filp->private_data;
+
+       if (!port_has_data(port)) {
+               /*
+                * If nothing's connected on the host just return 0 in
+                * case of list_empty; this tells the userspace app
+                * that there's no connection
+                */
+               if (!port->host_connected)
+                       return 0;
+               if (filp->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+
+               ret = wait_event_interruptible(port->waitqueue,
+                                              !will_read_block(port));
+               if (ret < 0)
+                       return ret;
+       }
+       /* Port got hot-unplugged. */
+       if (!port->guest_connected)
+               return -ENODEV;
+       /*
+        * We could've received a disconnection message while we were
+        * waiting for more data.
+        *
+        * This check is not clubbed in the if() statement above as we
+        * might receive some data as well as the host could get
+        * disconnected after we got woken up from our wait.  So we
+        * really want to give off whatever data we have and only then
+        * check for host_connected.
+        */
+       if (!port_has_data(port) && !port->host_connected)
+               return 0;
+
+       return fill_readbuf(port, ubuf, count, true);
+}
+
+static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
+                              size_t count, loff_t *offp)
+{
+       struct port *port;
+       char *buf;
+       ssize_t ret;
+       bool nonblock;
+
+       /* Userspace could be out to fool us */
+       if (!count)
+               return 0;
+
+       port = filp->private_data;
+
+       nonblock = filp->f_flags & O_NONBLOCK;
+
+       if (will_write_block(port)) {
+               if (nonblock)
+                       return -EAGAIN;
+
+               ret = wait_event_interruptible(port->waitqueue,
+                                              !will_write_block(port));
+               if (ret < 0)
+                       return ret;
+       }
+       /* Port got hot-unplugged. */
+       if (!port->guest_connected)
+               return -ENODEV;
+
+       count = min((size_t)(32 * 1024), count);
+
+       buf = kmalloc(count, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       ret = copy_from_user(buf, ubuf, count);
+       if (ret) {
+               ret = -EFAULT;
+               goto free_buf;
+       }
+
+       /*
+        * We now ask send_buf() to not spin for generic ports -- we
+        * can re-use the same code path that non-blocking file
+        * descriptors take for blocking file descriptors since the
+        * wait is already done and we're certain the write will go
+        * through to the host.
+        */
+       nonblock = true;
+       ret = send_buf(port, buf, count, nonblock);
+
+       if (nonblock && ret > 0)
+               goto out;
+
+free_buf:
+       kfree(buf);
+out:
+       return ret;
+}
+
+static unsigned int port_fops_poll(struct file *filp, poll_table *wait)
+{
+       struct port *port;
+       unsigned int ret;
+
+       port = filp->private_data;
+       poll_wait(filp, &port->waitqueue, wait);
+
+       if (!port->guest_connected) {
+               /* Port got unplugged */
+               return POLLHUP;
+       }
+       ret = 0;
+       if (!will_read_block(port))
+               ret |= POLLIN | POLLRDNORM;
+       if (!will_write_block(port))
+               ret |= POLLOUT;
+       if (!port->host_connected)
+               ret |= POLLHUP;
+
+       return ret;
+}
+
+static void remove_port(struct kref *kref);
+
+static int port_fops_release(struct inode *inode, struct file *filp)
+{
+       struct port *port;
+
+       port = filp->private_data;
+
+       /* Notify host of port being closed */
+       send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
+
+       spin_lock_irq(&port->inbuf_lock);
+       port->guest_connected = false;
+
+       discard_port_data(port);
+
+       spin_unlock_irq(&port->inbuf_lock);
+
+       spin_lock_irq(&port->outvq_lock);
+       reclaim_consumed_buffers(port);
+       spin_unlock_irq(&port->outvq_lock);
+
+       /*
+        * Locks aren't necessary here as a port can't be opened after
+        * unplug, and if a port isn't unplugged, a kref would already
+        * exist for the port.  Plus, taking ports_lock here would
+        * create a dependency on other locks taken by functions
+        * inside remove_port if we're the last holder of the port,
+        * creating many problems.
+        */
+       kref_put(&port->kref, remove_port);
+
+       return 0;
+}
+
+static int port_fops_open(struct inode *inode, struct file *filp)
+{
+       struct cdev *cdev = inode->i_cdev;
+       struct port *port;
+       int ret;
+
+       port = find_port_by_devt(cdev->dev);
+       filp->private_data = port;
+
+       /* Prevent against a port getting hot-unplugged at the same time */
+       spin_lock_irq(&port->portdev->ports_lock);
+       kref_get(&port->kref);
+       spin_unlock_irq(&port->portdev->ports_lock);
+
+       /*
+        * Don't allow opening of console port devices -- that's done
+        * via /dev/hvc
+        */
+       if (is_console_port(port)) {
+               ret = -ENXIO;
+               goto out;
+       }
+
+       /* Allow only one process to open a particular port at a time */
+       spin_lock_irq(&port->inbuf_lock);
+       if (port->guest_connected) {
+               spin_unlock_irq(&port->inbuf_lock);
+               ret = -EMFILE;
+               goto out;
+       }
+
+       port->guest_connected = true;
+       spin_unlock_irq(&port->inbuf_lock);
+
+       spin_lock_irq(&port->outvq_lock);
+       /*
+        * There might be a chance that we missed reclaiming a few
+        * buffers in the window of the port getting previously closed
+        * and opening now.
+        */
+       reclaim_consumed_buffers(port);
+       spin_unlock_irq(&port->outvq_lock);
+
+       nonseekable_open(inode, filp);
+
+       /* Notify host of port being opened */
+       send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1);
+
+       return 0;
+out:
+       kref_put(&port->kref, remove_port);
+       return ret;
+}
+
+static int port_fops_fasync(int fd, struct file *filp, int mode)
+{
+       struct port *port;
+
+       port = filp->private_data;
+       return fasync_helper(fd, filp, mode, &port->async_queue);
+}
+
+/*
+ * The file operations that we support: programs in the guest can open
+ * a console device, read from it, write to it, poll for data and
+ * close it.  The devices are at
+ *   /dev/vport<device number>p<port number>
+ */
+static const struct file_operations port_fops = {
+       .owner = THIS_MODULE,
+       .open  = port_fops_open,
+       .read  = port_fops_read,
+       .write = port_fops_write,
+       .poll  = port_fops_poll,
+       .release = port_fops_release,
+       .fasync = port_fops_fasync,
+       .llseek = no_llseek,
+};
+
+/*
+ * The put_chars() callback is pretty straightforward.
+ *
+ * We turn the characters into a scatter-gather list, add it to the
+ * output queue and then kick the Host.  Then we sit here waiting for
+ * it to finish: inefficient in theory, but in practice
+ * implementations will do it immediately (lguest's Launcher does).
+ */
+static int put_chars(u32 vtermno, const char *buf, int count)
+{
+       struct port *port;
+
+       if (unlikely(early_put_chars))
+               return early_put_chars(vtermno, buf, count);
+
+       port = find_port_by_vtermno(vtermno);
+       if (!port)
+               return -EPIPE;
+
+       return send_buf(port, (void *)buf, count, false);
+}
+
+/*
+ * get_chars() is the callback from the hvc_console infrastructure
+ * when an interrupt is received.
+ *
+ * We call out to fill_readbuf that gets us the required data from the
+ * buffers that are queued up.
+ */
+static int get_chars(u32 vtermno, char *buf, int count)
+{
+       struct port *port;
+
+       /* If we've not set up the port yet, we have no input to give. */
+       if (unlikely(early_put_chars))
+               return 0;
+
+       port = find_port_by_vtermno(vtermno);
+       if (!port)
+               return -EPIPE;
+
+       /* If we don't have an input queue yet, we can't get input. */
+       BUG_ON(!port->in_vq);
+
+       return fill_readbuf(port, buf, count, false);
+}
+
+static void resize_console(struct port *port)
+{
+       struct virtio_device *vdev;
+
+       /* The port could have been hot-unplugged */
+       if (!port || !is_console_port(port))
+               return;
+
+       vdev = port->portdev->vdev;
+       if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE))
+               hvc_resize(port->cons.hvc, port->cons.ws);
+}
+
+/* We set the configuration at this point, since we now have a tty */
+static int notifier_add_vio(struct hvc_struct *hp, int data)
+{
+       struct port *port;
+
+       port = find_port_by_vtermno(hp->vtermno);
+       if (!port)
+               return -EINVAL;
+
+       hp->irq_requested = 1;
+       resize_console(port);
+
+       return 0;
+}
+
+static void notifier_del_vio(struct hvc_struct *hp, int data)
+{
+       hp->irq_requested = 0;
+}
+
+/* The operations for console ports. */
+static const struct hv_ops hv_ops = {
+       .get_chars = get_chars,
+       .put_chars = put_chars,
+       .notifier_add = notifier_add_vio,
+       .notifier_del = notifier_del_vio,
+       .notifier_hangup = notifier_del_vio,
+};
+
+/*
+ * Console drivers are initialized very early so boot messages can go
+ * out, so we do things slightly differently from the generic virtio
+ * initialization of the net and block drivers.
+ *
+ * At this stage, the console is output-only.  It's too early to set
+ * up a virtqueue, so we let the drivers do some boutique early-output
+ * thing.
+ */
+int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int))
+{
+       early_put_chars = put_chars;
+       return hvc_instantiate(0, 0, &hv_ops);
+}
+
+int init_port_console(struct port *port)
+{
+       int ret;
+
+       /*
+        * The Host's telling us this port is a console port.  Hook it
+        * up with an hvc console.
+        *
+        * To set up and manage our virtual console, we call
+        * hvc_alloc().
+        *
+        * The first argument of hvc_alloc() is the virtual console
+        * number.  The second argument is the parameter for the
+        * notification mechanism (like irq number).  We currently
+        * leave this as zero, virtqueues have implicit notifications.
+        *
+        * The third argument is a "struct hv_ops" containing the
+        * put_chars() get_chars(), notifier_add() and notifier_del()
+        * pointers.  The final argument is the output buffer size: we
+        * can do any size, so we put PAGE_SIZE here.
+        */
+       port->cons.vtermno = pdrvdata.next_vtermno;
+
+       port->cons.hvc = hvc_alloc(port->cons.vtermno, 0, &hv_ops, PAGE_SIZE);
+       if (IS_ERR(port->cons.hvc)) {
+               ret = PTR_ERR(port->cons.hvc);
+               dev_err(port->dev,
+                       "error %d allocating hvc for port\n", ret);
+               port->cons.hvc = NULL;
+               return ret;
+       }
+       spin_lock_irq(&pdrvdata_lock);
+       pdrvdata.next_vtermno++;
+       list_add_tail(&port->cons.list, &pdrvdata.consoles);
+       spin_unlock_irq(&pdrvdata_lock);
+       port->guest_connected = true;
+
+       /*
+        * Start using the new console output if this is the first
+        * console to come up.
+        */
+       if (early_put_chars)
+               early_put_chars = NULL;
+
+       /* Notify host of port being opened */
+       send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
+
+       return 0;
+}
+
+static ssize_t show_port_name(struct device *dev,
+                             struct device_attribute *attr, char *buffer)
+{
+       struct port *port;
+
+       port = dev_get_drvdata(dev);
+
+       return sprintf(buffer, "%s\n", port->name);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, show_port_name, NULL);
+
+static struct attribute *port_sysfs_entries[] = {
+       &dev_attr_name.attr,
+       NULL
+};
+
+static struct attribute_group port_attribute_group = {
+       .name = NULL,           /* put in device directory */
+       .attrs = port_sysfs_entries,
+};
+
+static int debugfs_open(struct inode *inode, struct file *filp)
+{
+       filp->private_data = inode->i_private;
+       return 0;
+}
+
+static ssize_t debugfs_read(struct file *filp, char __user *ubuf,
+                           size_t count, loff_t *offp)
+{
+       struct port *port;
+       char *buf;
+       ssize_t ret, out_offset, out_count;
+
+       out_count = 1024;
+       buf = kmalloc(out_count, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       port = filp->private_data;
+       out_offset = 0;
+       out_offset += snprintf(buf + out_offset, out_count,
+                              "name: %s\n", port->name ? port->name : "");
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "guest_connected: %d\n", port->guest_connected);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "host_connected: %d\n", port->host_connected);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "outvq_full: %d\n", port->outvq_full);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "is_console: %s\n",
+                              is_console_port(port) ? "yes" : "no");
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "console_vtermno: %u\n", port->cons.vtermno);
+
+       ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset);
+       kfree(buf);
+       return ret;
+}
+
+static const struct file_operations port_debugfs_ops = {
+       .owner = THIS_MODULE,
+       .open  = debugfs_open,
+       .read  = debugfs_read,
+};
+
+static void set_console_size(struct port *port, u16 rows, u16 cols)
+{
+       if (!port || !is_console_port(port))
+               return;
+
+       port->cons.ws.ws_row = rows;
+       port->cons.ws.ws_col = cols;
+}
+
+static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock)
+{
+       struct port_buffer *buf;
+       unsigned int nr_added_bufs;
+       int ret;
+
+       nr_added_bufs = 0;
+       do {
+               buf = alloc_buf(PAGE_SIZE);
+               if (!buf)
+                       break;
+
+               spin_lock_irq(lock);
+               ret = add_inbuf(vq, buf);
+               if (ret < 0) {
+                       spin_unlock_irq(lock);
+                       free_buf(buf);
+                       break;
+               }
+               nr_added_bufs++;
+               spin_unlock_irq(lock);
+       } while (ret > 0);
+
+       return nr_added_bufs;
+}
+
+static void send_sigio_to_port(struct port *port)
+{
+       if (port->async_queue && port->guest_connected)
+               kill_fasync(&port->async_queue, SIGIO, POLL_OUT);
+}
+
+static int add_port(struct ports_device *portdev, u32 id)
+{
+       char debugfs_name[16];
+       struct port *port;
+       struct port_buffer *buf;
+       dev_t devt;
+       unsigned int nr_added_bufs;
+       int err;
+
+       port = kmalloc(sizeof(*port), GFP_KERNEL);
+       if (!port) {
+               err = -ENOMEM;
+               goto fail;
+       }
+       kref_init(&port->kref);
+
+       port->portdev = portdev;
+       port->id = id;
+
+       port->name = NULL;
+       port->inbuf = NULL;
+       port->cons.hvc = NULL;
+       port->async_queue = NULL;
+
+       port->cons.ws.ws_row = port->cons.ws.ws_col = 0;
+
+       port->host_connected = port->guest_connected = false;
+
+       port->outvq_full = false;
+
+       port->in_vq = portdev->in_vqs[port->id];
+       port->out_vq = portdev->out_vqs[port->id];
+
+       port->cdev = cdev_alloc();
+       if (!port->cdev) {
+               dev_err(&port->portdev->vdev->dev, "Error allocating cdev\n");
+               err = -ENOMEM;
+               goto free_port;
+       }
+       port->cdev->ops = &port_fops;
+
+       devt = MKDEV(portdev->chr_major, id);
+       err = cdev_add(port->cdev, devt, 1);
+       if (err < 0) {
+               dev_err(&port->portdev->vdev->dev,
+                       "Error %d adding cdev for port %u\n", err, id);
+               goto free_cdev;
+       }
+       port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev,
+                                 devt, port, "vport%up%u",
+                                 port->portdev->drv_index, id);
+       if (IS_ERR(port->dev)) {
+               err = PTR_ERR(port->dev);
+               dev_err(&port->portdev->vdev->dev,
+                       "Error %d creating device for port %u\n",
+                       err, id);
+               goto free_cdev;
+       }
+
+       spin_lock_init(&port->inbuf_lock);
+       spin_lock_init(&port->outvq_lock);
+       init_waitqueue_head(&port->waitqueue);
+
+       /* Fill the in_vq with buffers so the host can send us data. */
+       nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock);
+       if (!nr_added_bufs) {
+               dev_err(port->dev, "Error allocating inbufs\n");
+               err = -ENOMEM;
+               goto free_device;
+       }
+
+       /*
+        * If we're not using multiport support, this has to be a console port
+        */
+       if (!use_multiport(port->portdev)) {
+               err = init_port_console(port);
+               if (err)
+                       goto free_inbufs;
+       }
+
+       spin_lock_irq(&portdev->ports_lock);
+       list_add_tail(&port->list, &port->portdev->ports);
+       spin_unlock_irq(&portdev->ports_lock);
+
+       /*
+        * Tell the Host we're set so that it can send us various
+        * configuration parameters for this port (eg, port name,
+        * caching, whether this is a console port, etc.)
+        */
+       send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
+
+       if (pdrvdata.debugfs_dir) {
+               /*
+                * Finally, create the debugfs file that we can use to
+                * inspect a port's state at any time
+                */
+               sprintf(debugfs_name, "vport%up%u",
+                       port->portdev->drv_index, id);
+               port->debugfs_file = debugfs_create_file(debugfs_name, 0444,
+                                                        pdrvdata.debugfs_dir,
+                                                        port,
+                                                        &port_debugfs_ops);
+       }
+       return 0;
+
+free_inbufs:
+       while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
+               free_buf(buf);
+free_device:
+       device_destroy(pdrvdata.class, port->dev->devt);
+free_cdev:
+       cdev_del(port->cdev);
+free_port:
+       kfree(port);
+fail:
+       /* The host might want to notify management sw about port add failure */
+       __send_control_msg(portdev, id, VIRTIO_CONSOLE_PORT_READY, 0);
+       return err;
+}
+
+/* No users remain, remove all port-specific data. */
+static void remove_port(struct kref *kref)
+{
+       struct port *port;
+
+       port = container_of(kref, struct port, kref);
+
+       sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
+       device_destroy(pdrvdata.class, port->dev->devt);
+       cdev_del(port->cdev);
+
+       kfree(port->name);
+
+       debugfs_remove(port->debugfs_file);
+
+       kfree(port);
+}
+
+/*
+ * Port got unplugged.  Remove port from portdev's list and drop the
+ * kref reference.  If no userspace has this port opened, it will
+ * result in immediate removal the port.
+ */
+static void unplug_port(struct port *port)
+{
+       struct port_buffer *buf;
+
+       spin_lock_irq(&port->portdev->ports_lock);
+       list_del(&port->list);
+       spin_unlock_irq(&port->portdev->ports_lock);
+
+       if (port->guest_connected) {
+               port->guest_connected = false;
+               port->host_connected = false;
+               wake_up_interruptible(&port->waitqueue);
+
+               /* Let the app know the port is going down. */
+               send_sigio_to_port(port);
+       }
+
+       if (is_console_port(port)) {
+               spin_lock_irq(&pdrvdata_lock);
+               list_del(&port->cons.list);
+               spin_unlock_irq(&pdrvdata_lock);
+#if 0
+               /*
+                * hvc_remove() not called as removing one hvc port
+                * results in other hvc ports getting frozen.
+                *
+                * Once this is resolved in hvc, this functionality
+                * will be enabled.  Till that is done, the -EPIPE
+                * return from get_chars() above will help
+                * hvc_console.c to clean up on ports we remove here.
+                */
+               hvc_remove(port->cons.hvc);
+#endif
+       }
+
+       /* Remove unused data this port might have received. */
+       discard_port_data(port);
+
+       reclaim_consumed_buffers(port);
+
+       /* Remove buffers we queued up for the Host to send us data in. */
+       while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
+               free_buf(buf);
+
+       /*
+        * We should just assume the device itself has gone off --
+        * else a close on an open port later will try to send out a
+        * control message.
+        */
+       port->portdev = NULL;
+
+       /*
+        * Locks around here are not necessary - a port can't be
+        * opened after we removed the port struct from ports_list
+        * above.
+        */
+       kref_put(&port->kref, remove_port);
+}
+
+/* Any private messages that the Host and Guest want to share */
+static void handle_control_message(struct ports_device *portdev,
+                                  struct port_buffer *buf)
+{
+       struct virtio_console_control *cpkt;
+       struct port *port;
+       size_t name_size;
+       int err;
+
+       cpkt = (struct virtio_console_control *)(buf->buf + buf->offset);
+
+       port = find_port_by_id(portdev, cpkt->id);
+       if (!port && cpkt->event != VIRTIO_CONSOLE_PORT_ADD) {
+               /* No valid header at start of buffer.  Drop it. */
+               dev_dbg(&portdev->vdev->dev,
+                       "Invalid index %u in control packet\n", cpkt->id);
+               return;
+       }
+
+       switch (cpkt->event) {
+       case VIRTIO_CONSOLE_PORT_ADD:
+               if (port) {
+                       dev_dbg(&portdev->vdev->dev,
+                               "Port %u already added\n", port->id);
+                       send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
+                       break;
+               }
+               if (cpkt->id >= portdev->config.max_nr_ports) {
+                       dev_warn(&portdev->vdev->dev,
+                               "Request for adding port with out-of-bound id %u, max. supported id: %u\n",
+                               cpkt->id, portdev->config.max_nr_ports - 1);
+                       break;
+               }
+               add_port(portdev, cpkt->id);
+               break;
+       case VIRTIO_CONSOLE_PORT_REMOVE:
+               unplug_port(port);
+               break;
+       case VIRTIO_CONSOLE_CONSOLE_PORT:
+               if (!cpkt->value)
+                       break;
+               if (is_console_port(port))
+                       break;
+
+               init_port_console(port);
+               /*
+                * Could remove the port here in case init fails - but
+                * have to notify the host first.
+                */
+               break;
+       case VIRTIO_CONSOLE_RESIZE: {
+               struct {
+                       __u16 rows;
+                       __u16 cols;
+               } size;
+
+               if (!is_console_port(port))
+                       break;
+
+               memcpy(&size, buf->buf + buf->offset + sizeof(*cpkt),
+                      sizeof(size));
+               set_console_size(port, size.rows, size.cols);
+
+               port->cons.hvc->irq_requested = 1;
+               resize_console(port);
+               break;
+       }
+       case VIRTIO_CONSOLE_PORT_OPEN:
+               port->host_connected = cpkt->value;
+               wake_up_interruptible(&port->waitqueue);
+               /*
+                * If the host port got closed and the host had any
+                * unconsumed buffers, we'll be able to reclaim them
+                * now.
+                */
+               spin_lock_irq(&port->outvq_lock);
+               reclaim_consumed_buffers(port);
+               spin_unlock_irq(&port->outvq_lock);
+
+               /*
+                * If the guest is connected, it'll be interested in
+                * knowing the host connection state changed.
+                */
+               send_sigio_to_port(port);
+               break;
+       case VIRTIO_CONSOLE_PORT_NAME:
+               /*
+                * Skip the size of the header and the cpkt to get the size
+                * of the name that was sent
+                */
+               name_size = buf->len - buf->offset - sizeof(*cpkt) + 1;
+
+               port->name = kmalloc(name_size, GFP_KERNEL);
+               if (!port->name) {
+                       dev_err(port->dev,
+                               "Not enough space to store port name\n");
+                       break;
+               }
+               strncpy(port->name, buf->buf + buf->offset + sizeof(*cpkt),
+                       name_size - 1);
+               port->name[name_size - 1] = 0;
+
+               /*
+                * Since we only have one sysfs attribute, 'name',
+                * create it only if we have a name for the port.
+                */
+               err = sysfs_create_group(&port->dev->kobj,
+                                        &port_attribute_group);
+               if (err) {
+                       dev_err(port->dev,
+                               "Error %d creating sysfs device attributes\n",
+                               err);
+               } else {
+                       /*
+                        * Generate a udev event so that appropriate
+                        * symlinks can be created based on udev
+                        * rules.
+                        */
+                       kobject_uevent(&port->dev->kobj, KOBJ_CHANGE);
+               }
+               break;
+       }
+}
+
+static void control_work_handler(struct work_struct *work)
+{
+       struct ports_device *portdev;
+       struct virtqueue *vq;
+       struct port_buffer *buf;
+       unsigned int len;
+
+       portdev = container_of(work, struct ports_device, control_work);
+       vq = portdev->c_ivq;
+
+       spin_lock(&portdev->cvq_lock);
+       while ((buf = virtqueue_get_buf(vq, &len))) {
+               spin_unlock(&portdev->cvq_lock);
+
+               buf->len = len;
+               buf->offset = 0;
+
+               handle_control_message(portdev, buf);
+
+               spin_lock(&portdev->cvq_lock);
+               if (add_inbuf(portdev->c_ivq, buf) < 0) {
+                       dev_warn(&portdev->vdev->dev,
+                                "Error adding buffer to queue\n");
+                       free_buf(buf);
+               }
+       }
+       spin_unlock(&portdev->cvq_lock);
+}
+
+static void out_intr(struct virtqueue *vq)
+{
+       struct port *port;
+
+       port = find_port_by_vq(vq->vdev->priv, vq);
+       if (!port)
+               return;
+
+       wake_up_interruptible(&port->waitqueue);
+}
+
+static void in_intr(struct virtqueue *vq)
+{
+       struct port *port;
+       unsigned long flags;
+
+       port = find_port_by_vq(vq->vdev->priv, vq);
+       if (!port)
+               return;
+
+       spin_lock_irqsave(&port->inbuf_lock, flags);
+       if (!port->inbuf)
+               port->inbuf = get_inbuf(port);
+
+       /*
+        * Don't queue up data when port is closed.  This condition
+        * can be reached when a console port is not yet connected (no
+        * tty is spawned) and the host sends out data to console
+        * ports.  For generic serial ports, the host won't
+        * (shouldn't) send data till the guest is connected.
+        */
+       if (!port->guest_connected)
+               discard_port_data(port);
+
+       spin_unlock_irqrestore(&port->inbuf_lock, flags);
+
+       wake_up_interruptible(&port->waitqueue);
+
+       /* Send a SIGIO indicating new data in case the process asked for it */
+       send_sigio_to_port(port);
+
+       if (is_console_port(port) && hvc_poll(port->cons.hvc))
+               hvc_kick();
+}
+
+static void control_intr(struct virtqueue *vq)
+{
+       struct ports_device *portdev;
+
+       portdev = vq->vdev->priv;
+       schedule_work(&portdev->control_work);
+}
+
+static void config_intr(struct virtio_device *vdev)
+{
+       struct ports_device *portdev;
+
+       portdev = vdev->priv;
+
+       if (!use_multiport(portdev)) {
+               struct port *port;
+               u16 rows, cols;
+
+               vdev->config->get(vdev,
+                                 offsetof(struct virtio_console_config, cols),
+                                 &cols, sizeof(u16));
+               vdev->config->get(vdev,
+                                 offsetof(struct virtio_console_config, rows),
+                                 &rows, sizeof(u16));
+
+               port = find_port_by_id(portdev, 0);
+               set_console_size(port, rows, cols);
+
+               /*
+                * We'll use this way of resizing only for legacy
+                * support.  For newer userspace
+                * (VIRTIO_CONSOLE_F_MULTPORT+), use control messages
+                * to indicate console size changes so that it can be
+                * done per-port.
+                */
+               resize_console(port);
+       }
+}
+
+static int init_vqs(struct ports_device *portdev)
+{
+       vq_callback_t **io_callbacks;
+       char **io_names;
+       struct virtqueue **vqs;
+       u32 i, j, nr_ports, nr_queues;
+       int err;
+
+       nr_ports = portdev->config.max_nr_ports;
+       nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2;
+
+       vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL);
+       io_callbacks = kmalloc(nr_queues * sizeof(vq_callback_t *), GFP_KERNEL);
+       io_names = kmalloc(nr_queues * sizeof(char *), GFP_KERNEL);
+       portdev->in_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
+                                 GFP_KERNEL);
+       portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
+                                  GFP_KERNEL);
+       if (!vqs || !io_callbacks || !io_names || !portdev->in_vqs ||
+                       !portdev->out_vqs) {
+               err = -ENOMEM;
+               goto free;
+       }
+
+       /*
+        * For backward compat (newer host but older guest), the host
+        * spawns a console port first and also inits the vqs for port
+        * 0 before others.
+        */
+       j = 0;
+       io_callbacks[j] = in_intr;
+       io_callbacks[j + 1] = out_intr;
+       io_names[j] = "input";
+       io_names[j + 1] = "output";
+       j += 2;
+
+       if (use_multiport(portdev)) {
+               io_callbacks[j] = control_intr;
+               io_callbacks[j + 1] = NULL;
+               io_names[j] = "control-i";
+               io_names[j + 1] = "control-o";
+
+               for (i = 1; i < nr_ports; i++) {
+                       j += 2;
+                       io_callbacks[j] = in_intr;
+                       io_callbacks[j + 1] = out_intr;
+                       io_names[j] = "input";
+                       io_names[j + 1] = "output";
+               }
+       }
+       /* Find the queues. */
+       err = portdev->vdev->config->find_vqs(portdev->vdev, nr_queues, vqs,
+                                             io_callbacks,
+                                             (const char **)io_names);
+       if (err)
+               goto free;
+
+       j = 0;
+       portdev->in_vqs[0] = vqs[0];
+       portdev->out_vqs[0] = vqs[1];
+       j += 2;
+       if (use_multiport(portdev)) {
+               portdev->c_ivq = vqs[j];
+               portdev->c_ovq = vqs[j + 1];
+
+               for (i = 1; i < nr_ports; i++) {
+                       j += 2;
+                       portdev->in_vqs[i] = vqs[j];
+                       portdev->out_vqs[i] = vqs[j + 1];
+               }
+       }
+       kfree(io_names);
+       kfree(io_callbacks);
+       kfree(vqs);
+
+       return 0;
+
+free:
+       kfree(portdev->out_vqs);
+       kfree(portdev->in_vqs);
+       kfree(io_names);
+       kfree(io_callbacks);
+       kfree(vqs);
+
+       return err;
+}
+
+static const struct file_operations portdev_fops = {
+       .owner = THIS_MODULE,
+};
+
+/*
+ * Once we're further in boot, we get probed like any other virtio
+ * device.
+ *
+ * If the host also supports multiple console ports, we check the
+ * config space to see how many ports the host has spawned.  We
+ * initialize each port found.
+ */
+static int __devinit virtcons_probe(struct virtio_device *vdev)
+{
+       struct ports_device *portdev;
+       int err;
+       bool multiport;
+
+       portdev = kmalloc(sizeof(*portdev), GFP_KERNEL);
+       if (!portdev) {
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       /* Attach this portdev to this virtio_device, and vice-versa. */
+       portdev->vdev = vdev;
+       vdev->priv = portdev;
+
+       spin_lock_irq(&pdrvdata_lock);
+       portdev->drv_index = pdrvdata.index++;
+       spin_unlock_irq(&pdrvdata_lock);
+
+       portdev->chr_major = register_chrdev(0, "virtio-portsdev",
+                                            &portdev_fops);
+       if (portdev->chr_major < 0) {
+               dev_err(&vdev->dev,
+                       "Error %d registering chrdev for device %u\n",
+                       portdev->chr_major, portdev->drv_index);
+               err = portdev->chr_major;
+               goto free;
+       }
+
+       multiport = false;
+       portdev->config.max_nr_ports = 1;
+       if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT)) {
+               multiport = true;
+               vdev->features[0] |= 1 << VIRTIO_CONSOLE_F_MULTIPORT;
+
+               vdev->config->get(vdev, offsetof(struct virtio_console_config,
+                                                max_nr_ports),
+                                 &portdev->config.max_nr_ports,
+                                 sizeof(portdev->config.max_nr_ports));
+       }
+
+       /* Let the Host know we support multiple ports.*/
+       vdev->config->finalize_features(vdev);
+
+       err = init_vqs(portdev);
+       if (err < 0) {
+               dev_err(&vdev->dev, "Error %d initializing vqs\n", err);
+               goto free_chrdev;
+       }
+
+       spin_lock_init(&portdev->ports_lock);
+       INIT_LIST_HEAD(&portdev->ports);
+
+       if (multiport) {
+               unsigned int nr_added_bufs;
+
+               spin_lock_init(&portdev->cvq_lock);
+               INIT_WORK(&portdev->control_work, &control_work_handler);
+
+               nr_added_bufs = fill_queue(portdev->c_ivq, &portdev->cvq_lock);
+               if (!nr_added_bufs) {
+                       dev_err(&vdev->dev,
+                               "Error allocating buffers for control queue\n");
+                       err = -ENOMEM;
+                       goto free_vqs;
+               }
+       } else {
+               /*
+                * For backward compatibility: Create a console port
+                * if we're running on older host.
+                */
+               add_port(portdev, 0);
+       }
+
+       spin_lock_irq(&pdrvdata_lock);
+       list_add_tail(&portdev->list, &pdrvdata.portdevs);
+       spin_unlock_irq(&pdrvdata_lock);
+
+       __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
+                          VIRTIO_CONSOLE_DEVICE_READY, 1);
+       return 0;
+
+free_vqs:
+       /* The host might want to notify mgmt sw about device add failure */
+       __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
+                          VIRTIO_CONSOLE_DEVICE_READY, 0);
+       vdev->config->del_vqs(vdev);
+       kfree(portdev->in_vqs);
+       kfree(portdev->out_vqs);
+free_chrdev:
+       unregister_chrdev(portdev->chr_major, "virtio-portsdev");
+free:
+       kfree(portdev);
+fail:
+       return err;
+}
+
+static void virtcons_remove(struct virtio_device *vdev)
+{
+       struct ports_device *portdev;
+       struct port *port, *port2;
+
+       portdev = vdev->priv;
+
+       spin_lock_irq(&pdrvdata_lock);
+       list_del(&portdev->list);
+       spin_unlock_irq(&pdrvdata_lock);
+
+       /* Disable interrupts for vqs */
+       vdev->config->reset(vdev);
+       /* Finish up work that's lined up */
+       cancel_work_sync(&portdev->control_work);
+
+       list_for_each_entry_safe(port, port2, &portdev->ports, list)
+               unplug_port(port);
+
+       unregister_chrdev(portdev->chr_major, "virtio-portsdev");
+
+       /*
+        * When yanking out a device, we immediately lose the
+        * (device-side) queues.  So there's no point in keeping the
+        * guest side around till we drop our final reference.  This
+        * also means that any ports which are in an open state will
+        * have to just stop using the port, as the vqs are going
+        * away.
+        */
+       if (use_multiport(portdev)) {
+               struct port_buffer *buf;
+               unsigned int len;
+
+               while ((buf = virtqueue_get_buf(portdev->c_ivq, &len)))
+                       free_buf(buf);
+
+               while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq)))
+                       free_buf(buf);
+       }
+
+       vdev->config->del_vqs(vdev);
+       kfree(portdev->in_vqs);
+       kfree(portdev->out_vqs);
+
+       kfree(portdev);
+}
+
+static struct virtio_device_id id_table[] = {
+       { VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID },
+       { 0 },
+};
+
+static unsigned int features[] = {
+       VIRTIO_CONSOLE_F_SIZE,
+       VIRTIO_CONSOLE_F_MULTIPORT,
+};
+
+static struct virtio_driver virtio_console = {
+       .feature_table = features,
+       .feature_table_size = ARRAY_SIZE(features),
+       .driver.name =  KBUILD_MODNAME,
+       .driver.owner = THIS_MODULE,
+       .id_table =     id_table,
+       .probe =        virtcons_probe,
+       .remove =       virtcons_remove,
+       .config_changed = config_intr,
+};
+
+static int __init init(void)
+{
+       int err;
+
+       pdrvdata.class = class_create(THIS_MODULE, "virtio-ports");
+       if (IS_ERR(pdrvdata.class)) {
+               err = PTR_ERR(pdrvdata.class);
+               pr_err("Error %d creating virtio-ports class\n", err);
+               return err;
+       }
+
+       pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL);
+       if (!pdrvdata.debugfs_dir) {
+               pr_warning("Error %ld creating debugfs dir for virtio-ports\n",
+                          PTR_ERR(pdrvdata.debugfs_dir));
+       }
+       INIT_LIST_HEAD(&pdrvdata.consoles);
+       INIT_LIST_HEAD(&pdrvdata.portdevs);
+
+       return register_virtio_driver(&virtio_console);
+}
+
+static void __exit fini(void)
+{
+       unregister_virtio_driver(&virtio_console);
+
+       class_destroy(pdrvdata.class);
+       if (pdrvdata.debugfs_dir)
+               debugfs_remove_recursive(pdrvdata.debugfs_dir);
+}
+module_init(init);
+module_exit(fini);
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_DESCRIPTION("Virtio console driver");
+MODULE_LICENSE("GPL");
index 01b886e..79c47e8 100644 (file)
@@ -196,9 +196,9 @@ static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
        clkevt.clkevt.min_delta_ns = clockevent_delta2ns(1, &clkevt.clkevt) + 1;
        clkevt.clkevt.cpumask = cpumask_of(0);
 
-       setup_irq(irq, &tc_irqaction);
-
        clockevents_register_device(&clkevt.clkevt);
+
+       setup_irq(irq, &tc_irqaction);
 }
 
 #else /* !CONFIG_GENERIC_CLOCKEVENTS */
index 1109f68..5cb4d09 100644 (file)
@@ -1919,8 +1919,10 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
 
        ret = sysdev_driver_register(&cpu_sysdev_class,
                                        &cpufreq_sysdev_driver);
+       if (ret)
+               goto err_null_driver;
 
-       if ((!ret) && !(cpufreq_driver->flags & CPUFREQ_STICKY)) {
+       if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) {
                int i;
                ret = -ENODEV;
 
@@ -1935,21 +1937,22 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
                if (ret) {
                        dprintk("no CPU initialized for driver %s\n",
                                                        driver_data->name);
-                       sysdev_driver_unregister(&cpu_sysdev_class,
-                                               &cpufreq_sysdev_driver);
-
-                       spin_lock_irqsave(&cpufreq_driver_lock, flags);
-                       cpufreq_driver = NULL;
-                       spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+                       goto err_sysdev_unreg;
                }
        }
 
-       if (!ret) {
-               register_hotcpu_notifier(&cpufreq_cpu_notifier);
-               dprintk("driver %s up and running\n", driver_data->name);
-               cpufreq_debug_enable_ratelimit();
-       }
+       register_hotcpu_notifier(&cpufreq_cpu_notifier);
+       dprintk("driver %s up and running\n", driver_data->name);
+       cpufreq_debug_enable_ratelimit();
 
+       return 0;
+err_sysdev_unreg:
+       sysdev_driver_unregister(&cpu_sysdev_class,
+                       &cpufreq_sysdev_driver);
+err_null_driver:
+       spin_lock_irqsave(&cpufreq_driver_lock, flags);
+       cpufreq_driver = NULL;
+       spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
        return ret;
 }
 EXPORT_SYMBOL_GPL(cpufreq_register_driver);
index 526bfbf..94284c8 100644 (file)
@@ -81,8 +81,6 @@ static unsigned int dbs_enable;       /* number of CPUs using this policy */
  */
 static DEFINE_MUTEX(dbs_mutex);
 
-static struct workqueue_struct *kconservative_wq;
-
 static struct dbs_tuners {
        unsigned int sampling_rate;
        unsigned int sampling_down_factor;
@@ -560,7 +558,7 @@ static void do_dbs_timer(struct work_struct *work)
 
        dbs_check_cpu(dbs_info);
 
-       queue_delayed_work_on(cpu, kconservative_wq, &dbs_info->work, delay);
+       schedule_delayed_work_on(cpu, &dbs_info->work, delay);
        mutex_unlock(&dbs_info->timer_mutex);
 }
 
@@ -572,8 +570,7 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
 
        dbs_info->enable = 1;
        INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
-       queue_delayed_work_on(dbs_info->cpu, kconservative_wq, &dbs_info->work,
-                               delay);
+       schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work, delay);
 }
 
 static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
@@ -716,25 +713,12 @@ struct cpufreq_governor cpufreq_gov_conservative = {
 
 static int __init cpufreq_gov_dbs_init(void)
 {
-       int err;
-
-       kconservative_wq = create_workqueue("kconservative");
-       if (!kconservative_wq) {
-               printk(KERN_ERR "Creation of kconservative failed\n");
-               return -EFAULT;
-       }
-
-       err = cpufreq_register_governor(&cpufreq_gov_conservative);
-       if (err)
-               destroy_workqueue(kconservative_wq);
-
-       return err;
+       return cpufreq_register_governor(&cpufreq_gov_conservative);
 }
 
 static void __exit cpufreq_gov_dbs_exit(void)
 {
        cpufreq_unregister_governor(&cpufreq_gov_conservative);
-       destroy_workqueue(kconservative_wq);
 }
 
 
index c631f27..58aa85e 100644 (file)
@@ -104,8 +104,6 @@ static unsigned int dbs_enable;     /* number of CPUs using this policy */
  */
 static DEFINE_MUTEX(dbs_mutex);
 
-static struct workqueue_struct *kondemand_wq;
-
 static struct dbs_tuners {
        unsigned int sampling_rate;
        unsigned int up_threshold;
@@ -667,7 +665,7 @@ static void do_dbs_timer(struct work_struct *work)
                __cpufreq_driver_target(dbs_info->cur_policy,
                        dbs_info->freq_lo, CPUFREQ_RELATION_H);
        }
-       queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay);
+       schedule_delayed_work_on(cpu, &dbs_info->work, delay);
        mutex_unlock(&dbs_info->timer_mutex);
 }
 
@@ -681,8 +679,7 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
 
        dbs_info->sample_type = DBS_NORMAL_SAMPLE;
        INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
-       queue_delayed_work_on(dbs_info->cpu, kondemand_wq, &dbs_info->work,
-               delay);
+       schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work, delay);
 }
 
 static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
@@ -814,7 +811,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
 
 static int __init cpufreq_gov_dbs_init(void)
 {
-       int err;
        cputime64_t wall;
        u64 idle_time;
        int cpu = get_cpu();
@@ -838,22 +834,12 @@ static int __init cpufreq_gov_dbs_init(void)
                        MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10);
        }
 
-       kondemand_wq = create_workqueue("kondemand");
-       if (!kondemand_wq) {
-               printk(KERN_ERR "Creation of kondemand failed\n");
-               return -EFAULT;
-       }
-       err = cpufreq_register_governor(&cpufreq_gov_ondemand);
-       if (err)
-               destroy_workqueue(kondemand_wq);
-
-       return err;
+       return cpufreq_register_governor(&cpufreq_gov_ondemand);
 }
 
 static void __exit cpufreq_gov_dbs_exit(void)
 {
        cpufreq_unregister_governor(&cpufreq_gov_ondemand);
-       destroy_workqueue(kondemand_wq);
 }
 
 
index 297f48b..07bca49 100644 (file)
@@ -79,6 +79,7 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 #include <linux/dmapool.h>
 #include <linux/dmaengine.h>
 #include <linux/amba/bus.h>
@@ -235,16 +236,19 @@ static void pl08x_start_txd(struct pl08x_dma_chan *plchan,
 }
 
 /*
- * Overall DMAC remains enabled always.
+ * Pause the channel by setting the HALT bit.
  *
- * Disabling individual channels could lose data.
+ * For M->P transfers, pause the DMAC first and then stop the peripheral -
+ * the FIFO can only drain if the peripheral is still requesting data.
+ * (note: this can still timeout if the DMAC FIFO never drains of data.)
  *
- * Disable the peripheral DMA after disabling the DMAC in order to allow
- * the DMAC FIFO to drain, and hence allow the channel to show inactive
+ * For P->M transfers, disable the peripheral first to stop it filling
+ * the DMAC FIFO, and then pause the DMAC.
  */
 static void pl08x_pause_phy_chan(struct pl08x_phy_chan *ch)
 {
        u32 val;
+       int timeout;
 
        /* Set the HALT bit and wait for the FIFO to drain */
        val = readl(ch->base + PL080_CH_CONFIG);
@@ -252,8 +256,13 @@ static void pl08x_pause_phy_chan(struct pl08x_phy_chan *ch)
        writel(val, ch->base + PL080_CH_CONFIG);
 
        /* Wait for channel inactive */
-       while (pl08x_phy_channel_busy(ch))
-               cpu_relax();
+       for (timeout = 1000; timeout; timeout--) {
+               if (!pl08x_phy_channel_busy(ch))
+                       break;
+               udelay(1);
+       }
+       if (pl08x_phy_channel_busy(ch))
+               pr_err("pl08x: channel%u timeout waiting for pause\n", ch->id);
 }
 
 static void pl08x_resume_phy_chan(struct pl08x_phy_chan *ch)
@@ -267,19 +276,24 @@ static void pl08x_resume_phy_chan(struct pl08x_phy_chan *ch)
 }
 
 
-/* Stops the channel */
-static void pl08x_stop_phy_chan(struct pl08x_phy_chan *ch)
+/*
+ * pl08x_terminate_phy_chan() stops the channel, clears the FIFO and
+ * clears any pending interrupt status.  This should not be used for
+ * an on-going transfer, but as a method of shutting down a channel
+ * (eg, when it's no longer used) or terminating a transfer.
+ */
+static void pl08x_terminate_phy_chan(struct pl08x_driver_data *pl08x,
+       struct pl08x_phy_chan *ch)
 {
-       u32 val;
+       u32 val = readl(ch->base + PL080_CH_CONFIG);
 
-       pl08x_pause_phy_chan(ch);
+       val &= ~(PL080_CONFIG_ENABLE | PL080_CONFIG_ERR_IRQ_MASK |
+                PL080_CONFIG_TC_IRQ_MASK);
 
-       /* Disable channel */
-       val = readl(ch->base + PL080_CH_CONFIG);
-       val &= ~PL080_CONFIG_ENABLE;
-       val &= ~PL080_CONFIG_ERR_IRQ_MASK;
-       val &= ~PL080_CONFIG_TC_IRQ_MASK;
        writel(val, ch->base + PL080_CH_CONFIG);
+
+       writel(1 << ch->id, pl08x->base + PL080_ERR_CLEAR);
+       writel(1 << ch->id, pl08x->base + PL080_TC_CLEAR);
 }
 
 static inline u32 get_bytes_in_cctl(u32 cctl)
@@ -404,13 +418,12 @@ static inline void pl08x_put_phy_channel(struct pl08x_driver_data *pl08x,
 {
        unsigned long flags;
 
+       spin_lock_irqsave(&ch->lock, flags);
+
        /* Stop the channel and clear its interrupts */
-       pl08x_stop_phy_chan(ch);
-       writel((1 << ch->id), pl08x->base + PL080_ERR_CLEAR);
-       writel((1 << ch->id), pl08x->base + PL080_TC_CLEAR);
+       pl08x_terminate_phy_chan(pl08x, ch);
 
        /* Mark it as free */
-       spin_lock_irqsave(&ch->lock, flags);
        ch->serving = NULL;
        spin_unlock_irqrestore(&ch->lock, flags);
 }
@@ -1449,7 +1462,7 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
                plchan->state = PL08X_CHAN_IDLE;
 
                if (plchan->phychan) {
-                       pl08x_stop_phy_chan(plchan->phychan);
+                       pl08x_terminate_phy_chan(pl08x, plchan->phychan);
 
                        /*
                         * Mark physical channel as free and free any slave
index e53d438..e18eaab 100644 (file)
@@ -49,6 +49,7 @@ struct imxdma_channel {
 
 struct imxdma_engine {
        struct device                   *dev;
+       struct device_dma_parameters    dma_parms;
        struct dma_device               dma_device;
        struct imxdma_channel           channel[MAX_DMA_CHANNELS];
 };
@@ -242,6 +243,21 @@ static struct dma_async_tx_descriptor *imxdma_prep_slave_sg(
        else
                dmamode = DMA_MODE_WRITE;
 
+       switch (imxdmac->word_size) {
+       case DMA_SLAVE_BUSWIDTH_4_BYTES:
+               if (sgl->length & 3 || sgl->dma_address & 3)
+                       return NULL;
+               break;
+       case DMA_SLAVE_BUSWIDTH_2_BYTES:
+               if (sgl->length & 1 || sgl->dma_address & 1)
+                       return NULL;
+               break;
+       case DMA_SLAVE_BUSWIDTH_1_BYTE:
+               break;
+       default:
+               return NULL;
+       }
+
        ret = imx_dma_setup_sg(imxdmac->imxdma_channel, sgl, sg_len,
                 dma_length, imxdmac->per_address, dmamode);
        if (ret)
@@ -329,6 +345,9 @@ static int __init imxdma_probe(struct platform_device *pdev)
 
        INIT_LIST_HEAD(&imxdma->dma_device.channels);
 
+       dma_cap_set(DMA_SLAVE, imxdma->dma_device.cap_mask);
+       dma_cap_set(DMA_CYCLIC, imxdma->dma_device.cap_mask);
+
        /* Initialize channel parameters */
        for (i = 0; i < MAX_DMA_CHANNELS; i++) {
                struct imxdma_channel *imxdmac = &imxdma->channel[i];
@@ -346,11 +365,7 @@ static int __init imxdma_probe(struct platform_device *pdev)
                imxdmac->imxdma = imxdma;
                spin_lock_init(&imxdmac->lock);
 
-               dma_cap_set(DMA_SLAVE, imxdma->dma_device.cap_mask);
-               dma_cap_set(DMA_CYCLIC, imxdma->dma_device.cap_mask);
-
                imxdmac->chan.device = &imxdma->dma_device;
-               imxdmac->chan.chan_id = i;
                imxdmac->channel = i;
 
                /* Add the channel to the DMAC list */
@@ -370,6 +385,9 @@ static int __init imxdma_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, imxdma);
 
+       imxdma->dma_device.dev->dma_parms = &imxdma->dma_parms;
+       dma_set_max_seg_size(imxdma->dma_device.dev, 0xffffff);
+
        ret = dma_async_device_register(&imxdma->dma_device);
        if (ret) {
                dev_err(&pdev->dev, "unable to register\n");
index d5a5d4d..b6d1455 100644 (file)
@@ -230,7 +230,7 @@ struct sdma_engine;
  * struct sdma_channel - housekeeping for a SDMA channel
  *
  * @sdma               pointer to the SDMA engine for this channel
- * @channel            the channel number, matches dmaengine chan_id
+ * @channel            the channel number, matches dmaengine chan_id + 1
  * @direction          transfer type. Needed for setting SDMA script
  * @peripheral_type    Peripheral type. Needed for setting SDMA script
  * @event_id0          aka dma request line
@@ -301,6 +301,7 @@ struct sdma_firmware_header {
 
 struct sdma_engine {
        struct device                   *dev;
+       struct device_dma_parameters    dma_parms;
        struct sdma_channel             channel[MAX_DMA_CHANNELS];
        struct sdma_channel_control     *channel_control;
        void __iomem                    *regs;
@@ -449,7 +450,7 @@ static void sdma_handle_channel_loop(struct sdma_channel *sdmac)
                if (bd->mode.status & BD_RROR)
                        sdmac->status = DMA_ERROR;
                else
-                       sdmac->status = DMA_SUCCESS;
+                       sdmac->status = DMA_IN_PROGRESS;
 
                bd->mode.status |= BD_DONE;
                sdmac->buf_tail++;
@@ -770,15 +771,15 @@ static void sdma_enable_channel(struct sdma_engine *sdma, int channel)
        __raw_writel(1 << channel, sdma->regs + SDMA_H_START);
 }
 
-static dma_cookie_t sdma_assign_cookie(struct sdma_channel *sdma)
+static dma_cookie_t sdma_assign_cookie(struct sdma_channel *sdmac)
 {
-       dma_cookie_t cookie = sdma->chan.cookie;
+       dma_cookie_t cookie = sdmac->chan.cookie;
 
        if (++cookie < 0)
                cookie = 1;
 
-       sdma->chan.cookie = cookie;
-       sdma->desc.cookie = cookie;
+       sdmac->chan.cookie = cookie;
+       sdmac->desc.cookie = cookie;
 
        return cookie;
 }
@@ -798,7 +799,7 @@ static dma_cookie_t sdma_tx_submit(struct dma_async_tx_descriptor *tx)
 
        cookie = sdma_assign_cookie(sdmac);
 
-       sdma_enable_channel(sdma, tx->chan->chan_id);
+       sdma_enable_channel(sdma, sdmac->channel);
 
        spin_unlock_irq(&sdmac->lock);
 
@@ -811,10 +812,6 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan)
        struct imx_dma_data *data = chan->private;
        int prio, ret;
 
-       /* No need to execute this for internal channel 0 */
-       if (chan->chan_id == 0)
-               return 0;
-
        if (!data)
                return -EINVAL;
 
@@ -879,7 +876,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
        struct sdma_channel *sdmac = to_sdma_chan(chan);
        struct sdma_engine *sdma = sdmac->sdma;
        int ret, i, count;
-       int channel = chan->chan_id;
+       int channel = sdmac->channel;
        struct scatterlist *sg;
 
        if (sdmac->status == DMA_IN_PROGRESS)
@@ -924,22 +921,33 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
                        ret =  -EINVAL;
                        goto err_out;
                }
-               if (sdmac->word_size == DMA_SLAVE_BUSWIDTH_4_BYTES)
+
+               switch (sdmac->word_size) {
+               case DMA_SLAVE_BUSWIDTH_4_BYTES:
                        bd->mode.command = 0;
-               else
-                       bd->mode.command = sdmac->word_size;
+                       if (count & 3 || sg->dma_address & 3)
+                               return NULL;
+                       break;
+               case DMA_SLAVE_BUSWIDTH_2_BYTES:
+                       bd->mode.command = 2;
+                       if (count & 1 || sg->dma_address & 1)
+                               return NULL;
+                       break;
+               case DMA_SLAVE_BUSWIDTH_1_BYTE:
+                       bd->mode.command = 1;
+                       break;
+               default:
+                       return NULL;
+               }
 
                param = BD_DONE | BD_EXTD | BD_CONT;
 
-               if (sdmac->flags & IMX_DMA_SG_LOOP) {
+               if (i + 1 == sg_len) {
                        param |= BD_INTR;
-                       if (i + 1 == sg_len)
-                               param |= BD_WRAP;
+                       param |= BD_LAST;
+                       param &= ~BD_CONT;
                }
 
-               if (i + 1 == sg_len)
-                       param |= BD_INTR;
-
                dev_dbg(sdma->dev, "entry %d: count: %d dma: 0x%08x %s%s\n",
                                i, count, sg->dma_address,
                                param & BD_WRAP ? "wrap" : "",
@@ -953,6 +961,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
 
        return &sdmac->desc;
 err_out:
+       sdmac->status = DMA_ERROR;
        return NULL;
 }
 
@@ -963,7 +972,7 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
        struct sdma_channel *sdmac = to_sdma_chan(chan);
        struct sdma_engine *sdma = sdmac->sdma;
        int num_periods = buf_len / period_len;
-       int channel = chan->chan_id;
+       int channel = sdmac->channel;
        int ret, i = 0, buf = 0;
 
        dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel);
@@ -1066,14 +1075,12 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan,
 {
        struct sdma_channel *sdmac = to_sdma_chan(chan);
        dma_cookie_t last_used;
-       enum dma_status ret;
 
        last_used = chan->cookie;
 
-       ret = dma_async_is_complete(cookie, sdmac->last_completed, last_used);
        dma_set_tx_state(txstate, sdmac->last_completed, last_used, 0);
 
-       return ret;
+       return sdmac->status;
 }
 
 static void sdma_issue_pending(struct dma_chan *chan)
@@ -1135,7 +1142,7 @@ static int __init sdma_get_firmware(struct sdma_engine *sdma,
        /* download the RAM image for SDMA */
        sdma_load_script(sdma, ram_code,
                        header->ram_code_size,
-                       sdma->script_addrs->ram_code_start_addr);
+                       addr->ram_code_start_addr);
        clk_disable(sdma->clk);
 
        sdma_add_scripts(sdma, addr);
@@ -1237,7 +1244,6 @@ static int __init sdma_probe(struct platform_device *pdev)
        struct resource *iores;
        struct sdma_platform_data *pdata = pdev->dev.platform_data;
        int i;
-       dma_cap_mask_t mask;
        struct sdma_engine *sdma;
 
        sdma = kzalloc(sizeof(*sdma), GFP_KERNEL);
@@ -1280,6 +1286,9 @@ static int __init sdma_probe(struct platform_device *pdev)
 
        sdma->version = pdata->sdma_version;
 
+       dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask);
+       dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask);
+
        INIT_LIST_HEAD(&sdma->dma_device.channels);
        /* Initialize channel parameters */
        for (i = 0; i < MAX_DMA_CHANNELS; i++) {
@@ -1288,15 +1297,17 @@ static int __init sdma_probe(struct platform_device *pdev)
                sdmac->sdma = sdma;
                spin_lock_init(&sdmac->lock);
 
-               dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask);
-               dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask);
-
                sdmac->chan.device = &sdma->dma_device;
-               sdmac->chan.chan_id = i;
                sdmac->channel = i;
 
-               /* Add the channel to the DMAC list */
-               list_add_tail(&sdmac->chan.device_node, &sdma->dma_device.channels);
+               /*
+                * Add the channel to the DMAC list. Do not add channel 0 though
+                * because we need it internally in the SDMA driver. This also means
+                * that channel 0 in dmaengine counting matches sdma channel 1.
+                */
+               if (i)
+                       list_add_tail(&sdmac->chan.device_node,
+                                       &sdma->dma_device.channels);
        }
 
        ret = sdma_init(sdma);
@@ -1317,6 +1328,8 @@ static int __init sdma_probe(struct platform_device *pdev)
        sdma->dma_device.device_prep_dma_cyclic = sdma_prep_dma_cyclic;
        sdma->dma_device.device_control = sdma_control;
        sdma->dma_device.device_issue_pending = sdma_issue_pending;
+       sdma->dma_device.dev->dma_parms = &sdma->dma_parms;
+       dma_set_max_seg_size(sdma->dma_device.dev, 65535);
 
        ret = dma_async_device_register(&sdma->dma_device);
        if (ret) {
@@ -1324,13 +1337,6 @@ static int __init sdma_probe(struct platform_device *pdev)
                goto err_init;
        }
 
-       /* request channel 0. This is an internal control channel
-        * to the SDMA engine and not available to clients.
-        */
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-       dma_request_channel(mask, NULL, NULL);
-
        dev_info(sdma->dev, "initialized\n");
 
        return 0;
@@ -1348,7 +1354,7 @@ err_clk:
 err_request_region:
 err_irq:
        kfree(sdma);
-       return 0;
+       return ret;
 }
 
 static int __exit sdma_remove(struct platform_device *pdev)
index cb26ee9..c1a125e 100644 (file)
@@ -1145,29 +1145,6 @@ static int ipu_disable_channel(struct idmac *idmac, struct idmac_channel *ichan,
        reg = idmac_read_icreg(ipu, IDMAC_CHA_EN);
        idmac_write_icreg(ipu, reg & ~chan_mask, IDMAC_CHA_EN);
 
-       /*
-        * Problem (observed with channel DMAIC_7): after enabling the channel
-        * and initialising buffers, there comes an interrupt with current still
-        * pointing at buffer 0, whereas it should use buffer 0 first and only
-        * generate an interrupt when it is done, then current should already
-        * point to buffer 1. This spurious interrupt also comes on channel
-        * DMASDC_0. With DMAIC_7 normally, is we just leave the ISR after the
-        * first interrupt, there comes the second with current correctly
-        * pointing to buffer 1 this time. But sometimes this second interrupt
-        * doesn't come and the channel hangs. Clearing BUFx_RDY when disabling
-        * the channel seems to prevent the channel from hanging, but it doesn't
-        * prevent the spurious interrupt. This might also be unsafe. Think
-        * about the IDMAC controller trying to switch to a buffer, when we
-        * clear the ready bit, and re-enable it a moment later.
-        */
-       reg = idmac_read_ipureg(ipu, IPU_CHA_BUF0_RDY);
-       idmac_write_ipureg(ipu, 0, IPU_CHA_BUF0_RDY);
-       idmac_write_ipureg(ipu, reg & ~(1UL << channel), IPU_CHA_BUF0_RDY);
-
-       reg = idmac_read_ipureg(ipu, IPU_CHA_BUF1_RDY);
-       idmac_write_ipureg(ipu, 0, IPU_CHA_BUF1_RDY);
-       idmac_write_ipureg(ipu, reg & ~(1UL << channel), IPU_CHA_BUF1_RDY);
-
        spin_unlock_irqrestore(&ipu->lock, flags);
 
        return 0;
@@ -1246,33 +1223,6 @@ static irqreturn_t idmac_interrupt(int irq, void *dev_id)
 
        /* Other interrupts do not interfere with this channel */
        spin_lock(&ichan->lock);
-       if (unlikely(chan_id != IDMAC_SDC_0 && chan_id != IDMAC_SDC_1 &&
-                    ((curbuf >> chan_id) & 1) == ichan->active_buffer &&
-                    !list_is_last(ichan->queue.next, &ichan->queue))) {
-               int i = 100;
-
-               /* This doesn't help. See comment in ipu_disable_channel() */
-               while (--i) {
-                       curbuf = idmac_read_ipureg(&ipu_data, IPU_CHA_CUR_BUF);
-                       if (((curbuf >> chan_id) & 1) != ichan->active_buffer)
-                               break;
-                       cpu_relax();
-               }
-
-               if (!i) {
-                       spin_unlock(&ichan->lock);
-                       dev_dbg(dev,
-                               "IRQ on active buffer on channel %x, active "
-                               "%d, ready %x, %x, current %x!\n", chan_id,
-                               ichan->active_buffer, ready0, ready1, curbuf);
-                       return IRQ_NONE;
-               } else
-                       dev_dbg(dev,
-                               "Buffer deactivated on channel %x, active "
-                               "%d, ready %x, %x, current %x, rest %d!\n", chan_id,
-                               ichan->active_buffer, ready0, ready1, curbuf, i);
-       }
-
        if (unlikely((ichan->active_buffer && (ready1 >> chan_id) & 1) ||
                     (!ichan->active_buffer && (ready0 >> chan_id) & 1)
                     )) {
index 4a5ecc5..23e0355 100644 (file)
@@ -826,8 +826,6 @@ static void amd64_dump_dramcfg_low(u32 dclr, int chan)
 /* Display and decode various NB registers for debug purposes. */
 static void amd64_dump_misc_regs(struct amd64_pvt *pvt)
 {
-       int ganged;
-
        debugf1("F3xE8 (NB Cap): 0x%08x\n", pvt->nbcap);
 
        debugf1("  NB two channel DRAM capable: %s\n",
@@ -851,28 +849,19 @@ static void amd64_dump_misc_regs(struct amd64_pvt *pvt)
        debugf1("  DramHoleValid: %s\n",
                (pvt->dhar & DHAR_VALID) ? "yes" : "no");
 
+       amd64_debug_display_dimm_sizes(0, pvt);
+
        /* everything below this point is Fam10h and above */
-       if (boot_cpu_data.x86 == 0xf) {
-               amd64_debug_display_dimm_sizes(0, pvt);
+       if (boot_cpu_data.x86 == 0xf)
                return;
-       }
+
+       amd64_debug_display_dimm_sizes(1, pvt);
 
        amd64_info("using %s syndromes.\n", ((pvt->syn_type == 8) ? "x8" : "x4"));
 
        /* Only if NOT ganged does dclr1 have valid info */
        if (!dct_ganging_enabled(pvt))
                amd64_dump_dramcfg_low(pvt->dclr1, 1);
-
-       /*
-        * Determine if ganged and then dump memory sizes for first controller,
-        * and if NOT ganged dump info for 2nd controller.
-        */
-       ganged = dct_ganging_enabled(pvt);
-
-       amd64_debug_display_dimm_sizes(0, pvt);
-
-       if (!ganged)
-               amd64_debug_display_dimm_sizes(1, pvt);
 }
 
 /* Read in both of DBAM registers */
@@ -1644,11 +1633,10 @@ static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt)
                       WARN_ON(ctrl != 0);
        }
 
-       debugf1("F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n",
-               ctrl, ctrl ? pvt->dbam1 : pvt->dbam0);
+       dbam = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dbam1 : pvt->dbam0;
+       dcsb = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dcsb1 : pvt->dcsb0;
 
-       dbam = ctrl ? pvt->dbam1 : pvt->dbam0;
-       dcsb = ctrl ? pvt->dcsb1 : pvt->dcsb0;
+       debugf1("F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n", ctrl, dbam);
 
        edac_printk(KERN_DEBUG, EDAC_MC, "DCT%d chip selects:\n", ctrl);
 
index e28e416..bcb1126 100644 (file)
@@ -378,10 +378,17 @@ static void __init print_filtered(const char *info)
 
 static void __init dmi_dump_ids(void)
 {
+       const char *board;      /* Board Name is optional */
+
        printk(KERN_DEBUG "DMI: ");
-       print_filtered(dmi_get_system_info(DMI_BOARD_NAME));
-       printk(KERN_CONT "/");
+       print_filtered(dmi_get_system_info(DMI_SYS_VENDOR));
+       printk(KERN_CONT " ");
        print_filtered(dmi_get_system_info(DMI_PRODUCT_NAME));
+       board = dmi_get_system_info(DMI_BOARD_NAME);
+       if (board) {
+               printk(KERN_CONT "/");
+               print_filtered(board);
+       }
        printk(KERN_CONT ", BIOS ");
        print_filtered(dmi_get_system_info(DMI_BIOS_VERSION));
        printk(KERN_CONT " ");
index d81cc74..54d70a4 100644 (file)
@@ -187,7 +187,7 @@ MODULE_DEVICE_TABLE(pci, lnw_gpio_ids);
 
 static void lnw_irq_handler(unsigned irq, struct irq_desc *desc)
 {
-       struct lnw_gpio *lnw = (struct lnw_gpio *)get_irq_data(irq);
+       struct lnw_gpio *lnw = get_irq_data(irq);
        u32 base, gpio;
        void __iomem *gedr;
        u32 gedr_v;
@@ -206,7 +206,12 @@ static void lnw_irq_handler(unsigned irq, struct irq_desc *desc)
                /* clear the edge detect status bit */
                writel(gedr_v, gedr);
        }
-       desc->chip->eoi(irq);
+
+       if (desc->chip->irq_eoi)
+               desc->chip->irq_eoi(irq_get_irq_data(irq));
+       else
+               dev_warn(lnw->chip.dev, "missing EOI handler for irq %d\n", irq);
+
 }
 
 static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
index cead8e6..7f6f01a 100644 (file)
@@ -326,6 +326,7 @@ static DEFINE_PCI_DEVICE_TABLE(ioh_gpio_pcidev_id) = {
        { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x802E) },
        { 0, }
 };
+MODULE_DEVICE_TABLE(pci, ioh_gpio_pcidev_id);
 
 static struct pci_driver ioh_gpio_driver = {
        .name = "ml_ioh_gpio",
index a261972..b473429 100644 (file)
@@ -60,6 +60,7 @@ struct pca953x_chip {
        unsigned gpio_start;
        uint16_t reg_output;
        uint16_t reg_direction;
+       struct mutex i2c_lock;
 
 #ifdef CONFIG_GPIO_PCA953X_IRQ
        struct mutex irq_lock;
@@ -119,13 +120,17 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
 
        chip = container_of(gc, struct pca953x_chip, gpio_chip);
 
+       mutex_lock(&chip->i2c_lock);
        reg_val = chip->reg_direction | (1u << off);
        ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val);
        if (ret)
-               return ret;
+               goto exit;
 
        chip->reg_direction = reg_val;
-       return 0;
+       ret = 0;
+exit:
+       mutex_unlock(&chip->i2c_lock);
+       return ret;
 }
 
 static int pca953x_gpio_direction_output(struct gpio_chip *gc,
@@ -137,6 +142,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 
        chip = container_of(gc, struct pca953x_chip, gpio_chip);
 
+       mutex_lock(&chip->i2c_lock);
        /* set output level */
        if (val)
                reg_val = chip->reg_output | (1u << off);
@@ -145,7 +151,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 
        ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val);
        if (ret)
-               return ret;
+               goto exit;
 
        chip->reg_output = reg_val;
 
@@ -153,10 +159,13 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
        reg_val = chip->reg_direction & ~(1u << off);
        ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val);
        if (ret)
-               return ret;
+               goto exit;
 
        chip->reg_direction = reg_val;
-       return 0;
+       ret = 0;
+exit:
+       mutex_unlock(&chip->i2c_lock);
+       return ret;
 }
 
 static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
@@ -167,7 +176,9 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
 
        chip = container_of(gc, struct pca953x_chip, gpio_chip);
 
+       mutex_lock(&chip->i2c_lock);
        ret = pca953x_read_reg(chip, PCA953X_INPUT, &reg_val);
+       mutex_unlock(&chip->i2c_lock);
        if (ret < 0) {
                /* NOTE:  diagnostic already emitted; that's all we should
                 * do unless gpio_*_value_cansleep() calls become different
@@ -187,6 +198,7 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
 
        chip = container_of(gc, struct pca953x_chip, gpio_chip);
 
+       mutex_lock(&chip->i2c_lock);
        if (val)
                reg_val = chip->reg_output | (1u << off);
        else
@@ -194,9 +206,11 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
 
        ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val);
        if (ret)
-               return;
+               goto exit;
 
        chip->reg_output = reg_val;
+exit:
+       mutex_unlock(&chip->i2c_lock);
 }
 
 static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
@@ -517,6 +531,8 @@ static int __devinit pca953x_probe(struct i2c_client *client,
 
        chip->names = pdata->names;
 
+       mutex_init(&chip->i2c_lock);
+
        /* initialize cached registers from their original values.
         * we can't share this chip with another i2c master.
         */
index 0eba0a7..2c6af87 100644 (file)
@@ -286,6 +286,7 @@ static DEFINE_PCI_DEVICE_TABLE(pch_gpio_pcidev_id) = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8803) },
        { 0, }
 };
+MODULE_DEVICE_TABLE(pci, pch_gpio_pcidev_id);
 
 static struct pci_driver pch_gpio_driver = {
        .name = "pch_gpio",
index 2baa670..654faa8 100644 (file)
@@ -2674,3 +2674,23 @@ out:
        mutex_unlock(&dev->mode_config.mutex);
        return ret;
 }
+
+void drm_mode_config_reset(struct drm_device *dev)
+{
+       struct drm_crtc *crtc;
+       struct drm_encoder *encoder;
+       struct drm_connector *connector;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+               if (crtc->funcs->reset)
+                       crtc->funcs->reset(crtc);
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+               if (encoder->funcs->reset)
+                       encoder->funcs->reset(encoder);
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+               if (connector->funcs->reset)
+                       connector->funcs->reset(connector);
+}
+EXPORT_SYMBOL(drm_mode_config_reset);
index 952b3d4..9236965 100644 (file)
@@ -343,13 +343,12 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
        struct drm_encoder *encoder;
        bool ret = true;
 
-       adjusted_mode = drm_mode_duplicate(dev, mode);
-
        crtc->enabled = drm_helper_crtc_in_use(crtc);
-
        if (!crtc->enabled)
                return true;
 
+       adjusted_mode = drm_mode_duplicate(dev, mode);
+
        saved_hwmode = crtc->hwmode;
        saved_mode = crtc->mode;
        saved_x = crtc->x;
@@ -437,10 +436,9 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
         */
        drm_calc_timestamping_constants(crtc);
 
-       /* XXX free adjustedmode */
-       drm_mode_destroy(dev, adjusted_mode);
        /* FIXME: add subpixel order */
 done:
+       drm_mode_destroy(dev, adjusted_mode);
        if (!ret) {
                crtc->hwmode = saved_hwmode;
                crtc->mode = saved_mode;
@@ -497,14 +495,17 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
 
        crtc_funcs = set->crtc->helper_private;
 
+       if (!set->mode)
+               set->fb = NULL;
+
        if (set->fb) {
                DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n",
                                set->crtc->base.id, set->fb->base.id,
                                (int)set->num_connectors, set->x, set->y);
        } else {
-               DRM_DEBUG_KMS("[CRTC:%d] [NOFB] #connectors=%d (x y) (%i %i)\n",
-                               set->crtc->base.id, (int)set->num_connectors,
-                               set->x, set->y);
+               DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id);
+               set->mode = NULL;
+               set->num_connectors = 0;
        }
 
        dev = set->crtc->dev;
@@ -649,8 +650,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                mode_changed = true;
 
        if (mode_changed) {
-               set->crtc->enabled = (set->mode != NULL);
-               if (set->mode != NULL) {
+               set->crtc->enabled = drm_helper_crtc_in_use(set->crtc);
+               if (set->crtc->enabled) {
                        DRM_DEBUG_KMS("attempting to set mode from"
                                        " userspace\n");
                        drm_mode_debug_printmodeline(set->mode);
@@ -665,6 +666,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                                ret = -EINVAL;
                                goto fail;
                        }
+                       DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
+                       for (i = 0; i < set->num_connectors; i++) {
+                               DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
+                                             drm_get_connector_name(set->connectors[i]));
+                               set->connectors[i]->dpms = DRM_MODE_DPMS_ON;
+                       }
                }
                drm_helper_disable_unused_functions(dev);
        } else if (fb_changed) {
@@ -681,12 +688,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                        goto fail;
                }
        }
-       DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
-       for (i = 0; i < set->num_connectors; i++) {
-               DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
-                             drm_get_connector_name(set->connectors[i]));
-               set->connectors[i]->dpms = DRM_MODE_DPMS_ON;
-       }
 
        kfree(save_connectors);
        kfree(save_encoders);
index 6977a1c..f73ef43 100644 (file)
@@ -672,7 +672,7 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
        struct drm_crtc_helper_funcs *crtc_funcs;
        u16 *red, *green, *blue, *transp;
        struct drm_crtc *crtc;
-       int i, rc = 0;
+       int i, j, rc = 0;
        int start;
 
        for (i = 0; i < fb_helper->crtc_count; i++) {
@@ -685,7 +685,7 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
                transp = cmap->transp;
                start = cmap->start;
 
-               for (i = 0; i < cmap->len; i++) {
+               for (j = 0; j < cmap->len; j++) {
                        u16 hred, hgreen, hblue, htransp = 0xffff;
 
                        hred = *red++;
index 3cdbaf3..be9a9c0 100644 (file)
@@ -283,17 +283,18 @@ int drm_vma_info(struct seq_file *m, void *data)
 #endif
 
        mutex_lock(&dev->struct_mutex);
-       seq_printf(m, "vma use count: %d, high_memory = %p, 0x%08llx\n",
+       seq_printf(m, "vma use count: %d, high_memory = %pK, 0x%pK\n",
                   atomic_read(&dev->vma_count),
-                  high_memory, (u64)virt_to_phys(high_memory));
+                  high_memory, (void *)virt_to_phys(high_memory));
 
        list_for_each_entry(pt, &dev->vmalist, head) {
                vma = pt->vma;
                if (!vma)
                        continue;
                seq_printf(m,
-                          "\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000",
-                          pt->pid, vma->vm_start, vma->vm_end,
+                          "\n%5d 0x%pK-0x%pK %c%c%c%c%c%c 0x%08lx000",
+                          pt->pid,
+                          (void *)vma->vm_start, (void *)vma->vm_end,
                           vma->vm_flags & VM_READ ? 'r' : '-',
                           vma->vm_flags & VM_WRITE ? 'w' : '-',
                           vma->vm_flags & VM_EXEC ? 'x' : '-',
index 0054e95..28d1d3c 100644 (file)
@@ -164,8 +164,10 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
         * available. In that case we can't account for this and just
         * hope for the best.
         */
-       if ((vblrc > 0) && (abs(diff_ns) > 1000000))
+       if ((vblrc > 0) && (abs64(diff_ns) > 1000000)) {
                atomic_inc(&dev->_vblank_count[crtc]);
+               smp_mb__after_atomic_inc();
+       }
 
        /* Invalidate all timestamps while vblank irq's are off. */
        clear_vblank_timestamps(dev, crtc);
@@ -491,6 +493,12 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc)
        /* Dot clock in Hz: */
        dotclock = (u64) crtc->hwmode.clock * 1000;
 
+       /* Fields of interlaced scanout modes are only halve a frame duration.
+        * Double the dotclock to get halve the frame-/line-/pixelduration.
+        */
+       if (crtc->hwmode.flags & DRM_MODE_FLAG_INTERLACE)
+               dotclock *= 2;
+
        /* Valid dotclock? */
        if (dotclock > 0) {
                /* Convert scanline length in pixels and video dot clock to
@@ -603,14 +611,6 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
                return -EAGAIN;
        }
 
-       /* Don't know yet how to handle interlaced or
-        * double scan modes. Just no-op for now.
-        */
-       if (mode->flags & (DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLSCAN)) {
-               DRM_DEBUG("crtc %d: Noop due to unsupported mode.\n", crtc);
-               return -ENOTSUPP;
-       }
-
        /* Get current scanout position with system timestamp.
         * Repeat query up to DRM_TIMESTAMP_MAXRETRIES times
         * if single query takes longer than max_error nanoseconds.
@@ -858,10 +858,11 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
        if (rc) {
                tslot = atomic_read(&dev->_vblank_count[crtc]) + diff;
                vblanktimestamp(dev, crtc, tslot) = t_vblank;
-               smp_wmb();
        }
 
+       smp_mb__before_atomic_inc();
        atomic_add(diff, &dev->_vblank_count[crtc]);
+       smp_mb__after_atomic_inc();
 }
 
 /**
@@ -1011,7 +1012,8 @@ int drm_modeset_ctl(struct drm_device *dev, void *data,
                    struct drm_file *file_priv)
 {
        struct drm_modeset_ctl *modeset = data;
-       int crtc, ret = 0;
+       int ret = 0;
+       unsigned int crtc;
 
        /* If drm_vblank_init() hasn't been called yet, just no-op */
        if (!dev->num_crtcs)
@@ -1250,7 +1252,7 @@ void drm_handle_vblank_events(struct drm_device *dev, int crtc)
  * Drivers should call this routine in their vblank interrupt handlers to
  * update the vblank counter and send any signals that may be pending.
  */
-void drm_handle_vblank(struct drm_device *dev, int crtc)
+bool drm_handle_vblank(struct drm_device *dev, int crtc)
 {
        u32 vblcount;
        s64 diff_ns;
@@ -1258,7 +1260,7 @@ void drm_handle_vblank(struct drm_device *dev, int crtc)
        unsigned long irqflags;
 
        if (!dev->num_crtcs)
-               return;
+               return false;
 
        /* Need timestamp lock to prevent concurrent execution with
         * vblank enable/disable, as this would cause inconsistent
@@ -1269,7 +1271,7 @@ void drm_handle_vblank(struct drm_device *dev, int crtc)
        /* Vblank irq handling disabled. Nothing to do. */
        if (!dev->vblank_enabled[crtc]) {
                spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
-               return;
+               return false;
        }
 
        /* Fetch corresponding timestamp for this vblank interval from
@@ -1293,15 +1295,16 @@ void drm_handle_vblank(struct drm_device *dev, int crtc)
         * e.g., due to spurious vblank interrupts. We need to
         * ignore those for accounting.
         */
-       if (abs(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS) {
+       if (abs64(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS) {
                /* Store new timestamp in ringbuffer. */
                vblanktimestamp(dev, crtc, vblcount + 1) = tvblank;
-               smp_wmb();
 
                /* Increment cooked vblank count. This also atomically commits
                 * the timestamp computed above.
                 */
+               smp_mb__before_atomic_inc();
                atomic_inc(&dev->_vblank_count[crtc]);
+               smp_mb__after_atomic_inc();
        } else {
                DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n",
                          crtc, (int) diff_ns);
@@ -1311,5 +1314,6 @@ void drm_handle_vblank(struct drm_device *dev, int crtc)
        drm_handle_vblank_events(dev, crtc);
 
        spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
+       return true;
 }
 EXPORT_SYMBOL(drm_handle_vblank);
index 3601466..4ff9b6c 100644 (file)
@@ -865,7 +865,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
                int max_freq;
 
                /* RPSTAT1 is in the GT power well */
-               __gen6_force_wake_get(dev_priv);
+               __gen6_gt_force_wake_get(dev_priv);
 
                seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status);
                seq_printf(m, "RPSTAT1: 0x%08x\n", I915_READ(GEN6_RPSTAT1));
@@ -888,7 +888,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
                seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n",
                           max_freq * 100);
 
-               __gen6_force_wake_put(dev_priv);
+               __gen6_gt_force_wake_put(dev_priv);
        } else {
                seq_printf(m, "no P-state info available\n");
        }
index 17bd766..e33d9be 100644 (file)
@@ -1895,6 +1895,17 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        if (IS_GEN2(dev))
                dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(30));
 
+       /* 965GM sometimes incorrectly writes to hardware status page (HWS)
+        * using 32bit addressing, overwriting memory if HWS is located
+        * above 4GB.
+        *
+        * The documentation also mentions an issue with undefined
+        * behaviour if any general state is accessed within a page above 4GB,
+        * which also needs to be handled carefully.
+        */
+       if (IS_BROADWATER(dev) || IS_CRESTLINE(dev))
+               dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(32));
+
        mmio_bar = IS_GEN2(dev) ? 1 : 0;
        dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, 0);
        if (!dev_priv->regs) {
index 66796bb..22ec066 100644 (file)
@@ -46,6 +46,12 @@ module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);
 unsigned int i915_powersave = 1;
 module_param_named(powersave, i915_powersave, int, 0600);
 
+unsigned int i915_semaphores = 0;
+module_param_named(semaphores, i915_semaphores, int, 0600);
+
+unsigned int i915_enable_rc6 = 0;
+module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600);
+
 unsigned int i915_lvds_downclock = 0;
 module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
 
@@ -251,7 +257,7 @@ void intel_detect_pch (struct drm_device *dev)
        }
 }
 
-void __gen6_force_wake_get(struct drm_i915_private *dev_priv)
+void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
 {
        int count;
 
@@ -267,12 +273,22 @@ void __gen6_force_wake_get(struct drm_i915_private *dev_priv)
                udelay(10);
 }
 
-void __gen6_force_wake_put(struct drm_i915_private *dev_priv)
+void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
 {
        I915_WRITE_NOTRACE(FORCEWAKE, 0);
        POSTING_READ(FORCEWAKE);
 }
 
+void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
+{
+       int loop = 500;
+       u32 fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES);
+       while (fifo < 20 && loop--) {
+               udelay(10);
+               fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES);
+       }
+}
+
 static int i915_drm_freeze(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -354,12 +370,13 @@ static int i915_drm_thaw(struct drm_device *dev)
                error = i915_gem_init_ringbuffer(dev);
                mutex_unlock(&dev->struct_mutex);
 
+               drm_mode_config_reset(dev);
                drm_irq_install(dev);
 
                /* Resume the modeset for every activated CRTC */
                drm_helper_resume_force_mode(dev);
 
-               if (dev_priv->renderctx && dev_priv->pwrctx)
+               if (IS_IRONLAKE_M(dev))
                        ironlake_enable_rc6(dev);
        }
 
@@ -542,6 +559,7 @@ int i915_reset(struct drm_device *dev, u8 flags)
 
                mutex_unlock(&dev->struct_mutex);
                drm_irq_uninstall(dev);
+               drm_mode_config_reset(dev);
                drm_irq_install(dev);
                mutex_lock(&dev->struct_mutex);
        }
@@ -566,6 +584,14 @@ int i915_reset(struct drm_device *dev, u8 flags)
 static int __devinit
 i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
+       /* Only bind to function 0 of the device. Early generations
+        * used function 1 as a placeholder for multi-head. This causes
+        * us confusion instead, especially on the systems where both
+        * functions have the same PCI-ID!
+        */
+       if (PCI_FUNC(pdev->devfn))
+               return -ENODEV;
+
        return drm_get_pci_dev(pdev, ent, &driver);
 }
 
index a0149c6..456f404 100644 (file)
@@ -956,8 +956,10 @@ extern struct drm_ioctl_desc i915_ioctls[];
 extern int i915_max_ioctl;
 extern unsigned int i915_fbpercrtc;
 extern unsigned int i915_powersave;
+extern unsigned int i915_semaphores;
 extern unsigned int i915_lvds_downclock;
 extern unsigned int i915_panel_use_ssc;
+extern unsigned int i915_enable_rc6;
 
 extern int i915_suspend(struct drm_device *dev, pm_message_t state);
 extern int i915_resume(struct drm_device *dev);
@@ -1176,6 +1178,9 @@ void i915_gem_detach_phys_object(struct drm_device *dev,
 void i915_gem_free_all_phys_object(struct drm_device *dev);
 void i915_gem_release(struct drm_device *dev, struct drm_file *file);
 
+uint32_t
+i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj);
+
 /* i915_gem_gtt.c */
 void i915_gem_restore_gtt_mappings(struct drm_device *dev);
 int __must_check i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj);
@@ -1352,22 +1357,32 @@ __i915_write(64, q)
  * must be set to prevent GT core from power down and stale values being
  * returned.
  */
-void __gen6_force_wake_get(struct drm_i915_private *dev_priv);
-void __gen6_force_wake_put (struct drm_i915_private *dev_priv);
-static inline u32 i915_safe_read(struct drm_i915_private *dev_priv, u32 reg)
+void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv);
+void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv);
+void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
+
+static inline u32 i915_gt_read(struct drm_i915_private *dev_priv, u32 reg)
 {
        u32 val;
 
        if (dev_priv->info->gen >= 6) {
-               __gen6_force_wake_get(dev_priv);
+               __gen6_gt_force_wake_get(dev_priv);
                val = I915_READ(reg);
-               __gen6_force_wake_put(dev_priv);
+               __gen6_gt_force_wake_put(dev_priv);
        } else
                val = I915_READ(reg);
 
        return val;
 }
 
+static inline void i915_gt_write(struct drm_i915_private *dev_priv,
+                               u32 reg, u32 val)
+{
+       if (dev_priv->info->gen >= 6)
+               __gen6_gt_wait_for_fifo(dev_priv);
+       I915_WRITE(reg, val);
+}
+
 static inline void
 i915_write(struct drm_i915_private *dev_priv, u32 reg, u64 val, int len)
 {
index cf4f74c..36e66cc 100644 (file)
@@ -1398,7 +1398,7 @@ i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj)
  * Return the required GTT alignment for an object, only taking into account
  * unfenced tiled surface requirements.
  */
-static uint32_t
+uint32_t
 i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj)
 {
        struct drm_device *dev = obj->base.dev;
index d2f445e..50ab161 100644 (file)
@@ -772,8 +772,8 @@ i915_gem_execbuffer_sync_rings(struct drm_i915_gem_object *obj,
        if (from == NULL || to == from)
                return 0;
 
-       /* XXX gpu semaphores are currently causing hard hangs on SNB mobile */
-       if (INTEL_INFO(obj->base.dev)->gen < 6 || IS_MOBILE(obj->base.dev))
+       /* XXX gpu semaphores are implicated in various hard hangs on SNB */
+       if (INTEL_INFO(obj->base.dev)->gen < 6 || !i915_semaphores)
                return i915_gem_object_wait_rendering(obj, true);
 
        idx = intel_ring_sync_index(from, to);
index 22a32b9..d64843e 100644 (file)
@@ -349,14 +349,27 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
                        (obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end &&
                         i915_gem_object_fence_ok(obj, args->tiling_mode));
 
-               obj->tiling_changed = true;
-               obj->tiling_mode = args->tiling_mode;
-               obj->stride = args->stride;
+               /* Rebind if we need a change of alignment */
+               if (!obj->map_and_fenceable) {
+                       u32 unfenced_alignment =
+                               i915_gem_get_unfenced_gtt_alignment(obj);
+                       if (obj->gtt_offset & (unfenced_alignment - 1))
+                               ret = i915_gem_object_unbind(obj);
+               }
+
+               if (ret == 0) {
+                       obj->tiling_changed = true;
+                       obj->tiling_mode = args->tiling_mode;
+                       obj->stride = args->stride;
+               }
        }
+       /* we have to maintain this existing ABI... */
+       args->stride = obj->stride;
+       args->tiling_mode = obj->tiling_mode;
        drm_gem_object_unreference(&obj->base);
        mutex_unlock(&dev->struct_mutex);
 
-       return 0;
+       return ret;
 }
 
 /**
index 062f353..8a9e08b 100644 (file)
@@ -316,6 +316,8 @@ static void i915_hotplug_work_func(struct work_struct *work)
        struct drm_mode_config *mode_config = &dev->mode_config;
        struct intel_encoder *encoder;
 
+       DRM_DEBUG_KMS("running encoder hotplug functions\n");
+
        list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
                if (encoder->hot_plug)
                        encoder->hot_plug(encoder);
@@ -1196,18 +1198,18 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                                intel_finish_page_flip_plane(dev, 1);
                }
 
-               if (pipea_stats & vblank_status) {
+               if (pipea_stats & vblank_status &&
+                   drm_handle_vblank(dev, 0)) {
                        vblank++;
-                       drm_handle_vblank(dev, 0);
                        if (!dev_priv->flip_pending_is_done) {
                                i915_pageflip_stall_check(dev, 0);
                                intel_finish_page_flip(dev, 0);
                        }
                }
 
-               if (pipeb_stats & vblank_status) {
+               if (pipeb_stats & vblank_status &&
+                   drm_handle_vblank(dev, 1)) {
                        vblank++;
-                       drm_handle_vblank(dev, 1);
                        if (!dev_priv->flip_pending_is_done) {
                                i915_pageflip_stall_check(dev, 1);
                                intel_finish_page_flip(dev, 1);
@@ -1649,9 +1651,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        } else {
                hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG |
                               SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG;
-               hotplug_mask |= SDE_AUX_MASK | SDE_FDI_MASK | SDE_TRANS_MASK;
-               I915_WRITE(FDI_RXA_IMR, 0);
-               I915_WRITE(FDI_RXB_IMR, 0);
+               hotplug_mask |= SDE_AUX_MASK;
        }
 
        dev_priv->pch_irq_mask = ~hotplug_mask;
index 5cfc689..2abe240 100644 (file)
  *   address/value pairs. Don't overdue it, though, x <= 2^4 must hold!
  */
 #define MI_LOAD_REGISTER_IMM(x)        MI_INSTR(0x22, 2*x-1)
-#define MI_FLUSH_DW            MI_INSTR(0x26, 2) /* for GEN6 */
+#define MI_FLUSH_DW            MI_INSTR(0x26, 1) /* for GEN6 */
+#define   MI_INVALIDATE_TLB    (1<<18)
+#define   MI_INVALIDATE_BSD    (1<<7)
 #define MI_BATCH_BUFFER                MI_INSTR(0x30, 1)
 #define   MI_BATCH_NON_SECURE  (1)
 #define   MI_BATCH_NON_SECURE_I965 (1<<8)
 #define  FORCEWAKE                             0xA18C
 #define  FORCEWAKE_ACK                         0x130090
 
+#define  GT_FIFO_FREE_ENTRIES                  0x120008
+
 #define GEN6_RPNSWREQ                          0xA008
 #define   GEN6_TURBO_DISABLE                   (1<<31)
 #define   GEN6_FREQUENCY(x)                    ((x)<<25)
index 17035b8..8a77ff4 100644 (file)
@@ -535,6 +535,15 @@ static int intel_crt_set_property(struct drm_connector *connector,
        return 0;
 }
 
+static void intel_crt_reset(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct intel_crt *crt = intel_attached_crt(connector);
+
+       if (HAS_PCH_SPLIT(dev))
+               crt->force_hotplug_required = 1;
+}
+
 /*
  * Routines for controlling stuff on the analog port
  */
@@ -548,6 +557,7 @@ static const struct drm_encoder_helper_funcs intel_crt_helper_funcs = {
 };
 
 static const struct drm_connector_funcs intel_crt_connector_funcs = {
+       .reset = intel_crt_reset,
        .dpms = drm_helper_connector_dpms,
        .detect = intel_crt_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
index d7f237d..49fb54f 100644 (file)
@@ -1219,7 +1219,7 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev)
        u32 blt_ecoskpd;
 
        /* Make sure blitter notifies FBC of writes */
-       __gen6_force_wake_get(dev_priv);
+       __gen6_gt_force_wake_get(dev_priv);
        blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD);
        blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY <<
                GEN6_BLITTER_LOCK_SHIFT;
@@ -1230,7 +1230,7 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev)
                         GEN6_BLITTER_LOCK_SHIFT);
        I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
        POSTING_READ(GEN6_BLITTER_ECOSKPD);
-       __gen6_force_wake_put(dev_priv);
+       __gen6_gt_force_wake_put(dev_priv);
 }
 
 static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
@@ -1630,19 +1630,19 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                struct drm_i915_gem_object *obj = to_intel_framebuffer(old_fb)->obj;
 
                wait_event(dev_priv->pending_flip_queue,
+                          atomic_read(&dev_priv->mm.wedged) ||
                           atomic_read(&obj->pending_flip) == 0);
 
                /* Big Hammer, we also need to ensure that any pending
                 * MI_WAIT_FOR_EVENT inside a user batch buffer on the
                 * current scanout is retired before unpinning the old
                 * framebuffer.
+                *
+                * This should only fail upon a hung GPU, in which case we
+                * can safely continue.
                 */
                ret = i915_gem_object_flush_gpu(obj, false);
-               if (ret) {
-                       i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
-                       mutex_unlock(&dev->struct_mutex);
-                       return ret;
-               }
+               (void) ret;
        }
 
        ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y,
@@ -2045,6 +2045,31 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
                   atomic_read(&obj->pending_flip) == 0);
 }
 
+static bool intel_crtc_driving_pch(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct intel_encoder *encoder;
+
+       /*
+        * If there's a non-PCH eDP on this crtc, it must be DP_A, and that
+        * must be driven by its own crtc; no sharing is possible.
+        */
+       list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
+               if (encoder->base.crtc != crtc)
+                       continue;
+
+               switch (encoder->type) {
+               case INTEL_OUTPUT_EDP:
+                       if (!intel_encoder_is_pch_edp(&encoder->base))
+                               return false;
+                       continue;
+               }
+       }
+
+       return true;
+}
+
 static void ironlake_crtc_enable(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
@@ -2053,6 +2078,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
        u32 reg, temp;
+       bool is_pch_port = false;
 
        if (intel_crtc->active)
                return;
@@ -2066,7 +2092,56 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
                        I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN);
        }
 
-       ironlake_fdi_enable(crtc);
+       is_pch_port = intel_crtc_driving_pch(crtc);
+
+       if (is_pch_port)
+               ironlake_fdi_enable(crtc);
+       else {
+               /* disable CPU FDI tx and PCH FDI rx */
+               reg = FDI_TX_CTL(pipe);
+               temp = I915_READ(reg);
+               I915_WRITE(reg, temp & ~FDI_TX_ENABLE);
+               POSTING_READ(reg);
+
+               reg = FDI_RX_CTL(pipe);
+               temp = I915_READ(reg);
+               temp &= ~(0x7 << 16);
+               temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+               I915_WRITE(reg, temp & ~FDI_RX_ENABLE);
+
+               POSTING_READ(reg);
+               udelay(100);
+
+               /* Ironlake workaround, disable clock pointer after downing FDI */
+               if (HAS_PCH_IBX(dev))
+                       I915_WRITE(FDI_RX_CHICKEN(pipe),
+                                  I915_READ(FDI_RX_CHICKEN(pipe) &
+                                            ~FDI_RX_PHASE_SYNC_POINTER_ENABLE));
+
+               /* still set train pattern 1 */
+               reg = FDI_TX_CTL(pipe);
+               temp = I915_READ(reg);
+               temp &= ~FDI_LINK_TRAIN_NONE;
+               temp |= FDI_LINK_TRAIN_PATTERN_1;
+               I915_WRITE(reg, temp);
+
+               reg = FDI_RX_CTL(pipe);
+               temp = I915_READ(reg);
+               if (HAS_PCH_CPT(dev)) {
+                       temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+                       temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
+               } else {
+                       temp &= ~FDI_LINK_TRAIN_NONE;
+                       temp |= FDI_LINK_TRAIN_PATTERN_1;
+               }
+               /* BPC in FDI rx is consistent with that in PIPECONF */
+               temp &= ~(0x07 << 16);
+               temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+               I915_WRITE(reg, temp);
+
+               POSTING_READ(reg);
+               udelay(100);
+       }
 
        /* Enable panel fitting for LVDS */
        if (dev_priv->pch_pf_size &&
@@ -2100,6 +2175,10 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
                intel_flush_display_plane(dev, plane);
        }
 
+       /* Skip the PCH stuff if possible */
+       if (!is_pch_port)
+               goto done;
+
        /* For PCH output, training FDI link */
        if (IS_GEN6(dev))
                gen6_fdi_link_train(crtc);
@@ -2184,7 +2263,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        I915_WRITE(reg, temp | TRANS_ENABLE);
        if (wait_for(I915_READ(reg) & TRANS_STATE_ENABLE, 100))
                DRM_ERROR("failed to enable transcoder %d\n", pipe);
-
+done:
        intel_crtc_load_lut(crtc);
        intel_update_fbc(dev);
        intel_crtc_update_cursor(crtc, true);
@@ -5551,6 +5630,16 @@ cleanup_work:
        return ret;
 }
 
+static void intel_crtc_reset(struct drm_crtc *crtc)
+{
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+       /* Reset flags back to the 'unknown' status so that they
+        * will be correctly set on the initial modeset.
+        */
+       intel_crtc->dpms_mode = -1;
+}
+
 static struct drm_crtc_helper_funcs intel_helper_funcs = {
        .dpms = intel_crtc_dpms,
        .mode_fixup = intel_crtc_mode_fixup,
@@ -5562,6 +5651,7 @@ static struct drm_crtc_helper_funcs intel_helper_funcs = {
 };
 
 static const struct drm_crtc_funcs intel_crtc_funcs = {
+       .reset = intel_crtc_reset,
        .cursor_set = intel_crtc_cursor_set,
        .cursor_move = intel_crtc_cursor_move,
        .gamma_set = intel_crtc_gamma_set,
@@ -5652,8 +5742,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
        dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base;
        dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base;
 
-       intel_crtc->cursor_addr = 0;
-       intel_crtc->dpms_mode = -1;
+       intel_crtc_reset(&intel_crtc->base);
        intel_crtc->active = true; /* force the pipe off on setup_init_config */
 
        if (HAS_PCH_SPLIT(dev)) {
@@ -6193,7 +6282,7 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
         * userspace...
         */
        I915_WRITE(GEN6_RC_STATE, 0);
-       __gen6_force_wake_get(dev_priv);
+       __gen6_gt_force_wake_get(dev_priv);
 
        /* disable the counters and set deterministic thresholds */
        I915_WRITE(GEN6_RC_CONTROL, 0);
@@ -6291,7 +6380,7 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
        /* enable all PM interrupts */
        I915_WRITE(GEN6_PMINTRMSK, 0);
 
-       __gen6_force_wake_put(dev_priv);
+       __gen6_gt_force_wake_put(dev_priv);
 }
 
 void intel_enable_clock_gating(struct drm_device *dev)
@@ -6452,52 +6541,60 @@ void intel_enable_clock_gating(struct drm_device *dev)
        }
 }
 
-void intel_disable_clock_gating(struct drm_device *dev)
+static void ironlake_teardown_rc6(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (dev_priv->renderctx) {
-               struct drm_i915_gem_object *obj = dev_priv->renderctx;
-
-               I915_WRITE(CCID, 0);
-               POSTING_READ(CCID);
-
-               i915_gem_object_unpin(obj);
-               drm_gem_object_unreference(&obj->base);
+               i915_gem_object_unpin(dev_priv->renderctx);
+               drm_gem_object_unreference(&dev_priv->renderctx->base);
                dev_priv->renderctx = NULL;
        }
 
        if (dev_priv->pwrctx) {
-               struct drm_i915_gem_object *obj = dev_priv->pwrctx;
+               i915_gem_object_unpin(dev_priv->pwrctx);
+               drm_gem_object_unreference(&dev_priv->pwrctx->base);
+               dev_priv->pwrctx = NULL;
+       }
+}
+
+static void ironlake_disable_rc6(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (I915_READ(PWRCTXA)) {
+               /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */
+               I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT);
+               wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON),
+                        50);
 
                I915_WRITE(PWRCTXA, 0);
                POSTING_READ(PWRCTXA);
 
-               i915_gem_object_unpin(obj);
-               drm_gem_object_unreference(&obj->base);
-               dev_priv->pwrctx = NULL;
+               I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
+               POSTING_READ(RSTDBYCTL);
        }
+
+       ironlake_teardown_rc6(dev);
 }
 
-static void ironlake_disable_rc6(struct drm_device *dev)
+static int ironlake_setup_rc6(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */
-       I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT);
-       wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON),
-                10);
-       POSTING_READ(CCID);
-       I915_WRITE(PWRCTXA, 0);
-       POSTING_READ(PWRCTXA);
-       I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
-       POSTING_READ(RSTDBYCTL);
-       i915_gem_object_unpin(dev_priv->renderctx);
-       drm_gem_object_unreference(&dev_priv->renderctx->base);
-       dev_priv->renderctx = NULL;
-       i915_gem_object_unpin(dev_priv->pwrctx);
-       drm_gem_object_unreference(&dev_priv->pwrctx->base);
-       dev_priv->pwrctx = NULL;
+       if (dev_priv->renderctx == NULL)
+               dev_priv->renderctx = intel_alloc_context_page(dev);
+       if (!dev_priv->renderctx)
+               return -ENOMEM;
+
+       if (dev_priv->pwrctx == NULL)
+               dev_priv->pwrctx = intel_alloc_context_page(dev);
+       if (!dev_priv->pwrctx) {
+               ironlake_teardown_rc6(dev);
+               return -ENOMEM;
+       }
+
+       return 0;
 }
 
 void ironlake_enable_rc6(struct drm_device *dev)
@@ -6505,15 +6602,26 @@ void ironlake_enable_rc6(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
+       /* rc6 disabled by default due to repeated reports of hanging during
+        * boot and resume.
+        */
+       if (!i915_enable_rc6)
+               return;
+
+       ret = ironlake_setup_rc6(dev);
+       if (ret)
+               return;
+
        /*
         * GPU can automatically power down the render unit if given a page
         * to save state.
         */
        ret = BEGIN_LP_RING(6);
        if (ret) {
-               ironlake_disable_rc6(dev);
+               ironlake_teardown_rc6(dev);
                return;
        }
+
        OUT_RING(MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN);
        OUT_RING(MI_SET_CONTEXT);
        OUT_RING(dev_priv->renderctx->gtt_offset |
@@ -6530,6 +6638,7 @@ void ironlake_enable_rc6(struct drm_device *dev)
        I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
 }
 
+
 /* Set up chip specific display functions */
 static void intel_init_display(struct drm_device *dev)
 {
@@ -6772,21 +6881,9 @@ void intel_modeset_init(struct drm_device *dev)
        if (IS_GEN6(dev))
                gen6_enable_rps(dev_priv);
 
-       if (IS_IRONLAKE_M(dev)) {
-               dev_priv->renderctx = intel_alloc_context_page(dev);
-               if (!dev_priv->renderctx)
-                       goto skip_rc6;
-               dev_priv->pwrctx = intel_alloc_context_page(dev);
-               if (!dev_priv->pwrctx) {
-                       i915_gem_object_unpin(dev_priv->renderctx);
-                       drm_gem_object_unreference(&dev_priv->renderctx->base);
-                       dev_priv->renderctx = NULL;
-                       goto skip_rc6;
-               }
+       if (IS_IRONLAKE_M(dev))
                ironlake_enable_rc6(dev);
-       }
 
-skip_rc6:
        INIT_WORK(&dev_priv->idle_work, intel_idle_update);
        setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
                    (unsigned long)dev);
index 1f4242b..51cb4e3 100644 (file)
@@ -1639,6 +1639,24 @@ static int intel_dp_get_modes(struct drm_connector *connector)
        return 0;
 }
 
+static bool
+intel_dp_detect_audio(struct drm_connector *connector)
+{
+       struct intel_dp *intel_dp = intel_attached_dp(connector);
+       struct edid *edid;
+       bool has_audio = false;
+
+       edid = drm_get_edid(connector, &intel_dp->adapter);
+       if (edid) {
+               has_audio = drm_detect_monitor_audio(edid);
+
+               connector->display_info.raw_edid = NULL;
+               kfree(edid);
+       }
+
+       return has_audio;
+}
+
 static int
 intel_dp_set_property(struct drm_connector *connector,
                      struct drm_property *property,
@@ -1652,17 +1670,23 @@ intel_dp_set_property(struct drm_connector *connector,
                return ret;
 
        if (property == intel_dp->force_audio_property) {
-               if (val == intel_dp->force_audio)
+               int i = val;
+               bool has_audio;
+
+               if (i == intel_dp->force_audio)
                        return 0;
 
-               intel_dp->force_audio = val;
+               intel_dp->force_audio = i;
 
-               if (val > 0 && intel_dp->has_audio)
-                       return 0;
-               if (val < 0 && !intel_dp->has_audio)
+               if (i == 0)
+                       has_audio = intel_dp_detect_audio(connector);
+               else
+                       has_audio = i > 0;
+
+               if (has_audio == intel_dp->has_audio)
                        return 0;
 
-               intel_dp->has_audio = val > 0;
+               intel_dp->has_audio = has_audio;
                goto done;
        }
 
index 74db255..2c43104 100644 (file)
@@ -298,7 +298,6 @@ extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
 extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
                                    u16 *blue, int regno);
 extern void intel_enable_clock_gating(struct drm_device *dev);
-extern void intel_disable_clock_gating(struct drm_device *dev);
 extern void ironlake_enable_drps(struct drm_device *dev);
 extern void ironlake_disable_drps(struct drm_device *dev);
 extern void gen6_enable_rps(struct drm_i915_private *dev_priv);
index 0d0273e..c635c9e 100644 (file)
@@ -251,6 +251,27 @@ static int intel_hdmi_get_modes(struct drm_connector *connector)
                                   &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter);
 }
 
+static bool
+intel_hdmi_detect_audio(struct drm_connector *connector)
+{
+       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+       struct drm_i915_private *dev_priv = connector->dev->dev_private;
+       struct edid *edid;
+       bool has_audio = false;
+
+       edid = drm_get_edid(connector,
+                           &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter);
+       if (edid) {
+               if (edid->input & DRM_EDID_INPUT_DIGITAL)
+                       has_audio = drm_detect_monitor_audio(edid);
+
+               connector->display_info.raw_edid = NULL;
+               kfree(edid);
+       }
+
+       return has_audio;
+}
+
 static int
 intel_hdmi_set_property(struct drm_connector *connector,
                      struct drm_property *property,
@@ -264,17 +285,23 @@ intel_hdmi_set_property(struct drm_connector *connector,
                return ret;
 
        if (property == intel_hdmi->force_audio_property) {
-               if (val == intel_hdmi->force_audio)
+               int i = val;
+               bool has_audio;
+
+               if (i == intel_hdmi->force_audio)
                        return 0;
 
-               intel_hdmi->force_audio = val;
+               intel_hdmi->force_audio = i;
 
-               if (val > 0 && intel_hdmi->has_audio)
-                       return 0;
-               if (val < 0 && !intel_hdmi->has_audio)
+               if (i == 0)
+                       has_audio = intel_hdmi_detect_audio(connector);
+               else
+                       has_audio = i > 0;
+
+               if (has_audio == intel_hdmi->has_audio)
                        return 0;
 
-               intel_hdmi->has_audio = val > 0;
+               intel_hdmi->has_audio = has_audio;
                goto done;
        }
 
index ace8d5d..bcdba7b 100644 (file)
@@ -261,12 +261,6 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
                return true;
        }
 
-       /* Make sure pre-965s set dither correctly */
-       if (INTEL_INFO(dev)->gen < 4) {
-               if (dev_priv->lvds_dither)
-                       pfit_control |= PANEL_8TO6_DITHER_ENABLE;
-       }
-
        /* Native modes don't need fitting */
        if (adjusted_mode->hdisplay == mode->hdisplay &&
            adjusted_mode->vdisplay == mode->vdisplay)
@@ -374,10 +368,16 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
        }
 
 out:
+       /* If not enabling scaling, be consistent and always use 0. */
        if ((pfit_control & PFIT_ENABLE) == 0) {
                pfit_control = 0;
                pfit_pgm_ratios = 0;
        }
+
+       /* Make sure pre-965 set dither correctly */
+       if (INTEL_INFO(dev)->gen < 4 && dev_priv->lvds_dither)
+               pfit_control |= PANEL_8TO6_DITHER_ENABLE;
+
        if (pfit_control != intel_lvds->pfit_control ||
            pfit_pgm_ratios != intel_lvds->pfit_pgm_ratios) {
                intel_lvds->pfit_control = pfit_control;
index c65992d..f8f86e5 100644 (file)
@@ -208,7 +208,6 @@ u32 intel_panel_get_backlight(struct drm_device *dev)
                        val &= ~1;
                        pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc);
                        val *= lbpc;
-                       val >>= 1;
                }
        }
 
@@ -235,11 +234,11 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level)
 
        if (is_backlight_combination_mode(dev)){
                u32 max = intel_panel_get_max_backlight(dev);
-               u8 lpbc;
+               u8 lbpc;
 
-               lpbc = level * 0xfe / max + 1;
-               level /= lpbc;
-               pci_write_config_byte(dev->pdev, PCI_LBPC, lpbc);
+               lbpc = level * 0xfe / max + 1;
+               level /= lbpc;
+               pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc);
        }
 
        tmp = I915_READ(BLC_PWM_CTL);
index 6218fa9..445f27e 100644 (file)
@@ -1059,22 +1059,25 @@ static void gen6_bsd_ring_write_tail(struct intel_ring_buffer *ring,
 }
 
 static int gen6_ring_flush(struct intel_ring_buffer *ring,
-                          u32 invalidate_domains,
-                          u32 flush_domains)
+                          u32 invalidate, u32 flush)
 {
+       uint32_t cmd;
        int ret;
 
-       if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0)
+       if (((invalidate | flush) & I915_GEM_GPU_DOMAINS) == 0)
                return 0;
 
        ret = intel_ring_begin(ring, 4);
        if (ret)
                return ret;
 
-       intel_ring_emit(ring, MI_FLUSH_DW);
-       intel_ring_emit(ring, 0);
+       cmd = MI_FLUSH_DW;
+       if (invalidate & I915_GEM_GPU_DOMAINS)
+               cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD;
+       intel_ring_emit(ring, cmd);
        intel_ring_emit(ring, 0);
        intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, MI_NOOP);
        intel_ring_advance(ring);
        return 0;
 }
@@ -1230,22 +1233,25 @@ static int blt_ring_begin(struct intel_ring_buffer *ring,
 }
 
 static int blt_ring_flush(struct intel_ring_buffer *ring,
-                          u32 invalidate_domains,
-                          u32 flush_domains)
+                         u32 invalidate, u32 flush)
 {
+       uint32_t cmd;
        int ret;
 
-       if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0)
+       if (((invalidate | flush) & I915_GEM_DOMAIN_RENDER) == 0)
                return 0;
 
        ret = blt_ring_begin(ring, 4);
        if (ret)
                return ret;
 
-       intel_ring_emit(ring, MI_FLUSH_DW);
-       intel_ring_emit(ring, 0);
+       cmd = MI_FLUSH_DW;
+       if (invalidate & I915_GEM_DOMAIN_RENDER)
+               cmd |= MI_INVALIDATE_TLB;
+       intel_ring_emit(ring, cmd);
        intel_ring_emit(ring, 0);
        intel_ring_emit(ring, 0);
+       intel_ring_emit(ring, MI_NOOP);
        intel_ring_advance(ring);
        return 0;
 }
index 6d6fde8..3430686 100644 (file)
@@ -14,22 +14,23 @@ struct  intel_hw_status_page {
        struct          drm_i915_gem_object *obj;
 };
 
-#define I915_RING_READ(reg) i915_safe_read(dev_priv, reg)
+#define I915_RING_READ(reg) i915_gt_read(dev_priv, reg)
+#define I915_RING_WRITE(reg, val) i915_gt_write(dev_priv, reg, val)
 
 #define I915_READ_TAIL(ring) I915_RING_READ(RING_TAIL((ring)->mmio_base))
-#define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL((ring)->mmio_base), val)
+#define I915_WRITE_TAIL(ring, val) I915_RING_WRITE(RING_TAIL((ring)->mmio_base), val)
 
 #define I915_READ_START(ring) I915_RING_READ(RING_START((ring)->mmio_base))
-#define I915_WRITE_START(ring, val) I915_WRITE(RING_START((ring)->mmio_base), val)
+#define I915_WRITE_START(ring, val) I915_RING_WRITE(RING_START((ring)->mmio_base), val)
 
 #define I915_READ_HEAD(ring)  I915_RING_READ(RING_HEAD((ring)->mmio_base))
-#define I915_WRITE_HEAD(ring, val) I915_WRITE(RING_HEAD((ring)->mmio_base), val)
+#define I915_WRITE_HEAD(ring, val) I915_RING_WRITE(RING_HEAD((ring)->mmio_base), val)
 
 #define I915_READ_CTL(ring) I915_RING_READ(RING_CTL((ring)->mmio_base))
-#define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL((ring)->mmio_base), val)
+#define I915_WRITE_CTL(ring, val) I915_RING_WRITE(RING_CTL((ring)->mmio_base), val)
 
-#define I915_WRITE_IMR(ring, val) I915_WRITE(RING_IMR((ring)->mmio_base), val)
 #define I915_READ_IMR(ring) I915_RING_READ(RING_IMR((ring)->mmio_base))
+#define I915_WRITE_IMR(ring, val) I915_RING_WRITE(RING_IMR((ring)->mmio_base), val)
 
 #define I915_READ_NOPID(ring) I915_RING_READ(RING_NOPID((ring)->mmio_base))
 #define I915_READ_SYNC_0(ring) I915_RING_READ(RING_SYNC_0((ring)->mmio_base))
index 45cd376..7c50cdc 100644 (file)
@@ -46,6 +46,7 @@
                          SDVO_TV_MASK)
 
 #define IS_TV(c)       (c->output_flag & SDVO_TV_MASK)
+#define IS_TMDS(c)     (c->output_flag & SDVO_TMDS_MASK)
 #define IS_LVDS(c)     (c->output_flag & SDVO_LVDS_MASK)
 #define IS_TV_OR_LVDS(c) (c->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK))
 
@@ -473,20 +474,6 @@ static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
                return false;
        }
 
-       i = 3;
-       while (status == SDVO_CMD_STATUS_PENDING && i--) {
-               if (!intel_sdvo_read_byte(intel_sdvo,
-                                         SDVO_I2C_CMD_STATUS,
-                                         &status))
-                       return false;
-       }
-       if (status != SDVO_CMD_STATUS_SUCCESS) {
-               DRM_DEBUG_KMS("command returns response %s [%d]\n",
-                             status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP ? cmd_status_names[status] : "???",
-                             status);
-               return false;
-       }
-
        return true;
 }
 
@@ -497,6 +484,8 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
        u8 status;
        int i;
 
+       DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo));
+
        /*
         * The documentation states that all commands will be
         * processed within 15µs, and that we need only poll
@@ -505,14 +494,19 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
         *
         * Check 5 times in case the hardware failed to read the docs.
         */
-       do {
+       if (!intel_sdvo_read_byte(intel_sdvo,
+                                 SDVO_I2C_CMD_STATUS,
+                                 &status))
+               goto log_fail;
+
+       while (status == SDVO_CMD_STATUS_PENDING && retry--) {
+               udelay(15);
                if (!intel_sdvo_read_byte(intel_sdvo,
                                          SDVO_I2C_CMD_STATUS,
                                          &status))
-                       return false;
-       } while (status == SDVO_CMD_STATUS_PENDING && --retry);
+                       goto log_fail;
+       }
 
-       DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo));
        if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
                DRM_LOG_KMS("(%s)", cmd_status_names[status]);
        else
@@ -533,7 +527,7 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
        return true;
 
 log_fail:
-       DRM_LOG_KMS("\n");
+       DRM_LOG_KMS("... failed\n");
        return false;
 }
 
@@ -550,6 +544,7 @@ static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode)
 static bool intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,
                                              u8 ddc_bus)
 {
+       /* This must be the immediately preceding write before the i2c xfer */
        return intel_sdvo_write_cmd(intel_sdvo,
                                    SDVO_CMD_SET_CONTROL_BUS_SWITCH,
                                    &ddc_bus, 1);
@@ -557,7 +552,10 @@ static bool intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,
 
 static bool intel_sdvo_set_value(struct intel_sdvo *intel_sdvo, u8 cmd, const void *data, int len)
 {
-       return intel_sdvo_write_cmd(intel_sdvo, cmd, data, len);
+       if (!intel_sdvo_write_cmd(intel_sdvo, cmd, data, len))
+               return false;
+
+       return intel_sdvo_read_response(intel_sdvo, NULL, 0);
 }
 
 static bool
@@ -859,18 +857,21 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo)
 
        intel_dip_infoframe_csum(&avi_if);
 
-       if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX,
+       if (!intel_sdvo_set_value(intel_sdvo,
+                                 SDVO_CMD_SET_HBUF_INDEX,
                                  set_buf_index, 2))
                return false;
 
        for (i = 0; i < sizeof(avi_if); i += 8) {
-               if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA,
+               if (!intel_sdvo_set_value(intel_sdvo,
+                                         SDVO_CMD_SET_HBUF_DATA,
                                          data, 8))
                        return false;
                data++;
        }
 
-       return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE,
+       return intel_sdvo_set_value(intel_sdvo,
+                                   SDVO_CMD_SET_HBUF_TXRATE,
                                    &tx_rate, 1);
 }
 
@@ -1359,7 +1360,8 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
                                intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid);
                                intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid);
                        }
-               }
+               } else
+                       status = connector_status_disconnected;
                connector->display_info.raw_edid = NULL;
                kfree(edid);
        }
@@ -1407,10 +1409,25 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
 
        if ((intel_sdvo_connector->output_flag & response) == 0)
                ret = connector_status_disconnected;
-       else if (response & SDVO_TMDS_MASK)
+       else if (IS_TMDS(intel_sdvo_connector))
                ret = intel_sdvo_hdmi_sink_detect(connector);
-       else
-               ret = connector_status_connected;
+       else {
+               struct edid *edid;
+
+               /* if we have an edid check it matches the connection */
+               edid = intel_sdvo_get_edid(connector);
+               if (edid == NULL)
+                       edid = intel_sdvo_get_analog_edid(connector);
+               if (edid != NULL) {
+                       if (edid->input & DRM_EDID_INPUT_DIGITAL)
+                               ret = connector_status_disconnected;
+                       else
+                               ret = connector_status_connected;
+                       connector->display_info.raw_edid = NULL;
+                       kfree(edid);
+               } else
+                       ret = connector_status_connected;
+       }
 
        /* May update encoder flag for like clock for SDVO TV, etc.*/
        if (ret == connector_status_connected) {
@@ -1446,10 +1463,15 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
                edid = intel_sdvo_get_analog_edid(connector);
 
        if (edid != NULL) {
-               if (edid->input & DRM_EDID_INPUT_DIGITAL) {
+               struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
+               bool monitor_is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL);
+               bool connector_is_digital = !!IS_TMDS(intel_sdvo_connector);
+
+               if (connector_is_digital == monitor_is_digital) {
                        drm_mode_connector_update_edid_property(connector, edid);
                        drm_add_edid_modes(connector, edid);
                }
+
                connector->display_info.raw_edid = NULL;
                kfree(edid);
        }
@@ -1668,6 +1690,22 @@ static void intel_sdvo_destroy(struct drm_connector *connector)
        kfree(connector);
 }
 
+static bool intel_sdvo_detect_hdmi_audio(struct drm_connector *connector)
+{
+       struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
+       struct edid *edid;
+       bool has_audio = false;
+
+       if (!intel_sdvo->is_hdmi)
+               return false;
+
+       edid = intel_sdvo_get_edid(connector);
+       if (edid != NULL && edid->input & DRM_EDID_INPUT_DIGITAL)
+               has_audio = drm_detect_monitor_audio(edid);
+
+       return has_audio;
+}
+
 static int
 intel_sdvo_set_property(struct drm_connector *connector,
                        struct drm_property *property,
@@ -1684,17 +1722,23 @@ intel_sdvo_set_property(struct drm_connector *connector,
                return ret;
 
        if (property == intel_sdvo_connector->force_audio_property) {
-               if (val == intel_sdvo_connector->force_audio)
+               int i = val;
+               bool has_audio;
+
+               if (i == intel_sdvo_connector->force_audio)
                        return 0;
 
-               intel_sdvo_connector->force_audio = val;
+               intel_sdvo_connector->force_audio = i;
 
-               if (val > 0 && intel_sdvo->has_hdmi_audio)
-                       return 0;
-               if (val < 0 && !intel_sdvo->has_hdmi_audio)
+               if (i == 0)
+                       has_audio = intel_sdvo_detect_hdmi_audio(connector);
+               else
+                       has_audio = i > 0;
+
+               if (has_audio == intel_sdvo->has_hdmi_audio)
                        return 0;
 
-               intel_sdvo->has_hdmi_audio = val > 0;
+               intel_sdvo->has_hdmi_audio = has_audio;
                goto done;
        }
 
index 93206e4..fe4a53a 100644 (file)
@@ -1234,7 +1234,8 @@ static const struct drm_display_mode reported_modes[] = {
  * \return false if TV is disconnected.
  */
 static int
-intel_tv_detect_type (struct intel_tv *intel_tv)
+intel_tv_detect_type (struct intel_tv *intel_tv,
+                     struct drm_connector *connector)
 {
        struct drm_encoder *encoder = &intel_tv->base.base;
        struct drm_device *dev = encoder->dev;
@@ -1245,11 +1246,13 @@ intel_tv_detect_type (struct intel_tv *intel_tv)
        int type;
 
        /* Disable TV interrupts around load detect or we'll recurse */
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       i915_disable_pipestat(dev_priv, 0,
-                             PIPE_HOTPLUG_INTERRUPT_ENABLE |
-                             PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
-       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
+               spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+               i915_disable_pipestat(dev_priv, 0,
+                                     PIPE_HOTPLUG_INTERRUPT_ENABLE |
+                                     PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
+               spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       }
 
        save_tv_dac = tv_dac = I915_READ(TV_DAC);
        save_tv_ctl = tv_ctl = I915_READ(TV_CTL);
@@ -1302,11 +1305,13 @@ intel_tv_detect_type (struct intel_tv *intel_tv)
        I915_WRITE(TV_CTL, save_tv_ctl);
 
        /* Restore interrupt config */
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       i915_enable_pipestat(dev_priv, 0,
-                            PIPE_HOTPLUG_INTERRUPT_ENABLE |
-                            PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
-       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
+               spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+               i915_enable_pipestat(dev_priv, 0,
+                                    PIPE_HOTPLUG_INTERRUPT_ENABLE |
+                                    PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
+               spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       }
 
        return type;
 }
@@ -1356,7 +1361,7 @@ intel_tv_detect(struct drm_connector *connector, bool force)
        drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
 
        if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) {
-               type = intel_tv_detect_type(intel_tv);
+               type = intel_tv_detect_type(intel_tv, connector);
        } else if (force) {
                struct drm_crtc *crtc;
                int dpms_mode;
@@ -1364,7 +1369,7 @@ intel_tv_detect(struct drm_connector *connector, bool force)
                crtc = intel_get_load_detect_pipe(&intel_tv->base, connector,
                                                  &mode, &dpms_mode);
                if (crtc) {
-                       type = intel_tv_detect_type(intel_tv);
+                       type = intel_tv_detect_type(intel_tv, connector);
                        intel_release_load_detect_pipe(&intel_tv->base, connector,
                                                       dpms_mode);
                } else
@@ -1658,6 +1663,18 @@ intel_tv_init(struct drm_device *dev)
        intel_encoder = &intel_tv->base;
        connector = &intel_connector->base;
 
+       /* The documentation, for the older chipsets at least, recommend
+        * using a polling method rather than hotplug detection for TVs.
+        * This is because in order to perform the hotplug detection, the PLLs
+        * for the TV must be kept alive increasing power drain and starving
+        * bandwidth from other encoders. Notably for instance, it causes
+        * pipe underruns on Crestline when this encoder is supposedly idle.
+        *
+        * More recent chipsets favour HDMI rather than integrated S-Video.
+        */
+       connector->polled =
+               DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
+
        drm_connector_init(dev, connector, &intel_tv_connector_funcs,
                           DRM_MODE_CONNECTOR_SVIDEO);
 
index 2aef5cd..6bdab89 100644 (file)
@@ -6228,7 +6228,7 @@ parse_dcb15_entry(struct drm_device *dev, struct dcb_table *dcb,
                entry->tvconf.has_component_output = false;
                break;
        case OUTPUT_LVDS:
-               if ((conn & 0x00003f00) != 0x10)
+               if ((conn & 0x00003f00) >> 8 != 0x10)
                        entry->lvdsconf.use_straps_for_mode = true;
                entry->lvdsconf.use_power_scripts = true;
                break;
@@ -6310,6 +6310,9 @@ void merge_like_dcb_entries(struct drm_device *dev, struct dcb_table *dcb)
 static bool
 apply_dcb_encoder_quirks(struct drm_device *dev, int idx, u32 *conn, u32 *conf)
 {
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct dcb_table *dcb = &dev_priv->vbios.dcb;
+
        /* Dell Precision M6300
         *   DCB entry 2: 02025312 00000010
         *   DCB entry 3: 02026312 00000020
@@ -6327,6 +6330,18 @@ apply_dcb_encoder_quirks(struct drm_device *dev, int idx, u32 *conn, u32 *conf)
                        return false;
        }
 
+       /* GeForce3 Ti 200
+        *
+        * DCB reports an LVDS output that should be TMDS:
+        *   DCB entry 1: f2005014 ffffffff
+        */
+       if (nv_match_device(dev, 0x0201, 0x1462, 0x8851)) {
+               if (*conn == 0xf2005014 && *conf == 0xffffffff) {
+                       fabricate_dcb_output(dcb, OUTPUT_TMDS, 1, 1, 1);
+                       return false;
+               }
+       }
+
        return true;
 }
 
index a7fae26..a521840 100644 (file)
@@ -49,7 +49,10 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
                DRM_ERROR("bo %p still attached to GEM object\n", bo);
 
        nv10_mem_put_tile_region(dev, nvbo->tile, NULL);
-       nouveau_vm_put(&nvbo->vma);
+       if (nvbo->vma.node) {
+               nouveau_vm_unmap(&nvbo->vma);
+               nouveau_vm_put(&nvbo->vma);
+       }
        kfree(nvbo);
 }
 
@@ -128,6 +131,7 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan,
                }
        }
 
+       nvbo->bo.mem.num_pages = size >> PAGE_SHIFT;
        nouveau_bo_placement_set(nvbo, flags, 0);
 
        nvbo->channel = chan;
@@ -166,17 +170,17 @@ static void
 set_placement_range(struct nouveau_bo *nvbo, uint32_t type)
 {
        struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev);
+       int vram_pages = dev_priv->vram_size >> PAGE_SHIFT;
 
        if (dev_priv->card_type == NV_10 &&
-           nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM)) {
+           nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM) &&
+           nvbo->bo.mem.num_pages < vram_pages / 2) {
                /*
                 * Make sure that the color and depth buffers are handled
                 * by independent memory controller units. Up to a 9x
                 * speed up when alpha-blending and depth-test are enabled
                 * at the same time.
                 */
-               int vram_pages = dev_priv->vram_size >> PAGE_SHIFT;
-
                if (nvbo->tile_flags & NOUVEAU_GEM_TILE_ZETA) {
                        nvbo->placement.fpfn = vram_pages / 2;
                        nvbo->placement.lpfn = ~0;
@@ -785,7 +789,7 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr,
        if (ret)
                goto out;
 
-       ret = ttm_bo_move_ttm(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
+       ret = ttm_bo_move_ttm(bo, true, no_wait_reserve, no_wait_gpu, new_mem);
 out:
        ttm_bo_mem_put(bo, &tmp_mem);
        return ret;
@@ -811,11 +815,11 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr,
        if (ret)
                return ret;
 
-       ret = ttm_bo_move_ttm(bo, evict, no_wait_reserve, no_wait_gpu, &tmp_mem);
+       ret = ttm_bo_move_ttm(bo, true, no_wait_reserve, no_wait_gpu, &tmp_mem);
        if (ret)
                goto out;
 
-       ret = nouveau_bo_move_m2mf(bo, evict, intr, no_wait_reserve, no_wait_gpu, new_mem);
+       ret = nouveau_bo_move_m2mf(bo, true, intr, no_wait_reserve, no_wait_gpu, new_mem);
        if (ret)
                goto out;
 
index a21e000..390d82c 100644 (file)
@@ -507,6 +507,7 @@ nouveau_connector_native_mode(struct drm_connector *connector)
        int high_w = 0, high_h = 0, high_v = 0;
 
        list_for_each_entry(mode, &nv_connector->base.probed_modes, head) {
+               mode->vrefresh = drm_mode_vrefresh(mode);
                if (helper->mode_valid(connector, mode) != MODE_OK ||
                    (mode->flags & DRM_MODE_FLAG_INTERLACE))
                        continue;
index 65699bf..b368ed7 100644 (file)
@@ -83,7 +83,8 @@ nouveau_dma_init(struct nouveau_channel *chan)
                return ret;
 
        /* NV_MEMORY_TO_MEMORY_FORMAT requires a notifier object */
-       ret = nouveau_notifier_alloc(chan, NvNotify0, 32, &chan->m2mf_ntfy);
+       ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfd0, 0x1000,
+                                    &chan->m2mf_ntfy);
        if (ret)
                return ret;
 
index 13bb672..f658a04 100644 (file)
@@ -234,9 +234,9 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
                pci_set_power_state(pdev, PCI_D3hot);
        }
 
-       acquire_console_sem();
+       console_lock();
        nouveau_fbcon_set_suspend(dev, 1);
-       release_console_sem();
+       console_unlock();
        nouveau_fbcon_restore_accel(dev);
        return 0;
 
@@ -359,9 +359,9 @@ nouveau_pci_resume(struct pci_dev *pdev)
                nv_crtc->lut.depth = 0;
        }
 
-       acquire_console_sem();
+       console_lock();
        nouveau_fbcon_set_suspend(dev, 0);
-       release_console_sem();
+       console_unlock();
 
        nouveau_fbcon_zfill_all(dev);
 
index 01bffc4..982d70b 100644 (file)
@@ -848,14 +848,12 @@ extern void nv10_mem_put_tile_region(struct drm_device *dev,
                                     struct nouveau_fence *fence);
 extern const struct ttm_mem_type_manager_func nouveau_vram_manager;
 
-/* nvc0_vram.c */
-extern const struct ttm_mem_type_manager_func nvc0_vram_manager;
-
 /* nouveau_notifier.c */
 extern int  nouveau_notifier_init_channel(struct nouveau_channel *);
 extern void nouveau_notifier_takedown_channel(struct nouveau_channel *);
 extern int  nouveau_notifier_alloc(struct nouveau_channel *, uint32_t handle,
-                                  int cout, uint32_t *offset);
+                                  int cout, uint32_t start, uint32_t end,
+                                  uint32_t *offset);
 extern int  nouveau_notifier_offset(struct nouveau_gpuobj *, uint32_t *);
 extern int  nouveau_ioctl_notifier_alloc(struct drm_device *, void *data,
                                         struct drm_file *);
index 26347b7..b0fb9bd 100644 (file)
@@ -725,8 +725,10 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man,
        ret = vram->get(dev, mem->num_pages << PAGE_SHIFT,
                        mem->page_alignment << PAGE_SHIFT, size_nc,
                        (nvbo->tile_flags >> 8) & 0xff, &node);
-       if (ret)
-               return ret;
+       if (ret) {
+               mem->mm_node = NULL;
+               return (ret == -ENOSPC) ? 0 : ret;
+       }
 
        node->page_shift = 12;
        if (nvbo->vma.node)
index 8844b50..7609756 100644 (file)
@@ -123,7 +123,7 @@ nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc,
                return 0;
        }
 
-       return -ENOMEM;
+       return -ENOSPC;
 }
 
 int
index fe29d60..5ea1676 100644 (file)
@@ -96,7 +96,8 @@ nouveau_notifier_gpuobj_dtor(struct drm_device *dev,
 
 int
 nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
-                      int size, uint32_t *b_offset)
+                      int size, uint32_t start, uint32_t end,
+                      uint32_t *b_offset)
 {
        struct drm_device *dev = chan->dev;
        struct nouveau_gpuobj *nobj = NULL;
@@ -104,9 +105,10 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
        uint32_t offset;
        int target, ret;
 
-       mem = drm_mm_search_free(&chan->notifier_heap, size, 0, 0);
+       mem = drm_mm_search_free_in_range(&chan->notifier_heap, size, 0,
+                                         start, end, 0);
        if (mem)
-               mem = drm_mm_get_block(mem, size, 0);
+               mem = drm_mm_get_block_range(mem, size, 0, start, end);
        if (!mem) {
                NV_ERROR(dev, "Channel %d notifier block full\n", chan->id);
                return -ENOMEM;
@@ -177,7 +179,8 @@ nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data,
        if (IS_ERR(chan))
                return PTR_ERR(chan);
 
-       ret = nouveau_notifier_alloc(chan, na->handle, na->size, &na->offset);
+       ret = nouveau_notifier_alloc(chan, na->handle, na->size, 0, 0x1000,
+                                    &na->offset);
        nouveau_channel_put(&chan);
        return ret;
 }
index fb846a3..4399e2f 100644 (file)
@@ -443,7 +443,7 @@ nouveau_hwmon_fini(struct drm_device *dev)
        struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
 
        if (pm->hwmon) {
-               sysfs_remove_group(&pm->hwmon->kobj, &hwmon_attrgroup);
+               sysfs_remove_group(&dev->pdev->dev.kobj, &hwmon_attrgroup);
                hwmon_device_unregister(pm->hwmon);
        }
 #endif
@@ -543,7 +543,7 @@ nouveau_pm_resume(struct drm_device *dev)
        struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
        struct nouveau_pm_level *perflvl;
 
-       if (pm->cur == &pm->boot)
+       if (!pm->cur || pm->cur == &pm->boot)
                return;
 
        perflvl = pm->cur;
index 7ecc4ad..8d9968e 100644 (file)
@@ -265,8 +265,8 @@ nouveau_temp_probe_i2c(struct drm_device *dev)
        struct i2c_board_info info[] = {
                { I2C_BOARD_INFO("w83l785ts", 0x2d) },
                { I2C_BOARD_INFO("w83781d", 0x2d) },
-               { I2C_BOARD_INFO("f75375", 0x2e) },
                { I2C_BOARD_INFO("adt7473", 0x2e) },
+               { I2C_BOARD_INFO("f75375", 0x2e) },
                { I2C_BOARD_INFO("lm99", 0x4c) },
                { }
        };
index ef23550..c82db37 100644 (file)
@@ -342,8 +342,8 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder,
        if (nv_encoder->dcb->type == OUTPUT_LVDS) {
                bool duallink, dummy;
 
-               nouveau_bios_parse_lvds_table(dev, nv_connector->native_mode->
-                                             clock, &duallink, &dummy);
+               nouveau_bios_parse_lvds_table(dev, output_mode->clock,
+                                             &duallink, &dummy);
                if (duallink)
                        regp->fp_control |= (8 << 28);
        } else
@@ -518,8 +518,6 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode)
                return;
 
        if (nv_encoder->dcb->lvdsconf.use_power_scripts) {
-               struct nouveau_connector *nv_connector = nouveau_encoder_connector_get(nv_encoder);
-
                /* when removing an output, crtc may not be set, but PANEL_OFF
                 * must still be run
                 */
@@ -527,12 +525,8 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode)
                           nv04_dfp_get_bound_head(dev, nv_encoder->dcb);
 
                if (mode == DRM_MODE_DPMS_ON) {
-                       if (!nv_connector->native_mode) {
-                               NV_ERROR(dev, "Not turning on LVDS without native mode\n");
-                               return;
-                       }
                        call_lvds_script(dev, nv_encoder->dcb, head,
-                                        LVDS_PANEL_ON, nv_connector->native_mode->clock);
+                                        LVDS_PANEL_ON, nv_encoder->mode.clock);
                } else
                        /* pxclk of 0 is fine for PANEL_OFF, and for a
                         * disconnected LVDS encoder there is no native_mode
index 8870d72..18d30c2 100644 (file)
@@ -211,18 +211,32 @@ nv40_graph_set_tile_region(struct drm_device *dev, int i)
        struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
 
        switch (dev_priv->chipset) {
+       case 0x40:
+       case 0x41: /* guess */
+       case 0x42:
+       case 0x43:
+       case 0x45: /* guess */
+       case 0x4e:
+               nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch);
+               nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit);
+               nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr);
+               nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch);
+               nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit);
+               nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr);
+               break;
        case 0x44:
        case 0x4a:
-       case 0x4e:
                nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch);
                nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit);
                nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr);
                break;
-
        case 0x46:
        case 0x47:
        case 0x49:
        case 0x4b:
+       case 0x4c:
+       case 0x67:
+       default:
                nv_wr32(dev, NV47_PGRAPH_TSIZE(i), tile->pitch);
                nv_wr32(dev, NV47_PGRAPH_TLIMIT(i), tile->limit);
                nv_wr32(dev, NV47_PGRAPH_TILE(i), tile->addr);
@@ -230,15 +244,6 @@ nv40_graph_set_tile_region(struct drm_device *dev, int i)
                nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit);
                nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr);
                break;
-
-       default:
-               nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch);
-               nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit);
-               nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr);
-               nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch);
-               nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit);
-               nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr);
-               break;
        }
 }
 
@@ -396,17 +401,20 @@ nv40_graph_init(struct drm_device *dev)
                break;
        default:
                switch (dev_priv->chipset) {
-               case 0x46:
-               case 0x47:
-               case 0x49:
-               case 0x4b:
-                       nv_wr32(dev, 0x400DF0, nv_rd32(dev, NV04_PFB_CFG0));
-                       nv_wr32(dev, 0x400DF4, nv_rd32(dev, NV04_PFB_CFG1));
-                       break;
-               default:
+               case 0x41:
+               case 0x42:
+               case 0x43:
+               case 0x45:
+               case 0x4e:
+               case 0x44:
+               case 0x4a:
                        nv_wr32(dev, 0x4009F0, nv_rd32(dev, NV04_PFB_CFG0));
                        nv_wr32(dev, 0x4009F4, nv_rd32(dev, NV04_PFB_CFG1));
                        break;
+               default:
+                       nv_wr32(dev, 0x400DF0, nv_rd32(dev, NV04_PFB_CFG0));
+                       nv_wr32(dev, 0x400DF4, nv_rd32(dev, NV04_PFB_CFG1));
+                       break;
                }
                nv_wr32(dev, 0x4069F0, nv_rd32(dev, NV04_PFB_CFG0));
                nv_wr32(dev, 0x4069F4, nv_rd32(dev, NV04_PFB_CFG1));
index 14e24e9..0ea090f 100644 (file)
@@ -283,8 +283,7 @@ nv50_evo_create(struct drm_device *dev)
                        nv50_evo_channel_del(&dev_priv->evo);
                        return ret;
                }
-       } else
-       if (dev_priv->chipset != 0x50) {
+       } else {
                ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoFB16, 0x70, 0x19,
                                          0, 0xffffffff, 0x00010000);
                if (ret) {
index 2d7ea75..37e21d2 100644 (file)
@@ -256,6 +256,7 @@ nv50_graph_destroy_context(struct nouveau_channel *chan)
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+       struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
        int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
        unsigned long flags;
 
@@ -265,6 +266,7 @@ nv50_graph_destroy_context(struct nouveau_channel *chan)
                return;
 
        spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+       pfifo->reassign(dev, false);
        pgraph->fifo_access(dev, false);
 
        if (pgraph->channel(dev) == chan)
@@ -275,6 +277,7 @@ nv50_graph_destroy_context(struct nouveau_channel *chan)
        dev_priv->engine.instmem.flush(dev);
 
        pgraph->fifo_access(dev, true);
+       pfifo->reassign(dev, true);
        spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 
        nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
index ea00418..e57caa2 100644 (file)
@@ -403,16 +403,24 @@ nv50_instmem_unmap(struct nouveau_gpuobj *gpuobj)
 void
 nv50_instmem_flush(struct drm_device *dev)
 {
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       spin_lock(&dev_priv->ramin_lock);
        nv_wr32(dev, 0x00330c, 0x00000001);
        if (!nv_wait(dev, 0x00330c, 0x00000002, 0x00000000))
                NV_ERROR(dev, "PRAMIN flush timeout\n");
+       spin_unlock(&dev_priv->ramin_lock);
 }
 
 void
 nv84_instmem_flush(struct drm_device *dev)
 {
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       spin_lock(&dev_priv->ramin_lock);
        nv_wr32(dev, 0x070000, 0x00000001);
        if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000))
                NV_ERROR(dev, "PRAMIN flush timeout\n");
+       spin_unlock(&dev_priv->ramin_lock);
 }
 
index 38e523e..6144156 100644 (file)
@@ -45,11 +45,6 @@ nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde,
        }
 
        if (phys & 1) {
-               if (dev_priv->vram_sys_base) {
-                       phys += dev_priv->vram_sys_base;
-                       phys |= 0x30;
-               }
-
                if (coverage <= 32 * 1024 * 1024)
                        phys |= 0x60;
                else if (coverage <= 64 * 1024 * 1024)
@@ -174,7 +169,11 @@ nv50_vm_flush(struct nouveau_vm *vm)
 void
 nv50_vm_flush_engine(struct drm_device *dev, int engine)
 {
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       spin_lock(&dev_priv->ramin_lock);
        nv_wr32(dev, 0x100c80, (engine << 16) | 1);
        if (!nv_wait(dev, 0x100c80, 0x00000001, 0x00000000))
                NV_ERROR(dev, "vm flush timeout: engine %d\n", engine);
+       spin_unlock(&dev_priv->ramin_lock);
 }
index e6ea7d8..eb18a7e 100644 (file)
@@ -31,6 +31,7 @@
 #include "nvc0_graph.h"
 
 static void nvc0_graph_isr(struct drm_device *);
+static void nvc0_runk140_isr(struct drm_device *);
 static int  nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan);
 
 void
@@ -281,6 +282,7 @@ nvc0_graph_destroy(struct drm_device *dev)
                return;
 
        nouveau_irq_unregister(dev, 12);
+       nouveau_irq_unregister(dev, 25);
 
        nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
        nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
@@ -390,6 +392,7 @@ nvc0_graph_create(struct drm_device *dev)
        }
 
        nouveau_irq_register(dev, 12, nvc0_graph_isr);
+       nouveau_irq_register(dev, 25, nvc0_runk140_isr);
        NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */
        NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */
        NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */
@@ -512,8 +515,8 @@ nvc0_graph_init_gpc_1(struct drm_device *dev)
                        nv_wr32(dev, TP_UNIT(gpc, tp, 0x224), 0xc0000000);
                        nv_wr32(dev, TP_UNIT(gpc, tp, 0x48c), 0xc0000000);
                        nv_wr32(dev, TP_UNIT(gpc, tp, 0x084), 0xc0000000);
-                       nv_wr32(dev, TP_UNIT(gpc, tp, 0xe44), 0x001ffffe);
-                       nv_wr32(dev, TP_UNIT(gpc, tp, 0xe4c), 0x0000000f);
+                       nv_wr32(dev, TP_UNIT(gpc, tp, 0x644), 0x001ffffe);
+                       nv_wr32(dev, TP_UNIT(gpc, tp, 0x64c), 0x0000000f);
                }
                nv_wr32(dev, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
                nv_wr32(dev, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
@@ -777,3 +780,19 @@ nvc0_graph_isr(struct drm_device *dev)
 
        nv_wr32(dev, 0x400500, 0x00010001);
 }
+
+static void
+nvc0_runk140_isr(struct drm_device *dev)
+{
+       u32 units = nv_rd32(dev, 0x00017c) & 0x1f;
+
+       while (units) {
+               u32 unit = ffs(units) - 1;
+               u32 reg = 0x140000 + unit * 0x2000;
+               u32 st0 = nv_mask(dev, reg + 0x1020, 0, 0);
+               u32 st1 = nv_mask(dev, reg + 0x1420, 0, 0);
+
+               NV_INFO(dev, "PRUNK140: %d 0x%08x 0x%08x\n", unit, st0, st1);
+               units &= ~(1 << unit);
+       }
+}
index b9e68b2..f880ff7 100644 (file)
@@ -1830,7 +1830,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan)
 
        for (tp = 0, id = 0; tp < 4; tp++) {
                for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-                       if (tp <= priv->tp_nr[gpc]) {
+                       if (tp < priv->tp_nr[gpc]) {
                                nv_wr32(dev, TP_UNIT(gpc, tp, 0x698), id);
                                nv_wr32(dev, TP_UNIT(gpc, tp, 0x4e8), id);
                                nv_wr32(dev, GPC_UNIT(gpc, 0x0c10 + tp * 4), id);
index d3ca170..a4e5e53 100644 (file)
@@ -48,29 +48,29 @@ static void atombios_overscan_setup(struct drm_crtc *crtc,
 
        switch (radeon_crtc->rmx_type) {
        case RMX_CENTER:
-               args.usOverscanTop = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2;
-               args.usOverscanBottom = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2;
-               args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2;
-               args.usOverscanRight = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2;
+               args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2);
+               args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2);
+               args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2);
+               args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2);
                break;
        case RMX_ASPECT:
                a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay;
                a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay;
 
                if (a1 > a2) {
-                       args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2;
-                       args.usOverscanRight = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2;
+                       args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2);
+                       args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2);
                } else if (a2 > a1) {
-                       args.usOverscanLeft = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2;
-                       args.usOverscanRight = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2;
+                       args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2);
+                       args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2);
                }
                break;
        case RMX_FULL:
        default:
-               args.usOverscanRight = radeon_crtc->h_border;
-               args.usOverscanLeft = radeon_crtc->h_border;
-               args.usOverscanBottom = radeon_crtc->v_border;
-               args.usOverscanTop = radeon_crtc->v_border;
+               args.usOverscanRight = cpu_to_le16(radeon_crtc->h_border);
+               args.usOverscanLeft = cpu_to_le16(radeon_crtc->h_border);
+               args.usOverscanBottom = cpu_to_le16(radeon_crtc->v_border);
+               args.usOverscanTop = cpu_to_le16(radeon_crtc->v_border);
                break;
        }
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
@@ -419,23 +419,23 @@ static void atombios_crtc_program_ss(struct drm_crtc *crtc,
        memset(&args, 0, sizeof(args));
 
        if (ASIC_IS_DCE5(rdev)) {
-               args.v3.usSpreadSpectrumAmountFrac = 0;
+               args.v3.usSpreadSpectrumAmountFrac = cpu_to_le16(0);
                args.v3.ucSpreadSpectrumType = ss->type;
                switch (pll_id) {
                case ATOM_PPLL1:
                        args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL;
-                       args.v3.usSpreadSpectrumAmount = ss->amount;
-                       args.v3.usSpreadSpectrumStep = ss->step;
+                       args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount);
+                       args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step);
                        break;
                case ATOM_PPLL2:
                        args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL;
-                       args.v3.usSpreadSpectrumAmount = ss->amount;
-                       args.v3.usSpreadSpectrumStep = ss->step;
+                       args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount);
+                       args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step);
                        break;
                case ATOM_DCPLL:
                        args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL;
-                       args.v3.usSpreadSpectrumAmount = 0;
-                       args.v3.usSpreadSpectrumStep = 0;
+                       args.v3.usSpreadSpectrumAmount = cpu_to_le16(0);
+                       args.v3.usSpreadSpectrumStep = cpu_to_le16(0);
                        break;
                case ATOM_PPLL_INVALID:
                        return;
@@ -447,18 +447,18 @@ static void atombios_crtc_program_ss(struct drm_crtc *crtc,
                switch (pll_id) {
                case ATOM_PPLL1:
                        args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL;
-                       args.v2.usSpreadSpectrumAmount = ss->amount;
-                       args.v2.usSpreadSpectrumStep = ss->step;
+                       args.v2.usSpreadSpectrumAmount = cpu_to_le16(ss->amount);
+                       args.v2.usSpreadSpectrumStep = cpu_to_le16(ss->step);
                        break;
                case ATOM_PPLL2:
                        args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P2PLL;
-                       args.v2.usSpreadSpectrumAmount = ss->amount;
-                       args.v2.usSpreadSpectrumStep = ss->step;
+                       args.v2.usSpreadSpectrumAmount = cpu_to_le16(ss->amount);
+                       args.v2.usSpreadSpectrumStep = cpu_to_le16(ss->step);
                        break;
                case ATOM_DCPLL:
                        args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_DCPLL;
-                       args.v2.usSpreadSpectrumAmount = 0;
-                       args.v2.usSpreadSpectrumStep = 0;
+                       args.v2.usSpreadSpectrumAmount = cpu_to_le16(0);
+                       args.v2.usSpreadSpectrumStep = cpu_to_le16(0);
                        break;
                case ATOM_PPLL_INVALID:
                        return;
@@ -538,7 +538,6 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                        pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
                else
                        pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
-
        }
 
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
@@ -555,23 +554,28 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                                        dp_clock = dig_connector->dp_clock;
                                }
                        }
-#if 0 /* doesn't work properly on some laptops */
+
                        /* use recommended ref_div for ss */
                        if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
                                if (ss_enabled) {
                                        if (ss->refdiv) {
+                                               pll->flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP;
                                                pll->flags |= RADEON_PLL_USE_REF_DIV;
                                                pll->reference_div = ss->refdiv;
+                                               if (ASIC_IS_AVIVO(rdev))
+                                                       pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV;
                                        }
                                }
                        }
-#endif
+
                        if (ASIC_IS_AVIVO(rdev)) {
                                /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
                                if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
                                        adjusted_clock = mode->clock * 2;
                                if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
                                        pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER;
+                               if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+                                       pll->flags |= RADEON_PLL_IS_LCD;
                        } else {
                                if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
                                        pll->flags |= RADEON_PLL_NO_ODD_POST_DIV;
@@ -658,10 +662,12 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                                                   index, (uint32_t *)&args);
                                adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10;
                                if (args.v3.sOutput.ucRefDiv) {
+                                       pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV;
                                        pll->flags |= RADEON_PLL_USE_REF_DIV;
                                        pll->reference_div = args.v3.sOutput.ucRefDiv;
                                }
                                if (args.v3.sOutput.ucPostDiv) {
+                                       pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV;
                                        pll->flags |= RADEON_PLL_USE_POST_DIV;
                                        pll->post_div = args.v3.sOutput.ucPostDiv;
                                }
@@ -715,14 +721,14 @@ static void atombios_crtc_set_dcpll(struct drm_crtc *crtc,
                         * SetPixelClock provides the dividers
                         */
                        args.v5.ucCRTC = ATOM_CRTC_INVALID;
-                       args.v5.usPixelClock = dispclk;
+                       args.v5.usPixelClock = cpu_to_le16(dispclk);
                        args.v5.ucPpll = ATOM_DCPLL;
                        break;
                case 6:
                        /* if the default dcpll clock is specified,
                         * SetPixelClock provides the dividers
                         */
-                       args.v6.ulDispEngClkFreq = dispclk;
+                       args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk);
                        args.v6.ucPpll = ATOM_DCPLL;
                        break;
                default:
@@ -951,8 +957,12 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
        /* adjust pixel clock as needed */
        adjusted_clock = atombios_adjust_pll(crtc, mode, pll, ss_enabled, &ss);
 
-       radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
-                          &ref_div, &post_div);
+       if (ASIC_IS_AVIVO(rdev))
+               radeon_compute_pll_avivo(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
+                                        &ref_div, &post_div);
+       else
+               radeon_compute_pll_legacy(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
+                                         &ref_div, &post_div);
 
        atombios_crtc_program_ss(crtc, ATOM_DISABLE, radeon_crtc->pll_id, &ss);
 
@@ -981,9 +991,9 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
        }
 }
 
-static int evergreen_crtc_do_set_base(struct drm_crtc *crtc,
-                                     struct drm_framebuffer *fb,
-                                     int x, int y, int atomic)
+static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
+                                struct drm_framebuffer *fb,
+                                int x, int y, int atomic)
 {
        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
        struct drm_device *dev = crtc->dev;
@@ -994,6 +1004,7 @@ static int evergreen_crtc_do_set_base(struct drm_crtc *crtc,
        struct radeon_bo *rbo;
        uint64_t fb_location;
        uint32_t fb_format, fb_pitch_pixels, tiling_flags;
+       u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE);
        int r;
 
        /* no fb bound */
@@ -1045,11 +1056,17 @@ static int evergreen_crtc_do_set_base(struct drm_crtc *crtc,
        case 16:
                fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) |
                             EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565));
+#ifdef __BIG_ENDIAN
+               fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16);
+#endif
                break;
        case 24:
        case 32:
                fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) |
                             EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888));
+#ifdef __BIG_ENDIAN
+               fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32);
+#endif
                break;
        default:
                DRM_ERROR("Unsupported screen depth %d\n",
@@ -1094,6 +1111,7 @@ static int evergreen_crtc_do_set_base(struct drm_crtc *crtc,
        WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
               (u32) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK);
        WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format);
+       WREG32(EVERGREEN_GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap);
 
        WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0);
        WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
@@ -1115,12 +1133,6 @@ static int evergreen_crtc_do_set_base(struct drm_crtc *crtc,
        WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
               (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay);
 
-       if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
-               WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset,
-                      EVERGREEN_INTERLEAVE_EN);
-       else
-               WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
-
        if (!atomic && fb && fb != crtc->fb) {
                radeon_fb = to_radeon_framebuffer(fb);
                rbo = radeon_fb->obj->driver_private;
@@ -1150,6 +1162,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
        struct drm_framebuffer *target_fb;
        uint64_t fb_location;
        uint32_t fb_format, fb_pitch_pixels, tiling_flags;
+       u32 fb_swap = R600_D1GRPH_SWAP_ENDIAN_NONE;
        int r;
 
        /* no fb bound */
@@ -1203,12 +1216,18 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
                fb_format =
                    AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
                    AVIVO_D1GRPH_CONTROL_16BPP_RGB565;
+#ifdef __BIG_ENDIAN
+               fb_swap = R600_D1GRPH_SWAP_ENDIAN_16BIT;
+#endif
                break;
        case 24:
        case 32:
                fb_format =
                    AVIVO_D1GRPH_CONTROL_DEPTH_32BPP |
                    AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888;
+#ifdef __BIG_ENDIAN
+               fb_swap = R600_D1GRPH_SWAP_ENDIAN_32BIT;
+#endif
                break;
        default:
                DRM_ERROR("Unsupported screen depth %d\n",
@@ -1248,6 +1267,8 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
        WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS +
               radeon_crtc->crtc_offset, (u32) fb_location);
        WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format);
+       if (rdev->family >= CHIP_R600)
+               WREG32(R600_D1GRPH_SWAP_CONTROL + radeon_crtc->crtc_offset, fb_swap);
 
        WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0);
        WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
@@ -1269,12 +1290,6 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
        WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
               (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay);
 
-       if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
-               WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset,
-                      AVIVO_D1MODE_INTERLEAVE_EN);
-       else
-               WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
-
        if (!atomic && fb && fb != crtc->fb) {
                radeon_fb = to_radeon_framebuffer(fb);
                rbo = radeon_fb->obj->driver_private;
@@ -1298,7 +1313,7 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
        struct radeon_device *rdev = dev->dev_private;
 
        if (ASIC_IS_DCE4(rdev))
-               return evergreen_crtc_do_set_base(crtc, old_fb, x, y, 0);
+               return dce4_crtc_do_set_base(crtc, old_fb, x, y, 0);
        else if (ASIC_IS_AVIVO(rdev))
                return avivo_crtc_do_set_base(crtc, old_fb, x, y, 0);
        else
@@ -1313,7 +1328,7 @@ int atombios_crtc_set_base_atomic(struct drm_crtc *crtc,
        struct radeon_device *rdev = dev->dev_private;
 
        if (ASIC_IS_DCE4(rdev))
-               return evergreen_crtc_do_set_base(crtc, fb, x, y, 1);
+               return dce4_crtc_do_set_base(crtc, fb, x, y, 1);
        else if (ASIC_IS_AVIVO(rdev))
                return avivo_crtc_do_set_base(crtc, fb, x, y, 1);
        else
index 4e7778d..695de9a 100644 (file)
@@ -187,9 +187,9 @@ static int dp_link_clock_for_mode_clock(u8 dpcd[DP_DPCD_SIZE], int mode_clock)
 int dp_mode_valid(u8 dpcd[DP_DPCD_SIZE], int mode_clock)
 {
        int lanes = dp_lanes_for_mode_clock(dpcd, mode_clock);
-       int bw = dp_lanes_for_mode_clock(dpcd, mode_clock);
+       int dp_clock = dp_link_clock_for_mode_clock(dpcd, mode_clock);
 
-       if ((lanes == 0) || (bw == 0))
+       if ((lanes == 0) || (dp_clock == 0))
                return MODE_CLOCK_HIGH;
 
        return MODE_OK;
index 677af91..6140ea1 100644 (file)
@@ -97,26 +97,29 @@ u32 evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
 }
 
 /* get temperature in millidegrees */
-u32 evergreen_get_temp(struct radeon_device *rdev)
+int evergreen_get_temp(struct radeon_device *rdev)
 {
        u32 temp = (RREG32(CG_MULT_THERMAL_STATUS) & ASIC_T_MASK) >>
                ASIC_T_SHIFT;
        u32 actual_temp = 0;
 
-       if ((temp >> 10) & 1)
-               actual_temp = 0;
-       else if ((temp >> 9) & 1)
+       if (temp & 0x400)
+               actual_temp = -256;
+       else if (temp & 0x200)
                actual_temp = 255;
-       else
-               actual_temp = (temp >> 1) & 0xff;
+       else if (temp & 0x100) {
+               actual_temp = temp & 0x1ff;
+               actual_temp |= ~0x1ff;
+       } else
+               actual_temp = temp & 0xff;
 
-       return actual_temp * 1000;
+       return (actual_temp * 1000) / 2;
 }
 
-u32 sumo_get_temp(struct radeon_device *rdev)
+int sumo_get_temp(struct radeon_device *rdev)
 {
        u32 temp = RREG32(CG_THERMAL_STATUS) & 0xff;
-       u32 actual_temp = (temp >> 1) & 0xff;
+       int actual_temp = temp - 49;
 
        return actual_temp * 1000;
 }
@@ -1182,6 +1185,22 @@ static void evergreen_mc_program(struct radeon_device *rdev)
 /*
  * CP.
  */
+void evergreen_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
+{
+       /* set to DX10/11 mode */
+       radeon_ring_write(rdev, PACKET3(PACKET3_MODE_CONTROL, 0));
+       radeon_ring_write(rdev, 1);
+       /* FIXME: implement */
+       radeon_ring_write(rdev, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
+       radeon_ring_write(rdev,
+#ifdef __BIG_ENDIAN
+                         (2 << 0) |
+#endif
+                         (ib->gpu_addr & 0xFFFFFFFC));
+       radeon_ring_write(rdev, upper_32_bits(ib->gpu_addr) & 0xFF);
+       radeon_ring_write(rdev, ib->length_dw);
+}
+
 
 static int evergreen_cp_load_microcode(struct radeon_device *rdev)
 {
@@ -1192,7 +1211,11 @@ static int evergreen_cp_load_microcode(struct radeon_device *rdev)
                return -EINVAL;
 
        r700_cp_stop(rdev);
-       WREG32(CP_RB_CNTL, RB_NO_UPDATE | (15 << 8) | (3 << 0));
+       WREG32(CP_RB_CNTL,
+#ifdef __BIG_ENDIAN
+              BUF_SWAP_32BIT |
+#endif
+              RB_NO_UPDATE | RB_BLKSZ(15) | RB_BUFSZ(3));
 
        fw_data = (const __be32 *)rdev->pfp_fw->data;
        WREG32(CP_PFP_UCODE_ADDR, 0);
@@ -1233,7 +1256,7 @@ static int evergreen_cp_start(struct radeon_device *rdev)
        cp_me = 0xff;
        WREG32(CP_ME_CNTL, cp_me);
 
-       r = radeon_ring_lock(rdev, evergreen_default_size + 15);
+       r = radeon_ring_lock(rdev, evergreen_default_size + 19);
        if (r) {
                DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r);
                return r;
@@ -1266,6 +1289,11 @@ static int evergreen_cp_start(struct radeon_device *rdev)
        radeon_ring_write(rdev, 0xffffffff);
        radeon_ring_write(rdev, 0xffffffff);
 
+       radeon_ring_write(rdev, 0xc0026900);
+       radeon_ring_write(rdev, 0x00000316);
+       radeon_ring_write(rdev, 0x0000000e); /* VGT_VERTEX_REUSE_BLOCK_CNTL */
+       radeon_ring_write(rdev, 0x00000010); /*  */
+
        radeon_ring_unlock_commit(rdev);
 
        return 0;
@@ -1306,7 +1334,11 @@ int evergreen_cp_resume(struct radeon_device *rdev)
        WREG32(CP_RB_WPTR, 0);
 
        /* set the wb address wether it's enabled or not */
-       WREG32(CP_RB_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC);
+       WREG32(CP_RB_RPTR_ADDR,
+#ifdef __BIG_ENDIAN
+              RB_RPTR_SWAP(2) |
+#endif
+              ((rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC));
        WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFF);
        WREG32(SCRATCH_ADDR, ((rdev->wb.gpu_addr + RADEON_WB_SCRATCH_OFFSET) >> 8) & 0xFFFFFFFF);
 
@@ -2072,6 +2104,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
        WREG32(VGT_CACHE_INVALIDATION, vgt_cache_invalidation);
 
        WREG32(VGT_GS_VERTEX_REUSE, 16);
+       WREG32(PA_SU_LINE_STIPPLE_VALUE, 0);
        WREG32(PA_SC_LINE_STIPPLE_STATE, 0);
 
        WREG32(VGT_VERTEX_REUSE_BLOCK_CNTL, 14);
@@ -2161,7 +2194,6 @@ int evergreen_mc_init(struct radeon_device *rdev)
                rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
        }
        rdev->mc.visible_vram_size = rdev->mc.aper_size;
-       rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
        r700_vram_gtt_location(rdev, &rdev->mc);
        radeon_update_bandwidth_info(rdev);
 
@@ -2606,8 +2638,8 @@ restart_ih:
        while (rptr != wptr) {
                /* wptr/rptr are in bytes! */
                ring_index = rptr / 4;
-               src_id =  rdev->ih.ring[ring_index] & 0xff;
-               src_data = rdev->ih.ring[ring_index + 1] & 0xfffffff;
+               src_id =  le32_to_cpu(rdev->ih.ring[ring_index]) & 0xff;
+               src_data = le32_to_cpu(rdev->ih.ring[ring_index + 1]) & 0xfffffff;
 
                switch (src_id) {
                case 1: /* D1 vblank/vline */
@@ -2901,7 +2933,7 @@ static int evergreen_startup(struct radeon_device *rdev)
        /* XXX: ontario has problems blitting to gart at the moment */
        if (rdev->family == CHIP_PALM) {
                rdev->asic->copy = NULL;
-               rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
+               radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
        }
 
        /* allocate wb buffer */
index b758dc7..2be698e 100644 (file)
@@ -55,7 +55,7 @@ set_render_target(struct radeon_device *rdev, int format,
        if (h < 8)
                h = 8;
 
-       cb_color_info = ((format << 2) | (1 << 24));
+       cb_color_info = ((format << 2) | (1 << 24) | (1 << 8));
        pitch = (w / 8) - 1;
        slice = ((w * h) / 64) - 1;
 
@@ -133,6 +133,9 @@ set_vtx_resource(struct radeon_device *rdev, u64 gpu_addr)
 
        /* high addr, stride */
        sq_vtx_constant_word2 = ((upper_32_bits(gpu_addr) & 0xff) | (16 << 8));
+#ifdef __BIG_ENDIAN
+       sq_vtx_constant_word2 |= (2 << 30);
+#endif
        /* xyzw swizzles */
        sq_vtx_constant_word3 = (0 << 3) | (1 << 6) | (2 << 9) | (3 << 12);
 
@@ -173,7 +176,7 @@ set_tex_resource(struct radeon_device *rdev,
        sq_tex_resource_word0 = (1 << 0); /* 2D */
        sq_tex_resource_word0 |= ((((pitch >> 3) - 1) << 6) |
                                  ((w - 1) << 18));
-       sq_tex_resource_word1 = ((h - 1) << 0);
+       sq_tex_resource_word1 = ((h - 1) << 0) | (1 << 28);
        /* xyzw swizzles */
        sq_tex_resource_word4 = (0 << 16) | (1 << 19) | (2 << 22) | (3 << 25);
 
@@ -221,7 +224,11 @@ draw_auto(struct radeon_device *rdev)
        radeon_ring_write(rdev, DI_PT_RECTLIST);
 
        radeon_ring_write(rdev, PACKET3(PACKET3_INDEX_TYPE, 0));
-       radeon_ring_write(rdev, DI_INDEX_SIZE_16_BIT);
+       radeon_ring_write(rdev,
+#ifdef __BIG_ENDIAN
+                         (2 << 2) |
+#endif
+                         DI_INDEX_SIZE_16_BIT);
 
        radeon_ring_write(rdev, PACKET3(PACKET3_NUM_INSTANCES, 0));
        radeon_ring_write(rdev, 1);
@@ -232,7 +239,7 @@ draw_auto(struct radeon_device *rdev)
 
 }
 
-/* emits 30 */
+/* emits 36 */
 static void
 set_default_state(struct radeon_device *rdev)
 {
@@ -245,6 +252,8 @@ set_default_state(struct radeon_device *rdev)
        int num_hs_threads, num_ls_threads;
        int num_ps_stack_entries, num_vs_stack_entries, num_gs_stack_entries, num_es_stack_entries;
        int num_hs_stack_entries, num_ls_stack_entries;
+       u64 gpu_addr;
+       int dwords;
 
        switch (rdev->family) {
        case CHIP_CEDAR:
@@ -497,6 +506,18 @@ set_default_state(struct radeon_device *rdev)
        radeon_ring_write(rdev, 0x00000000);
        radeon_ring_write(rdev, 0x00000000);
 
+       /* set to DX10/11 mode */
+       radeon_ring_write(rdev, PACKET3(PACKET3_MODE_CONTROL, 0));
+       radeon_ring_write(rdev, 1);
+
+       /* emit an IB pointing at default state */
+       dwords = ALIGN(rdev->r600_blit.state_len, 0x10);
+       gpu_addr = rdev->r600_blit.shader_gpu_addr + rdev->r600_blit.state_offset;
+       radeon_ring_write(rdev, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
+       radeon_ring_write(rdev, gpu_addr & 0xFFFFFFFC);
+       radeon_ring_write(rdev, upper_32_bits(gpu_addr) & 0xFF);
+       radeon_ring_write(rdev, dwords);
+
 }
 
 static inline uint32_t i2f(uint32_t input)
@@ -527,8 +548,10 @@ static inline uint32_t i2f(uint32_t input)
 int evergreen_blit_init(struct radeon_device *rdev)
 {
        u32 obj_size;
-       int r;
+       int i, r, dwords;
        void *ptr;
+       u32 packet2s[16];
+       int num_packet2s = 0;
 
        /* pin copy shader into vram if already initialized */
        if (rdev->r600_blit.shader_obj)
@@ -536,8 +559,17 @@ int evergreen_blit_init(struct radeon_device *rdev)
 
        mutex_init(&rdev->r600_blit.mutex);
        rdev->r600_blit.state_offset = 0;
-       rdev->r600_blit.state_len = 0;
-       obj_size = 0;
+
+       rdev->r600_blit.state_len = evergreen_default_size;
+
+       dwords = rdev->r600_blit.state_len;
+       while (dwords & 0xf) {
+               packet2s[num_packet2s++] = cpu_to_le32(PACKET2(0));
+               dwords++;
+       }
+
+       obj_size = dwords * 4;
+       obj_size = ALIGN(obj_size, 256);
 
        rdev->r600_blit.vs_offset = obj_size;
        obj_size += evergreen_vs_size * 4;
@@ -567,8 +599,16 @@ int evergreen_blit_init(struct radeon_device *rdev)
                return r;
        }
 
-       memcpy(ptr + rdev->r600_blit.vs_offset, evergreen_vs, evergreen_vs_size * 4);
-       memcpy(ptr + rdev->r600_blit.ps_offset, evergreen_ps, evergreen_ps_size * 4);
+       memcpy_toio(ptr + rdev->r600_blit.state_offset,
+                   evergreen_default_state, rdev->r600_blit.state_len * 4);
+
+       if (num_packet2s)
+               memcpy_toio(ptr + rdev->r600_blit.state_offset + (rdev->r600_blit.state_len * 4),
+                           packet2s, num_packet2s * 4);
+       for (i = 0; i < evergreen_vs_size; i++)
+               *(u32 *)((unsigned long)ptr + rdev->r600_blit.vs_offset + i * 4) = cpu_to_le32(evergreen_vs[i]);
+       for (i = 0; i < evergreen_ps_size; i++)
+               *(u32 *)((unsigned long)ptr + rdev->r600_blit.ps_offset + i * 4) = cpu_to_le32(evergreen_ps[i]);
        radeon_bo_kunmap(rdev->r600_blit.shader_obj);
        radeon_bo_unreserve(rdev->r600_blit.shader_obj);
 
@@ -583,7 +623,7 @@ done:
                dev_err(rdev->dev, "(%d) pin blit object failed\n", r);
                return r;
        }
-       rdev->mc.active_vram_size = rdev->mc.real_vram_size;
+       radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
        return 0;
 }
 
@@ -591,7 +631,7 @@ void evergreen_blit_fini(struct radeon_device *rdev)
 {
        int r;
 
-       rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
+       radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
        if (rdev->r600_blit.shader_obj == NULL)
                return;
        /* If we can't reserve the bo, unref should be enough to destroy
@@ -652,7 +692,7 @@ int evergreen_blit_prepare_copy(struct radeon_device *rdev, int size_bytes)
        /* calculate number of loops correctly */
        ring_size = num_loops * dwords_per_loop;
        /* set default  + shaders */
-       ring_size += 46; /* shaders + def state */
+       ring_size += 52; /* shaders + def state */
        ring_size += 10; /* fence emit for VB IB */
        ring_size += 5; /* done copy */
        ring_size += 10; /* fence emit for done copy */
@@ -660,7 +700,7 @@ int evergreen_blit_prepare_copy(struct radeon_device *rdev, int size_bytes)
        if (r)
                return r;
 
-       set_default_state(rdev); /* 30 */
+       set_default_state(rdev); /* 36 */
        set_shaders(rdev); /* 16 */
        return 0;
 }
index ef1d28c..3a10399 100644 (file)
@@ -311,11 +311,19 @@ const u32 evergreen_vs[] =
        0x00000000,
        0x3c000000,
        0x67961001,
+#ifdef __BIG_ENDIAN
+       0x000a0000,
+#else
        0x00080000,
+#endif
        0x00000000,
        0x1c000000,
        0x67961000,
+#ifdef __BIG_ENDIAN
+       0x00020008,
+#else
        0x00000008,
+#endif
        0x00000000,
 };
 
index 36d32d8..eb4acf4 100644 (file)
@@ -98,6 +98,7 @@
 #define                BUF_SWAP_32BIT                                  (2 << 16)
 #define        CP_RB_RPTR                                      0x8700
 #define        CP_RB_RPTR_ADDR                                 0xC10C
+#define                RB_RPTR_SWAP(x)                                 ((x) << 0)
 #define        CP_RB_RPTR_ADDR_HI                              0xC110
 #define        CP_RB_RPTR_WR                                   0xC108
 #define        CP_RB_WPTR                                      0xC114
 #define                FORCE_EOV_MAX_CLK_CNT(x)                        ((x) << 0)
 #define                FORCE_EOV_MAX_REZ_CNT(x)                        ((x) << 16)
 #define PA_SC_LINE_STIPPLE                             0x28A0C
+#define        PA_SU_LINE_STIPPLE_VALUE                        0x8A60
 #define        PA_SC_LINE_STIPPLE_STATE                        0x8B10
 
 #define        SCRATCH_REG0                                    0x8500
 #define        PACKET3_DISPATCH_DIRECT                         0x15
 #define        PACKET3_DISPATCH_INDIRECT                       0x16
 #define        PACKET3_INDIRECT_BUFFER_END                     0x17
+#define        PACKET3_MODE_CONTROL                            0x18
 #define        PACKET3_SET_PREDICATION                         0x20
 #define        PACKET3_REG_RMW                                 0x21
 #define        PACKET3_COND_EXEC                               0x22
index 607241c..5a82b6b 100644 (file)
@@ -673,8 +673,10 @@ static int parser_auth(struct table *t, const char *filename)
        last_reg = strtol(last_reg_s, NULL, 16);
 
        do {
-               if (fgets(buf, 1024, file) == NULL)
+               if (fgets(buf, 1024, file) == NULL) {
+                       fclose(file);
                        return -1;
+               }
                len = strlen(buf);
                if (ftell(file) == end)
                        done = 1;
@@ -685,6 +687,7 @@ static int parser_auth(struct table *t, const char *filename)
                                fprintf(stderr,
                                        "Error matching regular expression %d in %s\n",
                                        r, filename);
+                               fclose(file);
                                return -1;
                        } else {
                                buf[match[0].rm_eo] = 0;
index 5968dde..e372f9e 100644 (file)
@@ -70,23 +70,6 @@ MODULE_FIRMWARE(FIRMWARE_R520);
 
 void r100_pre_page_flip(struct radeon_device *rdev, int crtc)
 {
-       struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc];
-       u32 tmp;
-
-       /* make sure flip is at vb rather than hb */
-       tmp = RREG32(RADEON_CRTC_OFFSET_CNTL + radeon_crtc->crtc_offset);
-       tmp &= ~RADEON_CRTC_OFFSET_FLIP_CNTL;
-       /* make sure pending bit is asserted */
-       tmp |= RADEON_CRTC_GUI_TRIG_OFFSET_LEFT_EN;
-       WREG32(RADEON_CRTC_OFFSET_CNTL + radeon_crtc->crtc_offset, tmp);
-
-       /* set pageflip to happen as late as possible in the vblank interval.
-        * same field for crtc1/2
-        */
-       tmp = RREG32(RADEON_CRTC_GEN_CNTL);
-       tmp &= ~RADEON_CRTC_VSTAT_MODE_MASK;
-       WREG32(RADEON_CRTC_GEN_CNTL, tmp);
-
        /* enable the pflip int */
        radeon_irq_kms_pflip_irq_get(rdev, crtc);
 }
@@ -1031,8 +1014,8 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size)
        WREG32(RADEON_CP_CSQ_MODE,
               REG_SET(RADEON_INDIRECT2_START, indirect2_start) |
               REG_SET(RADEON_INDIRECT1_START, indirect1_start));
-       WREG32(0x718, 0);
-       WREG32(0x744, 0x00004D4D);
+       WREG32(RADEON_CP_RB_WPTR_DELAY, 0);
+       WREG32(RADEON_CP_CSQ_MODE, 0x00004D4D);
        WREG32(RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIBM_INDBM);
        radeon_ring_start(rdev);
        r = radeon_ring_test(rdev);
@@ -1041,7 +1024,7 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size)
                return r;
        }
        rdev->cp.ready = true;
-       rdev->mc.active_vram_size = rdev->mc.real_vram_size;
+       radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
        return 0;
 }
 
@@ -1059,7 +1042,7 @@ void r100_cp_fini(struct radeon_device *rdev)
 void r100_cp_disable(struct radeon_device *rdev)
 {
        /* Disable ring */
-       rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
+       radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
        rdev->cp.ready = false;
        WREG32(RADEON_CP_CSQ_MODE, 0);
        WREG32(RADEON_CP_CSQ_CNTL, 0);
@@ -1427,6 +1410,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                }
                track->zb.robj = reloc->robj;
                track->zb.offset = idx_value;
+               track->zb_dirty = true;
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                break;
        case RADEON_RB3D_COLOROFFSET:
@@ -1439,6 +1423,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                }
                track->cb[0].robj = reloc->robj;
                track->cb[0].offset = idx_value;
+               track->cb_dirty = true;
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                break;
        case RADEON_PP_TXOFFSET_0:
@@ -1454,6 +1439,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                }
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                track->textures[i].robj = reloc->robj;
+               track->tex_dirty = true;
                break;
        case RADEON_PP_CUBIC_OFFSET_T0_0:
        case RADEON_PP_CUBIC_OFFSET_T0_1:
@@ -1471,6 +1457,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                track->textures[0].cube_info[i].offset = idx_value;
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                track->textures[0].cube_info[i].robj = reloc->robj;
+               track->tex_dirty = true;
                break;
        case RADEON_PP_CUBIC_OFFSET_T1_0:
        case RADEON_PP_CUBIC_OFFSET_T1_1:
@@ -1488,6 +1475,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                track->textures[1].cube_info[i].offset = idx_value;
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                track->textures[1].cube_info[i].robj = reloc->robj;
+               track->tex_dirty = true;
                break;
        case RADEON_PP_CUBIC_OFFSET_T2_0:
        case RADEON_PP_CUBIC_OFFSET_T2_1:
@@ -1505,9 +1493,12 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                track->textures[2].cube_info[i].offset = idx_value;
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                track->textures[2].cube_info[i].robj = reloc->robj;
+               track->tex_dirty = true;
                break;
        case RADEON_RE_WIDTH_HEIGHT:
                track->maxy = ((idx_value >> 16) & 0x7FF);
+               track->cb_dirty = true;
+               track->zb_dirty = true;
                break;
        case RADEON_RB3D_COLORPITCH:
                r = r100_cs_packet_next_reloc(p, &reloc);
@@ -1528,9 +1519,11 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                ib[idx] = tmp;
 
                track->cb[0].pitch = idx_value & RADEON_COLORPITCH_MASK;
+               track->cb_dirty = true;
                break;
        case RADEON_RB3D_DEPTHPITCH:
                track->zb.pitch = idx_value & RADEON_DEPTHPITCH_MASK;
+               track->zb_dirty = true;
                break;
        case RADEON_RB3D_CNTL:
                switch ((idx_value >> RADEON_RB3D_COLOR_FORMAT_SHIFT) & 0x1f) {
@@ -1555,6 +1548,8 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                        return -EINVAL;
                }
                track->z_enabled = !!(idx_value & RADEON_Z_ENABLE);
+               track->cb_dirty = true;
+               track->zb_dirty = true;
                break;
        case RADEON_RB3D_ZSTENCILCNTL:
                switch (idx_value & 0xf) {
@@ -1572,6 +1567,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                default:
                        break;
                }
+               track->zb_dirty = true;
                break;
        case RADEON_RB3D_ZPASS_ADDR:
                r = r100_cs_packet_next_reloc(p, &reloc);
@@ -1588,6 +1584,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                        uint32_t temp = idx_value >> 4;
                        for (i = 0; i < track->num_texture; i++)
                                track->textures[i].enabled = !!(temp & (1 << i));
+                       track->tex_dirty = true;
                }
                break;
        case RADEON_SE_VF_CNTL:
@@ -1602,12 +1599,14 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                i = (reg - RADEON_PP_TEX_SIZE_0) / 8;
                track->textures[i].width = (idx_value & RADEON_TEX_USIZE_MASK) + 1;
                track->textures[i].height = ((idx_value & RADEON_TEX_VSIZE_MASK) >> RADEON_TEX_VSIZE_SHIFT) + 1;
+               track->tex_dirty = true;
                break;
        case RADEON_PP_TEX_PITCH_0:
        case RADEON_PP_TEX_PITCH_1:
        case RADEON_PP_TEX_PITCH_2:
                i = (reg - RADEON_PP_TEX_PITCH_0) / 8;
                track->textures[i].pitch = idx_value + 32;
+               track->tex_dirty = true;
                break;
        case RADEON_PP_TXFILTER_0:
        case RADEON_PP_TXFILTER_1:
@@ -1621,6 +1620,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                tmp = (idx_value >> 27) & 0x7;
                if (tmp == 2 || tmp == 6)
                        track->textures[i].roundup_h = false;
+               track->tex_dirty = true;
                break;
        case RADEON_PP_TXFORMAT_0:
        case RADEON_PP_TXFORMAT_1:
@@ -1673,6 +1673,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                }
                track->textures[i].cube_info[4].width = 1 << ((idx_value >> 16) & 0xf);
                track->textures[i].cube_info[4].height = 1 << ((idx_value >> 20) & 0xf);
+               track->tex_dirty = true;
                break;
        case RADEON_PP_CUBIC_FACES_0:
        case RADEON_PP_CUBIC_FACES_1:
@@ -1683,6 +1684,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                        track->textures[i].cube_info[face].width = 1 << ((tmp >> (face * 8)) & 0xf);
                        track->textures[i].cube_info[face].height = 1 << ((tmp >> ((face * 8) + 4)) & 0xf);
                }
+               track->tex_dirty = true;
                break;
        default:
                printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n",
@@ -2310,7 +2312,6 @@ void r100_vram_init_sizes(struct radeon_device *rdev)
        /* FIXME we don't use the second aperture yet when we could use it */
        if (rdev->mc.visible_vram_size > rdev->mc.aper_size)
                rdev->mc.visible_vram_size = rdev->mc.aper_size;
-       rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
        config_aper_size = RREG32(RADEON_CONFIG_APER_SIZE);
        if (rdev->flags & RADEON_IS_IGP) {
                uint32_t tom;
@@ -2347,10 +2348,10 @@ void r100_vga_set_state(struct radeon_device *rdev, bool state)
 
        temp = RREG32(RADEON_CONFIG_CNTL);
        if (state == false) {
-               temp &= ~(1<<8);
-               temp |= (1<<9);
+               temp &= ~RADEON_CFG_VGA_RAM_EN;
+               temp |= RADEON_CFG_VGA_IO_DIS;
        } else {
-               temp &= ~(1<<9);
+               temp &= ~RADEON_CFG_VGA_IO_DIS;
        }
        WREG32(RADEON_CONFIG_CNTL, temp);
 }
@@ -3318,9 +3319,9 @@ int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track)
        unsigned long size;
        unsigned prim_walk;
        unsigned nverts;
-       unsigned num_cb = track->num_cb;
+       unsigned num_cb = track->cb_dirty ? track->num_cb : 0;
 
-       if (!track->zb_cb_clear && !track->color_channel_mask &&
+       if (num_cb && !track->zb_cb_clear && !track->color_channel_mask &&
            !track->blend_read_enable)
                num_cb = 0;
 
@@ -3341,7 +3342,9 @@ int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track)
                        return -EINVAL;
                }
        }
-       if (track->z_enabled) {
+       track->cb_dirty = false;
+
+       if (track->zb_dirty && track->z_enabled) {
                if (track->zb.robj == NULL) {
                        DRM_ERROR("[drm] No buffer for z buffer !\n");
                        return -EINVAL;
@@ -3358,6 +3361,28 @@ int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track)
                        return -EINVAL;
                }
        }
+       track->zb_dirty = false;
+
+       if (track->aa_dirty && track->aaresolve) {
+               if (track->aa.robj == NULL) {
+                       DRM_ERROR("[drm] No buffer for AA resolve buffer %d !\n", i);
+                       return -EINVAL;
+               }
+               /* I believe the format comes from colorbuffer0. */
+               size = track->aa.pitch * track->cb[0].cpp * track->maxy;
+               size += track->aa.offset;
+               if (size > radeon_bo_size(track->aa.robj)) {
+                       DRM_ERROR("[drm] Buffer too small for AA resolve buffer %d "
+                                 "(need %lu have %lu) !\n", i, size,
+                                 radeon_bo_size(track->aa.robj));
+                       DRM_ERROR("[drm] AA resolve buffer %d (%u %u %u %u)\n",
+                                 i, track->aa.pitch, track->cb[0].cpp,
+                                 track->aa.offset, track->maxy);
+                       return -EINVAL;
+               }
+       }
+       track->aa_dirty = false;
+
        prim_walk = (track->vap_vf_cntl >> 4) & 0x3;
        if (track->vap_vf_cntl & (1 << 14)) {
                nverts = track->vap_alt_nverts;
@@ -3417,13 +3442,23 @@ int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track)
                          prim_walk);
                return -EINVAL;
        }
-       return r100_cs_track_texture_check(rdev, track);
+
+       if (track->tex_dirty) {
+               track->tex_dirty = false;
+               return r100_cs_track_texture_check(rdev, track);
+       }
+       return 0;
 }
 
 void r100_cs_track_clear(struct radeon_device *rdev, struct r100_cs_track *track)
 {
        unsigned i, face;
 
+       track->cb_dirty = true;
+       track->zb_dirty = true;
+       track->tex_dirty = true;
+       track->aa_dirty = true;
+
        if (rdev->family < CHIP_R300) {
                track->num_cb = 1;
                if (rdev->family <= CHIP_RS200)
@@ -3437,6 +3472,8 @@ void r100_cs_track_clear(struct radeon_device *rdev, struct r100_cs_track *track
                track->num_texture = 16;
                track->maxy = 4096;
                track->separate_cube = 0;
+               track->aaresolve = false;
+               track->aa.robj = NULL;
        }
 
        for (i = 0; i < track->num_cb; i++) {
@@ -3746,8 +3783,6 @@ static int r100_startup(struct radeon_device *rdev)
        r100_mc_program(rdev);
        /* Resume clock */
        r100_clock_startup(rdev);
-       /* Initialize GPU configuration (# pipes, ...) */
-//     r100_gpu_init(rdev);
        /* Initialize GART (initialize after TTM so we can allocate
         * memory through TTM but finalize after TTM) */
        r100_enable_bm(rdev);
index af65600..2fef9de 100644 (file)
@@ -52,14 +52,7 @@ struct r100_cs_track_texture {
        unsigned                compress_format;
 };
 
-struct r100_cs_track_limits {
-       unsigned num_cb;
-       unsigned num_texture;
-       unsigned max_levels;
-};
-
 struct r100_cs_track {
-       struct radeon_device *rdev;
        unsigned                        num_cb;
        unsigned                        num_texture;
        unsigned                        maxy;
@@ -73,11 +66,17 @@ struct r100_cs_track {
        struct r100_cs_track_array      arrays[11];
        struct r100_cs_track_cb         cb[R300_MAX_CB];
        struct r100_cs_track_cb         zb;
+       struct r100_cs_track_cb         aa;
        struct r100_cs_track_texture    textures[R300_TRACK_MAX_TEXTURE];
        bool                            z_enabled;
        bool                            separate_cube;
        bool                            zb_cb_clear;
        bool                            blend_read_enable;
+       bool                            cb_dirty;
+       bool                            zb_dirty;
+       bool                            tex_dirty;
+       bool                            aa_dirty;
+       bool                            aaresolve;
 };
 
 int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track);
index d2408c3..f240583 100644 (file)
@@ -184,6 +184,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                }
                track->zb.robj = reloc->robj;
                track->zb.offset = idx_value;
+               track->zb_dirty = true;
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                break;
        case RADEON_RB3D_COLOROFFSET:
@@ -196,6 +197,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                }
                track->cb[0].robj = reloc->robj;
                track->cb[0].offset = idx_value;
+               track->cb_dirty = true;
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                break;
        case R200_PP_TXOFFSET_0:
@@ -214,6 +216,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                }
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                track->textures[i].robj = reloc->robj;
+               track->tex_dirty = true;
                break;
        case R200_PP_CUBIC_OFFSET_F1_0:
        case R200_PP_CUBIC_OFFSET_F2_0:
@@ -257,9 +260,12 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                track->textures[i].cube_info[face - 1].offset = idx_value;
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                track->textures[i].cube_info[face - 1].robj = reloc->robj;
+               track->tex_dirty = true;
                break;
        case RADEON_RE_WIDTH_HEIGHT:
                track->maxy = ((idx_value >> 16) & 0x7FF);
+               track->cb_dirty = true;
+               track->zb_dirty = true;
                break;
        case RADEON_RB3D_COLORPITCH:
                r = r100_cs_packet_next_reloc(p, &reloc);
@@ -280,9 +286,11 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                ib[idx] = tmp;
 
                track->cb[0].pitch = idx_value & RADEON_COLORPITCH_MASK;
+               track->cb_dirty = true;
                break;
        case RADEON_RB3D_DEPTHPITCH:
                track->zb.pitch = idx_value & RADEON_DEPTHPITCH_MASK;
+               track->zb_dirty = true;
                break;
        case RADEON_RB3D_CNTL:
                switch ((idx_value >> RADEON_RB3D_COLOR_FORMAT_SHIFT) & 0x1f) {
@@ -312,6 +320,8 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                }
 
                track->z_enabled = !!(idx_value & RADEON_Z_ENABLE);
+               track->cb_dirty = true;
+               track->zb_dirty = true;
                break;
        case RADEON_RB3D_ZSTENCILCNTL:
                switch (idx_value & 0xf) {
@@ -329,6 +339,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                default:
                        break;
                }
+               track->zb_dirty = true;
                break;
        case RADEON_RB3D_ZPASS_ADDR:
                r = r100_cs_packet_next_reloc(p, &reloc);
@@ -345,6 +356,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                        uint32_t temp = idx_value >> 4;
                        for (i = 0; i < track->num_texture; i++)
                                track->textures[i].enabled = !!(temp & (1 << i));
+                       track->tex_dirty = true;
                }
                break;
        case RADEON_SE_VF_CNTL:
@@ -369,6 +381,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                i = (reg - R200_PP_TXSIZE_0) / 32;
                track->textures[i].width = (idx_value & RADEON_TEX_USIZE_MASK) + 1;
                track->textures[i].height = ((idx_value & RADEON_TEX_VSIZE_MASK) >> RADEON_TEX_VSIZE_SHIFT) + 1;
+               track->tex_dirty = true;
                break;
        case R200_PP_TXPITCH_0:
        case R200_PP_TXPITCH_1:
@@ -378,6 +391,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
        case R200_PP_TXPITCH_5:
                i = (reg - R200_PP_TXPITCH_0) / 32;
                track->textures[i].pitch = idx_value + 32;
+               track->tex_dirty = true;
                break;
        case R200_PP_TXFILTER_0:
        case R200_PP_TXFILTER_1:
@@ -394,6 +408,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                tmp = (idx_value >> 27) & 0x7;
                if (tmp == 2 || tmp == 6)
                        track->textures[i].roundup_h = false;
+               track->tex_dirty = true;
                break;
        case R200_PP_TXMULTI_CTL_0:
        case R200_PP_TXMULTI_CTL_1:
@@ -432,6 +447,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                        track->textures[i].tex_coord_type = 1;
                        break;
                }
+               track->tex_dirty = true;
                break;
        case R200_PP_TXFORMAT_0:
        case R200_PP_TXFORMAT_1:
@@ -488,6 +504,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                }
                track->textures[i].cube_info[4].width = 1 << ((idx_value >> 16) & 0xf);
                track->textures[i].cube_info[4].height = 1 << ((idx_value >> 20) & 0xf);
+               track->tex_dirty = true;
                break;
        case R200_PP_CUBIC_FACES_0:
        case R200_PP_CUBIC_FACES_1:
@@ -501,6 +518,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                        track->textures[i].cube_info[face].width = 1 << ((tmp >> (face * 8)) & 0xf);
                        track->textures[i].cube_info[face].height = 1 << ((tmp >> ((face * 8) + 4)) & 0xf);
                }
+               track->tex_dirty = true;
                break;
        default:
                printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n",
index cf862ca..069efa8 100644 (file)
@@ -69,6 +69,9 @@ void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev)
        mb();
 }
 
+#define R300_PTE_WRITEABLE (1 << 2)
+#define R300_PTE_READABLE  (1 << 3)
+
 int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
 {
        void __iomem *ptr = (void *)rdev->gart.table.vram.ptr;
@@ -78,7 +81,7 @@ int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
        }
        addr = (lower_32_bits(addr) >> 8) |
               ((upper_32_bits(addr) & 0xff) << 24) |
-              0xc;
+              R300_PTE_WRITEABLE | R300_PTE_READABLE;
        /* on x86 we want this to be CPU endian, on powerpc
         * on powerpc without HW swappers, it'll get swapped on way
         * into VRAM - so no need for cpu_to_le32 on VRAM tables */
@@ -135,7 +138,7 @@ int rv370_pcie_gart_enable(struct radeon_device *rdev)
        WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_LO, rdev->mc.vram_start);
        WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_HI, 0);
        /* Clear error */
-       WREG32_PCIE(0x18, 0);
+       WREG32_PCIE(RADEON_PCIE_TX_GART_ERROR, 0);
        tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL);
        tmp |= RADEON_PCIE_TX_GART_EN;
        tmp |= RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD;
@@ -664,6 +667,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                }
                track->cb[i].robj = reloc->robj;
                track->cb[i].offset = idx_value;
+               track->cb_dirty = true;
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                break;
        case R300_ZB_DEPTHOFFSET:
@@ -676,6 +680,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                }
                track->zb.robj = reloc->robj;
                track->zb.offset = idx_value;
+               track->zb_dirty = true;
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                break;
        case R300_TX_OFFSET_0:
@@ -714,6 +719,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                tmp |= tile_flags;
                ib[idx] = tmp;
                track->textures[i].robj = reloc->robj;
+               track->tex_dirty = true;
                break;
        /* Tracked registers */
        case 0x2084:
@@ -740,6 +746,8 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                if (p->rdev->family < CHIP_RV515) {
                        track->maxy -= 1440;
                }
+               track->cb_dirty = true;
+               track->zb_dirty = true;
                break;
        case 0x4E00:
                /* RB3D_CCTL */
@@ -749,6 +757,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                        return -EINVAL;
                }
                track->num_cb = ((idx_value >> 5) & 0x3) + 1;
+               track->cb_dirty = true;
                break;
        case 0x4E38:
        case 0x4E3C:
@@ -811,6 +820,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                                  ((idx_value >> 21) & 0xF));
                        return -EINVAL;
                }
+               track->cb_dirty = true;
                break;
        case 0x4F00:
                /* ZB_CNTL */
@@ -819,6 +829,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                } else {
                        track->z_enabled = false;
                }
+               track->zb_dirty = true;
                break;
        case 0x4F10:
                /* ZB_FORMAT */
@@ -835,6 +846,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                                  (idx_value & 0xF));
                        return -EINVAL;
                }
+               track->zb_dirty = true;
                break;
        case 0x4F24:
                /* ZB_DEPTHPITCH */
@@ -858,14 +870,17 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                ib[idx] = tmp;
 
                track->zb.pitch = idx_value & 0x3FFC;
+               track->zb_dirty = true;
                break;
        case 0x4104:
+               /* TX_ENABLE */
                for (i = 0; i < 16; i++) {
                        bool enabled;
 
                        enabled = !!(idx_value & (1 << i));
                        track->textures[i].enabled = enabled;
                }
+               track->tex_dirty = true;
                break;
        case 0x44C0:
        case 0x44C4:
@@ -895,6 +910,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                        track->textures[i].compress_format = R100_TRACK_COMP_NONE;
                        break;
                case R300_TX_FORMAT_X16:
+               case R300_TX_FORMAT_FL_I16:
                case R300_TX_FORMAT_Y8X8:
                case R300_TX_FORMAT_Z5Y6X5:
                case R300_TX_FORMAT_Z6Y5X5:
@@ -907,6 +923,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                        track->textures[i].compress_format = R100_TRACK_COMP_NONE;
                        break;
                case R300_TX_FORMAT_Y16X16:
+               case R300_TX_FORMAT_FL_I16A16:
                case R300_TX_FORMAT_Z11Y11X10:
                case R300_TX_FORMAT_Z10Y11X11:
                case R300_TX_FORMAT_W8Z8Y8X8:
@@ -948,8 +965,8 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                        DRM_ERROR("Invalid texture format %u\n",
                                  (idx_value & 0x1F));
                        return -EINVAL;
-                       break;
                }
+               track->tex_dirty = true;
                break;
        case 0x4400:
        case 0x4404:
@@ -977,6 +994,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                if (tmp == 2 || tmp == 4 || tmp == 6) {
                        track->textures[i].roundup_h = false;
                }
+               track->tex_dirty = true;
                break;
        case 0x4500:
        case 0x4504:
@@ -1014,6 +1032,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                        DRM_ERROR("Forbidden bit TXFORMAT_MSB\n");
                        return -EINVAL;
                }
+               track->tex_dirty = true;
                break;
        case 0x4480:
        case 0x4484:
@@ -1043,6 +1062,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                track->textures[i].use_pitch = !!tmp;
                tmp = (idx_value >> 22) & 0xF;
                track->textures[i].txdepth = tmp;
+               track->tex_dirty = true;
                break;
        case R300_ZB_ZPASS_ADDR:
                r = r100_cs_packet_next_reloc(p, &reloc);
@@ -1057,6 +1077,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
        case 0x4e0c:
                /* RB3D_COLOR_CHANNEL_MASK */
                track->color_channel_mask = idx_value;
+               track->cb_dirty = true;
                break;
        case 0x43a4:
                /* SC_HYPERZ_EN */
@@ -1070,6 +1091,8 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
        case 0x4f1c:
                /* ZB_BW_CNTL */
                track->zb_cb_clear = !!(idx_value & (1 << 5));
+               track->cb_dirty = true;
+               track->zb_dirty = true;
                if (p->rdev->hyperz_filp != p->filp) {
                        if (idx_value & (R300_HIZ_ENABLE |
                                         R300_RD_COMP_ENABLE |
@@ -1081,8 +1104,28 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
        case 0x4e04:
                /* RB3D_BLENDCNTL */
                track->blend_read_enable = !!(idx_value & (1 << 2));
+               track->cb_dirty = true;
+               break;
+       case R300_RB3D_AARESOLVE_OFFSET:
+               r = r100_cs_packet_next_reloc(p, &reloc);
+               if (r) {
+                       DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
+                                 idx, reg);
+                       r100_cs_dump_packet(p, pkt);
+                       return r;
+               }
+               track->aa.robj = reloc->robj;
+               track->aa.offset = idx_value;
+               track->aa_dirty = true;
+               ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
+               break;
+       case R300_RB3D_AARESOLVE_PITCH:
+               track->aa.pitch = idx_value & 0x3FFE;
+               track->aa_dirty = true;
                break;
-       case 0x4f28: /* ZB_DEPTHCLEARVALUE */
+       case R300_RB3D_AARESOLVE_CTL:
+               track->aaresolve = idx_value & 0x1;
+               track->aa_dirty = true;
                break;
        case 0x4f30: /* ZB_MASK_OFFSET */
        case 0x4f34: /* ZB_ZMASK_PITCH */
index 1a0d536..f0bce39 100644 (file)
 #define R300_RB3D_COLORPITCH2               0x4E40 /* GUESS */
 #define R300_RB3D_COLORPITCH3               0x4E44 /* GUESS */
 
+#define R300_RB3D_AARESOLVE_OFFSET          0x4E80
+#define R300_RB3D_AARESOLVE_PITCH           0x4E84
 #define R300_RB3D_AARESOLVE_CTL             0x4E88
 /* gap */
 
index c387346..0b59ed7 100644 (file)
@@ -96,7 +96,7 @@ void r420_pipes_init(struct radeon_device *rdev)
                       "programming pipes. Bad things might happen.\n");
        }
        /* get max number of pipes */
-       gb_pipe_select = RREG32(0x402C);
+       gb_pipe_select = RREG32(R400_GB_PIPE_SELECT);
        num_pipes = ((gb_pipe_select >> 12) & 3) + 1;
 
        /* SE chips have 1 pipe */
index 3c8677f..2ce80d9 100644 (file)
@@ -79,8 +79,8 @@ static void r520_gpu_init(struct radeon_device *rdev)
                WREG32(0x4128, 0xFF);
        }
        r420_pipes_init(rdev);
-       gb_pipe_select = RREG32(0x402C);
-       tmp = RREG32(0x170C);
+       gb_pipe_select = RREG32(R400_GB_PIPE_SELECT);
+       tmp = RREG32(R300_DST_PIPE_CONFIG);
        pipe_select_current = (tmp >> 2) & 3;
        tmp = (1 << pipe_select_current) |
              (((gb_pipe_select >> 8) & 0xF) << 4);
index 1e10e3e..9b3fad2 100644 (file)
@@ -97,12 +97,16 @@ void r600_irq_disable(struct radeon_device *rdev);
 static void r600_pcie_gen2_enable(struct radeon_device *rdev);
 
 /* get temperature in millidegrees */
-u32 rv6xx_get_temp(struct radeon_device *rdev)
+int rv6xx_get_temp(struct radeon_device *rdev)
 {
        u32 temp = (RREG32(CG_THERMAL_STATUS) & ASIC_T_MASK) >>
                ASIC_T_SHIFT;
+       int actual_temp = temp & 0xff;
 
-       return temp * 1000;
+       if (temp & 0x100)
+               actual_temp -= 256;
+
+       return actual_temp * 1000;
 }
 
 void r600_pm_get_dynpm_state(struct radeon_device *rdev)
@@ -1251,7 +1255,6 @@ int r600_mc_init(struct radeon_device *rdev)
        rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE);
        rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE);
        rdev->mc.visible_vram_size = rdev->mc.aper_size;
-       rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
        r600_vram_gtt_location(rdev, &rdev->mc);
 
        if (rdev->flags & RADEON_IS_IGP) {
@@ -1933,7 +1936,7 @@ void r600_pciep_wreg(struct radeon_device *rdev, u32 reg, u32 v)
  */
 void r600_cp_stop(struct radeon_device *rdev)
 {
-       rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
+       radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
        WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1));
        WREG32(SCRATCH_UMSK, 0);
 }
@@ -2101,7 +2104,11 @@ static int r600_cp_load_microcode(struct radeon_device *rdev)
 
        r600_cp_stop(rdev);
 
-       WREG32(CP_RB_CNTL, RB_NO_UPDATE | RB_BLKSZ(15) | RB_BUFSZ(3));
+       WREG32(CP_RB_CNTL,
+#ifdef __BIG_ENDIAN
+              BUF_SWAP_32BIT |
+#endif
+              RB_NO_UPDATE | RB_BLKSZ(15) | RB_BUFSZ(3));
 
        /* Reset cp */
        WREG32(GRBM_SOFT_RESET, SOFT_RESET_CP);
@@ -2188,7 +2195,11 @@ int r600_cp_resume(struct radeon_device *rdev)
        WREG32(CP_RB_WPTR, 0);
 
        /* set the wb address whether it's enabled or not */
-       WREG32(CP_RB_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC);
+       WREG32(CP_RB_RPTR_ADDR,
+#ifdef __BIG_ENDIAN
+              RB_RPTR_SWAP(2) |
+#endif
+              ((rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC));
        WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFF);
        WREG32(SCRATCH_ADDR, ((rdev->wb.gpu_addr + RADEON_WB_SCRATCH_OFFSET) >> 8) & 0xFFFFFFFF);
 
@@ -2624,7 +2635,11 @@ void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
 {
        /* FIXME: implement */
        radeon_ring_write(rdev, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
-       radeon_ring_write(rdev, ib->gpu_addr & 0xFFFFFFFC);
+       radeon_ring_write(rdev,
+#ifdef __BIG_ENDIAN
+                         (2 << 0) |
+#endif
+                         (ib->gpu_addr & 0xFFFFFFFC));
        radeon_ring_write(rdev, upper_32_bits(ib->gpu_addr) & 0xFF);
        radeon_ring_write(rdev, ib->length_dw);
 }
@@ -3293,8 +3308,8 @@ restart_ih:
        while (rptr != wptr) {
                /* wptr/rptr are in bytes! */
                ring_index = rptr / 4;
-               src_id =  rdev->ih.ring[ring_index] & 0xff;
-               src_data = rdev->ih.ring[ring_index + 1] & 0xfffffff;
+               src_id = le32_to_cpu(rdev->ih.ring[ring_index]) & 0xff;
+               src_data = le32_to_cpu(rdev->ih.ring[ring_index + 1]) & 0xfffffff;
 
                switch (src_id) {
                case 1: /* D1 vblank/vline */
index ca5c29f..7f10434 100644 (file)
@@ -137,9 +137,9 @@ set_shaders(struct drm_device *dev)
        ps = (u32 *) ((char *)dev->agp_buffer_map->handle + dev_priv->blit_vb->offset + 256);
 
        for (i = 0; i < r6xx_vs_size; i++)
-               vs[i] = r6xx_vs[i];
+               vs[i] = cpu_to_le32(r6xx_vs[i]);
        for (i = 0; i < r6xx_ps_size; i++)
-               ps[i] = r6xx_ps[i];
+               ps[i] = cpu_to_le32(r6xx_ps[i]);
 
        dev_priv->blit_vb->used = 512;
 
@@ -192,6 +192,9 @@ set_vtx_resource(drm_radeon_private_t *dev_priv, u64 gpu_addr)
        DRM_DEBUG("\n");
 
        sq_vtx_constant_word2 = (((gpu_addr >> 32) & 0xff) | (16 << 8));
+#ifdef __BIG_ENDIAN
+       sq_vtx_constant_word2 |= (2 << 30);
+#endif
 
        BEGIN_RING(9);
        OUT_RING(CP_PACKET3(R600_IT_SET_RESOURCE, 7));
@@ -291,7 +294,11 @@ draw_auto(drm_radeon_private_t *dev_priv)
        OUT_RING(DI_PT_RECTLIST);
 
        OUT_RING(CP_PACKET3(R600_IT_INDEX_TYPE, 0));
+#ifdef __BIG_ENDIAN
+       OUT_RING((2 << 2) | DI_INDEX_SIZE_16_BIT);
+#else
        OUT_RING(DI_INDEX_SIZE_16_BIT);
+#endif
 
        OUT_RING(CP_PACKET3(R600_IT_NUM_INSTANCES, 0));
        OUT_RING(1);
index 86e5aa0..df68d91 100644 (file)
@@ -54,7 +54,7 @@ set_render_target(struct radeon_device *rdev, int format,
        if (h < 8)
                h = 8;
 
-       cb_color_info = ((format << 2) | (1 << 27));
+       cb_color_info = ((format << 2) | (1 << 27) | (1 << 8));
        pitch = (w / 8) - 1;
        slice = ((w * h) / 64) - 1;
 
@@ -165,6 +165,9 @@ set_vtx_resource(struct radeon_device *rdev, u64 gpu_addr)
        u32 sq_vtx_constant_word2;
 
        sq_vtx_constant_word2 = ((upper_32_bits(gpu_addr) & 0xff) | (16 << 8));
+#ifdef __BIG_ENDIAN
+       sq_vtx_constant_word2 |= (2 << 30);
+#endif
 
        radeon_ring_write(rdev, PACKET3(PACKET3_SET_RESOURCE, 7));
        radeon_ring_write(rdev, 0x460);
@@ -199,7 +202,7 @@ set_tex_resource(struct radeon_device *rdev,
        if (h < 1)
                h = 1;
 
-       sq_tex_resource_word0 = (1 << 0);
+       sq_tex_resource_word0 = (1 << 0) | (1 << 3);
        sq_tex_resource_word0 |= ((((pitch >> 3) - 1) << 8) |
                                  ((w - 1) << 19));
 
@@ -253,7 +256,11 @@ draw_auto(struct radeon_device *rdev)
        radeon_ring_write(rdev, DI_PT_RECTLIST);
 
        radeon_ring_write(rdev, PACKET3(PACKET3_INDEX_TYPE, 0));
-       radeon_ring_write(rdev, DI_INDEX_SIZE_16_BIT);
+       radeon_ring_write(rdev,
+#ifdef __BIG_ENDIAN
+                         (2 << 2) |
+#endif
+                         DI_INDEX_SIZE_16_BIT);
 
        radeon_ring_write(rdev, PACKET3(PACKET3_NUM_INSTANCES, 0));
        radeon_ring_write(rdev, 1);
@@ -424,7 +431,11 @@ set_default_state(struct radeon_device *rdev)
        dwords = ALIGN(rdev->r600_blit.state_len, 0x10);
        gpu_addr = rdev->r600_blit.shader_gpu_addr + rdev->r600_blit.state_offset;
        radeon_ring_write(rdev, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
-       radeon_ring_write(rdev, gpu_addr & 0xFFFFFFFC);
+       radeon_ring_write(rdev,
+#ifdef __BIG_ENDIAN
+                         (2 << 0) |
+#endif
+                         (gpu_addr & 0xFFFFFFFC));
        radeon_ring_write(rdev, upper_32_bits(gpu_addr) & 0xFF);
        radeon_ring_write(rdev, dwords);
 
@@ -467,7 +478,7 @@ static inline uint32_t i2f(uint32_t input)
 int r600_blit_init(struct radeon_device *rdev)
 {
        u32 obj_size;
-       int r, dwords;
+       int i, r, dwords;
        void *ptr;
        u32 packet2s[16];
        int num_packet2s = 0;
@@ -486,7 +497,7 @@ int r600_blit_init(struct radeon_device *rdev)
 
        dwords = rdev->r600_blit.state_len;
        while (dwords & 0xf) {
-               packet2s[num_packet2s++] = PACKET2(0);
+               packet2s[num_packet2s++] = cpu_to_le32(PACKET2(0));
                dwords++;
        }
 
@@ -529,8 +540,10 @@ int r600_blit_init(struct radeon_device *rdev)
        if (num_packet2s)
                memcpy_toio(ptr + rdev->r600_blit.state_offset + (rdev->r600_blit.state_len * 4),
                            packet2s, num_packet2s * 4);
-       memcpy(ptr + rdev->r600_blit.vs_offset, r6xx_vs, r6xx_vs_size * 4);
-       memcpy(ptr + rdev->r600_blit.ps_offset, r6xx_ps, r6xx_ps_size * 4);
+       for (i = 0; i < r6xx_vs_size; i++)
+               *(u32 *)((unsigned long)ptr + rdev->r600_blit.vs_offset + i * 4) = cpu_to_le32(r6xx_vs[i]);
+       for (i = 0; i < r6xx_ps_size; i++)
+               *(u32 *)((unsigned long)ptr + rdev->r600_blit.ps_offset + i * 4) = cpu_to_le32(r6xx_ps[i]);
        radeon_bo_kunmap(rdev->r600_blit.shader_obj);
        radeon_bo_unreserve(rdev->r600_blit.shader_obj);
 
@@ -545,7 +558,7 @@ done:
                dev_err(rdev->dev, "(%d) pin blit object failed\n", r);
                return r;
        }
-       rdev->mc.active_vram_size = rdev->mc.real_vram_size;
+       radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
        return 0;
 }
 
@@ -553,7 +566,7 @@ void r600_blit_fini(struct radeon_device *rdev)
 {
        int r;
 
-       rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
+       radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
        if (rdev->r600_blit.shader_obj == NULL)
                return;
        /* If we can't reserve the bo, unref should be enough to destroy
index e8151c1..2d1f6c5 100644 (file)
@@ -684,7 +684,11 @@ const u32 r6xx_vs[] =
        0x00000000,
        0x3c000000,
        0x68cd1000,
+#ifdef __BIG_ENDIAN
+       0x000a0000,
+#else
        0x00080000,
+#endif
        0x00000000,
 };
 
index 4f4cd8b..c3ab959 100644 (file)
@@ -396,6 +396,9 @@ static void r600_cp_load_microcode(drm_radeon_private_t *dev_priv)
        r600_do_cp_stop(dev_priv);
 
        RADEON_WRITE(R600_CP_RB_CNTL,
+#ifdef __BIG_ENDIAN
+                    R600_BUF_SWAP_32BIT |
+#endif
                     R600_RB_NO_UPDATE |
                     R600_RB_BLKSZ(15) |
                     R600_RB_BUFSZ(3));
@@ -486,9 +489,12 @@ static void r700_cp_load_microcode(drm_radeon_private_t *dev_priv)
        r600_do_cp_stop(dev_priv);
 
        RADEON_WRITE(R600_CP_RB_CNTL,
+#ifdef __BIG_ENDIAN
+                    R600_BUF_SWAP_32BIT |
+#endif
                     R600_RB_NO_UPDATE |
-                    (15 << 8) |
-                    (3 << 0));
+                    R600_RB_BLKSZ(15) |
+                    R600_RB_BUFSZ(3));
 
        RADEON_WRITE(R600_GRBM_SOFT_RESET, R600_SOFT_RESET_CP);
        RADEON_READ(R600_GRBM_SOFT_RESET);
@@ -550,8 +556,12 @@ static void r600_test_writeback(drm_radeon_private_t *dev_priv)
 
        if (!dev_priv->writeback_works) {
                /* Disable writeback to avoid unnecessary bus master transfer */
-               RADEON_WRITE(R600_CP_RB_CNTL, RADEON_READ(R600_CP_RB_CNTL) |
-                            RADEON_RB_NO_UPDATE);
+               RADEON_WRITE(R600_CP_RB_CNTL,
+#ifdef __BIG_ENDIAN
+                            R600_BUF_SWAP_32BIT |
+#endif
+                            RADEON_READ(R600_CP_RB_CNTL) |
+                            R600_RB_NO_UPDATE);
                RADEON_WRITE(R600_SCRATCH_UMSK, 0);
        }
 }
@@ -575,7 +585,11 @@ int r600_do_engine_reset(struct drm_device *dev)
 
        RADEON_WRITE(R600_CP_RB_WPTR_DELAY, 0);
        cp_rb_cntl = RADEON_READ(R600_CP_RB_CNTL);
-       RADEON_WRITE(R600_CP_RB_CNTL, R600_RB_RPTR_WR_ENA);
+       RADEON_WRITE(R600_CP_RB_CNTL,
+#ifdef __BIG_ENDIAN
+                    R600_BUF_SWAP_32BIT |
+#endif
+                    R600_RB_RPTR_WR_ENA);
 
        RADEON_WRITE(R600_CP_RB_RPTR_WR, cp_ptr);
        RADEON_WRITE(R600_CP_RB_WPTR, cp_ptr);
@@ -1838,7 +1852,10 @@ static void r600_cp_init_ring_buffer(struct drm_device *dev,
                        + dev_priv->gart_vm_start;
        }
        RADEON_WRITE(R600_CP_RB_RPTR_ADDR,
-                    rptr_addr & 0xffffffff);
+#ifdef __BIG_ENDIAN
+                    (2 << 0) |
+#endif
+                    (rptr_addr & 0xfffffffc));
        RADEON_WRITE(R600_CP_RB_RPTR_ADDR_HI,
                     upper_32_bits(rptr_addr));
 
@@ -1889,7 +1906,7 @@ static void r600_cp_init_ring_buffer(struct drm_device *dev,
        {
                u64 scratch_addr;
 
-               scratch_addr = RADEON_READ(R600_CP_RB_RPTR_ADDR);
+               scratch_addr = RADEON_READ(R600_CP_RB_RPTR_ADDR) & 0xFFFFFFFC;
                scratch_addr |= ((u64)RADEON_READ(R600_CP_RB_RPTR_ADDR_HI)) << 32;
                scratch_addr += R600_SCRATCH_REG_OFFSET;
                scratch_addr >>= 8;
index 7831e08..153095f 100644 (file)
@@ -295,17 +295,18 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
        }
 
        if (!IS_ALIGNED(pitch, pitch_align)) {
-               dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
-                        __func__, __LINE__, pitch);
+               dev_warn(p->dev, "%s:%d cb pitch (%d, 0x%x, %d) invalid\n",
+                        __func__, __LINE__, pitch, pitch_align, array_mode);
                return -EINVAL;
        }
        if (!IS_ALIGNED(height, height_align)) {
-               dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
-                        __func__, __LINE__, height);
+               dev_warn(p->dev, "%s:%d cb height (%d, 0x%x, %d) invalid\n",
+                        __func__, __LINE__, height, height_align, array_mode);
                return -EINVAL;
        }
        if (!IS_ALIGNED(base_offset, base_align)) {
-               dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset);
+               dev_warn(p->dev, "%s offset[%d] 0x%llx 0x%llx, %d not aligned\n", __func__, i,
+                        base_offset, base_align, array_mode);
                return -EINVAL;
        }
 
@@ -320,7 +321,10 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
                         * broken userspace.
                         */
                } else {
-                       dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[i]));
+                       dev_warn(p->dev, "%s offset[%d] %d %d %d %lu too big\n", __func__, i,
+                                array_mode,
+                                track->cb_color_bo_offset[i], tmp,
+                                radeon_bo_size(track->cb_color_bo[i]));
                        return -EINVAL;
                }
        }
@@ -455,17 +459,18 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
                        }
 
                        if (!IS_ALIGNED(pitch, pitch_align)) {
-                               dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n",
-                                        __func__, __LINE__, pitch);
+                               dev_warn(p->dev, "%s:%d db pitch (%d, 0x%x, %d) invalid\n",
+                                        __func__, __LINE__, pitch, pitch_align, array_mode);
                                return -EINVAL;
                        }
                        if (!IS_ALIGNED(height, height_align)) {
-                               dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
-                                        __func__, __LINE__, height);
+                               dev_warn(p->dev, "%s:%d db height (%d, 0x%x, %d) invalid\n",
+                                        __func__, __LINE__, height, height_align, array_mode);
                                return -EINVAL;
                        }
                        if (!IS_ALIGNED(base_offset, base_align)) {
-                               dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset);
+                               dev_warn(p->dev, "%s offset[%d] 0x%llx, 0x%llx, %d not aligned\n", __func__, i,
+                                        base_offset, base_align, array_mode);
                                return -EINVAL;
                        }
 
@@ -473,9 +478,10 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
                        nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1;
                        tmp = ntiles * bpe * 64 * nviews;
                        if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) {
-                               dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %u have %lu)\n",
-                                               track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset,
-                                               radeon_bo_size(track->db_bo));
+                               dev_warn(p->dev, "z/stencil buffer (%d) too small (0x%08X %d %d %d -> %u have %lu)\n",
+                                        array_mode,
+                                        track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset,
+                                        radeon_bo_size(track->db_bo));
                                return -EINVAL;
                        }
                }
@@ -1227,18 +1233,18 @@ static inline int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 i
        /* XXX check height as well... */
 
        if (!IS_ALIGNED(pitch, pitch_align)) {
-               dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
-                        __func__, __LINE__, pitch);
+               dev_warn(p->dev, "%s:%d tex pitch (%d, 0x%x, %d) invalid\n",
+                        __func__, __LINE__, pitch, pitch_align, G_038000_TILE_MODE(word0));
                return -EINVAL;
        }
        if (!IS_ALIGNED(base_offset, base_align)) {
-               dev_warn(p->dev, "%s:%d tex base offset (0x%llx) invalid\n",
-                        __func__, __LINE__, base_offset);
+               dev_warn(p->dev, "%s:%d tex base offset (0x%llx, 0x%llx, %d) invalid\n",
+                        __func__, __LINE__, base_offset, base_align, G_038000_TILE_MODE(word0));
                return -EINVAL;
        }
        if (!IS_ALIGNED(mip_offset, base_align)) {
-               dev_warn(p->dev, "%s:%d tex mip offset (0x%llx) invalid\n",
-                        __func__, __LINE__, mip_offset);
+               dev_warn(p->dev, "%s:%d tex mip offset (0x%llx, 0x%llx, %d) invalid\n",
+                        __func__, __LINE__, mip_offset, base_align, G_038000_TILE_MODE(word0));
                return -EINVAL;
        }
 
index 33cda01..f869897 100644 (file)
 #define R600_MEDIUM_VID_LOWER_GPIO_CNTL                            0x720
 #define R600_LOW_VID_LOWER_GPIO_CNTL                               0x724
 
-
+#define R600_D1GRPH_SWAP_CONTROL                               0x610C
+#       define R600_D1GRPH_SWAP_ENDIAN_NONE                    (0 << 0)
+#       define R600_D1GRPH_SWAP_ENDIAN_16BIT                   (1 << 0)
+#       define R600_D1GRPH_SWAP_ENDIAN_32BIT                   (2 << 0)
+#       define R600_D1GRPH_SWAP_ENDIAN_64BIT                   (3 << 0)
 
 #define R600_HDP_NONSURFACE_BASE                                0x2c04
 
index a5d898b..04bac0b 100644 (file)
 #define                ROQ_IB2_START(x)                                ((x) << 8)
 #define        CP_RB_BASE                                      0xC100
 #define        CP_RB_CNTL                                      0xC104
-#define                RB_BUFSZ(x)                                     ((x)<<0)
-#define                RB_BLKSZ(x)                                     ((x)<<8)
-#define                RB_NO_UPDATE                                    (1<<27)
-#define                RB_RPTR_WR_ENA                                  (1<<31)
+#define                RB_BUFSZ(x)                                     ((x) << 0)
+#define                RB_BLKSZ(x)                                     ((x) << 8)
+#define                RB_NO_UPDATE                                    (1 << 27)
+#define                RB_RPTR_WR_ENA                                  (1 << 31)
 #define                BUF_SWAP_32BIT                                  (2 << 16)
 #define        CP_RB_RPTR                                      0x8700
 #define        CP_RB_RPTR_ADDR                                 0xC10C
+#define                RB_RPTR_SWAP(x)                                 ((x) << 0)
 #define        CP_RB_RPTR_ADDR_HI                              0xC110
 #define        CP_RB_RPTR_WR                                   0xC108
 #define        CP_RB_WPTR                                      0xC114
index 71d2a55..6b34294 100644 (file)
@@ -179,10 +179,10 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev);
 void radeon_atombios_get_power_modes(struct radeon_device *rdev);
 void radeon_atom_set_voltage(struct radeon_device *rdev, u16 level);
 void rs690_pm_info(struct radeon_device *rdev);
-extern u32 rv6xx_get_temp(struct radeon_device *rdev);
-extern u32 rv770_get_temp(struct radeon_device *rdev);
-extern u32 evergreen_get_temp(struct radeon_device *rdev);
-extern u32 sumo_get_temp(struct radeon_device *rdev);
+extern int rv6xx_get_temp(struct radeon_device *rdev);
+extern int rv770_get_temp(struct radeon_device *rdev);
+extern int evergreen_get_temp(struct radeon_device *rdev);
+extern int sumo_get_temp(struct radeon_device *rdev);
 
 /*
  * Fences.
@@ -345,7 +345,6 @@ struct radeon_mc {
         * about vram size near mc fb location */
        u64                     mc_vram_size;
        u64                     visible_vram_size;
-       u64                     active_vram_size;
        u64                     gtt_size;
        u64                     gtt_start;
        u64                     gtt_end;
@@ -812,8 +811,7 @@ struct radeon_pm {
        fixed20_12              sclk;
        fixed20_12              mclk;
        fixed20_12              needed_bandwidth;
-       /* XXX: use a define for num power modes */
-       struct radeon_power_state power_state[8];
+       struct radeon_power_state *power_state;
        /* number of valid power states */
        int                     num_power_states;
        int                     current_power_state_index;
@@ -1449,6 +1447,7 @@ extern void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *m
 extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
 extern int radeon_resume_kms(struct drm_device *dev);
 extern int radeon_suspend_kms(struct drm_device *dev, pm_message_t state);
+extern void radeon_ttm_set_active_vram_size(struct radeon_device *rdev, u64 size);
 
 /* r600, rv610, rv630, rv620, rv635, rv670, rs780, rs880 */
 extern bool r600_card_posted(struct radeon_device *rdev);
index 3a1b161..793c5e6 100644 (file)
@@ -759,7 +759,7 @@ static struct radeon_asic evergreen_asic = {
        .gart_tlb_flush = &evergreen_pcie_gart_tlb_flush,
        .gart_set_page = &rs600_gart_set_page,
        .ring_test = &r600_ring_test,
-       .ring_ib_execute = &r600_ring_ib_execute,
+       .ring_ib_execute = &evergreen_ring_ib_execute,
        .irq_set = &evergreen_irq_set,
        .irq_process = &evergreen_irq_process,
        .get_vblank_counter = &evergreen_get_vblank_counter,
@@ -805,7 +805,7 @@ static struct radeon_asic sumo_asic = {
        .gart_tlb_flush = &evergreen_pcie_gart_tlb_flush,
        .gart_set_page = &rs600_gart_set_page,
        .ring_test = &r600_ring_test,
-       .ring_ib_execute = &r600_ring_ib_execute,
+       .ring_ib_execute = &evergreen_ring_ib_execute,
        .irq_set = &evergreen_irq_set,
        .irq_process = &evergreen_irq_process,
        .get_vblank_counter = &evergreen_get_vblank_counter,
@@ -834,6 +834,9 @@ static struct radeon_asic sumo_asic = {
        .pm_finish = &evergreen_pm_finish,
        .pm_init_profile = &rs780_pm_init_profile,
        .pm_get_dynpm_state = &r600_pm_get_dynpm_state,
+       .pre_page_flip = &evergreen_pre_page_flip,
+       .page_flip = &evergreen_page_flip,
+       .post_page_flip = &evergreen_post_page_flip,
 };
 
 static struct radeon_asic btc_asic = {
@@ -848,7 +851,7 @@ static struct radeon_asic btc_asic = {
        .gart_tlb_flush = &evergreen_pcie_gart_tlb_flush,
        .gart_set_page = &rs600_gart_set_page,
        .ring_test = &r600_ring_test,
-       .ring_ib_execute = &r600_ring_ib_execute,
+       .ring_ib_execute = &evergreen_ring_ib_execute,
        .irq_set = &evergreen_irq_set,
        .irq_process = &evergreen_irq_process,
        .get_vblank_counter = &evergreen_get_vblank_counter,
index e01f077..c59bd98 100644 (file)
@@ -355,6 +355,7 @@ int evergreen_resume(struct radeon_device *rdev);
 bool evergreen_gpu_is_lockup(struct radeon_device *rdev);
 int evergreen_asic_reset(struct radeon_device *rdev);
 void evergreen_bandwidth_update(struct radeon_device *rdev);
+void evergreen_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
 int evergreen_copy_blit(struct radeon_device *rdev,
                        uint64_t src_offset, uint64_t dst_offset,
                        unsigned num_pages, struct radeon_fence *fence);
index 5277790..02d5c41 100644 (file)
@@ -88,7 +88,7 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_dev
                        /* some evergreen boards have bad data for this entry */
                        if (ASIC_IS_DCE4(rdev)) {
                                if ((i == 7) &&
-                                   (gpio->usClkMaskRegisterIndex == 0x1936) &&
+                                   (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1936) &&
                                    (gpio->sucI2cId.ucAccess == 0)) {
                                        gpio->sucI2cId.ucAccess = 0x97;
                                        gpio->ucDataMaskShift = 8;
@@ -101,7 +101,7 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_dev
                        /* some DCE3 boards have bad data for this entry */
                        if (ASIC_IS_DCE3(rdev)) {
                                if ((i == 4) &&
-                                   (gpio->usClkMaskRegisterIndex == 0x1fda) &&
+                                   (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1fda) &&
                                    (gpio->sucI2cId.ucAccess == 0x94))
                                        gpio->sucI2cId.ucAccess = 0x14;
                        }
@@ -172,7 +172,7 @@ void radeon_atombios_i2c_init(struct radeon_device *rdev)
                        /* some evergreen boards have bad data for this entry */
                        if (ASIC_IS_DCE4(rdev)) {
                                if ((i == 7) &&
-                                   (gpio->usClkMaskRegisterIndex == 0x1936) &&
+                                   (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1936) &&
                                    (gpio->sucI2cId.ucAccess == 0)) {
                                        gpio->sucI2cId.ucAccess = 0x97;
                                        gpio->ucDataMaskShift = 8;
@@ -185,7 +185,7 @@ void radeon_atombios_i2c_init(struct radeon_device *rdev)
                        /* some DCE3 boards have bad data for this entry */
                        if (ASIC_IS_DCE3(rdev)) {
                                if ((i == 4) &&
-                                   (gpio->usClkMaskRegisterIndex == 0x1fda) &&
+                                   (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1fda) &&
                                    (gpio->sucI2cId.ucAccess == 0x94))
                                        gpio->sucI2cId.ucAccess = 0x14;
                        }
@@ -252,7 +252,7 @@ static inline struct radeon_gpio_rec radeon_lookup_gpio(struct radeon_device *rd
                        pin = &gpio_info->asGPIO_Pin[i];
                        if (id == pin->ucGPIO_ID) {
                                gpio.id = pin->ucGPIO_ID;
-                               gpio.reg = pin->usGpioPin_AIndex * 4;
+                               gpio.reg = le16_to_cpu(pin->usGpioPin_AIndex) * 4;
                                gpio.mask = (1 << pin->ucGpioPinBitShift);
                                gpio.valid = true;
                                break;
@@ -1163,16 +1163,6 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
                                p1pll->pll_out_min = 64800;
                        else
                                p1pll->pll_out_min = 20000;
-               } else if (p1pll->pll_out_min > 64800) {
-                       /* Limiting the pll output range is a good thing generally as
-                        * it limits the number of possible pll combinations for a given
-                        * frequency presumably to the ones that work best on each card.
-                        * However, certain duallink DVI monitors seem to like
-                        * pll combinations that would be limited by this at least on
-                        * pre-DCE 3.0 r6xx hardware.  This might need to be adjusted per
-                        * family.
-                        */
-                       p1pll->pll_out_min = 64800;
                }
 
                p1pll->pll_in_min =
@@ -1284,11 +1274,11 @@ bool radeon_atombios_sideport_present(struct radeon_device *rdev)
                                      data_offset);
                switch (crev) {
                case 1:
-                       if (igp_info->info.ulBootUpMemoryClock)
+                       if (le32_to_cpu(igp_info->info.ulBootUpMemoryClock))
                                return true;
                        break;
                case 2:
-                       if (igp_info->info_2.ulBootUpSidePortClock)
+                       if (le32_to_cpu(igp_info->info_2.ulBootUpSidePortClock))
                                return true;
                        break;
                default:
@@ -1452,7 +1442,7 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
 
                        for (i = 0; i < num_indices; i++) {
                                if ((ss_info->info.asSpreadSpectrum[i].ucClockIndication == id) &&
-                                   (clock <= ss_info->info.asSpreadSpectrum[i].ulTargetClockRange)) {
+                                   (clock <= le32_to_cpu(ss_info->info.asSpreadSpectrum[i].ulTargetClockRange))) {
                                        ss->percentage =
                                                le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
                                        ss->type = ss_info->info.asSpreadSpectrum[i].ucSpreadSpectrumMode;
@@ -1466,7 +1456,7 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
                                sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
                        for (i = 0; i < num_indices; i++) {
                                if ((ss_info->info_2.asSpreadSpectrum[i].ucClockIndication == id) &&
-                                   (clock <= ss_info->info_2.asSpreadSpectrum[i].ulTargetClockRange)) {
+                                   (clock <= le32_to_cpu(ss_info->info_2.asSpreadSpectrum[i].ulTargetClockRange))) {
                                        ss->percentage =
                                                le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
                                        ss->type = ss_info->info_2.asSpreadSpectrum[i].ucSpreadSpectrumMode;
@@ -1480,7 +1470,7 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
                                sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
                        for (i = 0; i < num_indices; i++) {
                                if ((ss_info->info_3.asSpreadSpectrum[i].ucClockIndication == id) &&
-                                   (clock <= ss_info->info_3.asSpreadSpectrum[i].ulTargetClockRange)) {
+                                   (clock <= le32_to_cpu(ss_info->info_3.asSpreadSpectrum[i].ulTargetClockRange))) {
                                        ss->percentage =
                                                le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
                                        ss->type = ss_info->info_3.asSpreadSpectrum[i].ucSpreadSpectrumMode;
@@ -1563,8 +1553,8 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
                if (misc & ATOM_DOUBLE_CLOCK_MODE)
                        lvds->native_mode.flags |= DRM_MODE_FLAG_DBLSCAN;
 
-               lvds->native_mode.width_mm = lvds_info->info.sLCDTiming.usImageHSize;
-               lvds->native_mode.height_mm = lvds_info->info.sLCDTiming.usImageVSize;
+               lvds->native_mode.width_mm = le16_to_cpu(lvds_info->info.sLCDTiming.usImageHSize);
+               lvds->native_mode.height_mm = le16_to_cpu(lvds_info->info.sLCDTiming.usImageVSize);
 
                /* set crtc values */
                drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V);
@@ -1579,13 +1569,13 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
                        lvds->linkb = false;
 
                /* parse the lcd record table */
-               if (lvds_info->info.usModePatchTableOffset) {
+               if (le16_to_cpu(lvds_info->info.usModePatchTableOffset)) {
                        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 +
-                                           lvds_info->info.usModePatchTableOffset);
+                                           le16_to_cpu(lvds_info->info.usModePatchTableOffset));
                        while (*record != ATOM_RECORD_END_TYPE) {
                                switch (*record) {
                                case LCD_MODE_PATCH_RECORD_MODE_TYPE:
@@ -1987,6 +1977,9 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev)
        num_modes = power_info->info.ucNumOfPowerModeEntries;
        if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK)
                num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK;
+       rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * num_modes, GFP_KERNEL);
+       if (!rdev->pm.power_state)
+               return state_index;
        /* last mode is usually default, array is low to high */
        for (i = 0; i < num_modes; i++) {
                rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
@@ -2196,7 +2189,7 @@ static u16 radeon_atombios_get_default_vddc(struct radeon_device *rdev)
                firmware_info =
                        (union firmware_info *)(mode_info->atom_context->bios +
                                                data_offset);
-               vddc = firmware_info->info_14.usBootUpVDDCVoltage;
+               vddc = le16_to_cpu(firmware_info->info_14.usBootUpVDDCVoltage);
        }
 
        return vddc;
@@ -2291,7 +2284,7 @@ static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev,
                rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
                        VOLTAGE_SW;
                rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
-                       clock_info->evergreen.usVDDC;
+                       le16_to_cpu(clock_info->evergreen.usVDDC);
        } else {
                sclk = le16_to_cpu(clock_info->r600.usEngineClockLow);
                sclk |= clock_info->r600.ucEngineClockHigh << 16;
@@ -2302,7 +2295,7 @@ static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev,
                rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
                        VOLTAGE_SW;
                rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
-                       clock_info->r600.usVDDC;
+                       le16_to_cpu(clock_info->r600.usVDDC);
        }
 
        if (rdev->flags & RADEON_IS_IGP) {
@@ -2338,6 +2331,10 @@ static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev)
        power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
 
        radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController);
+       rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) *
+                                      power_info->pplib.ucNumStates, GFP_KERNEL);
+       if (!rdev->pm.power_state)
+               return state_index;
        /* first mode is usually default, followed by low to high */
        for (i = 0; i < power_info->pplib.ucNumStates; i++) {
                mode_index = 0;
@@ -2411,13 +2408,17 @@ static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev)
        radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController);
        state_array = (struct StateArray *)
                (mode_info->atom_context->bios + data_offset +
-                power_info->pplib.usStateArrayOffset);
+                le16_to_cpu(power_info->pplib.usStateArrayOffset));
        clock_info_array = (struct ClockInfoArray *)
                (mode_info->atom_context->bios + data_offset +
-                power_info->pplib.usClockInfoArrayOffset);
+                le16_to_cpu(power_info->pplib.usClockInfoArrayOffset));
        non_clock_info_array = (struct NonClockInfoArray *)
                (mode_info->atom_context->bios + data_offset +
-                power_info->pplib.usNonClockInfoArrayOffset);
+                le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset));
+       rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) *
+                                      state_array->ucNumEntries, GFP_KERNEL);
+       if (!rdev->pm.power_state)
+               return state_index;
        for (i = 0; i < state_array->ucNumEntries; i++) {
                mode_index = 0;
                power_state = (union pplib_power_state *)&state_array->states[i];
@@ -2491,19 +2492,22 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
                        break;
                }
        } else {
-               /* add the default mode */
-               rdev->pm.power_state[state_index].type =
-                       POWER_STATE_TYPE_DEFAULT;
-               rdev->pm.power_state[state_index].num_clock_modes = 1;
-               rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk;
-               rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk;
-               rdev->pm.power_state[state_index].default_clock_mode =
-                       &rdev->pm.power_state[state_index].clock_info[0];
-               rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
-               rdev->pm.power_state[state_index].pcie_lanes = 16;
-               rdev->pm.default_power_state_index = state_index;
-               rdev->pm.power_state[state_index].flags = 0;
-               state_index++;
+               rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state), GFP_KERNEL);
+               if (rdev->pm.power_state) {
+                       /* add the default mode */
+                       rdev->pm.power_state[state_index].type =
+                               POWER_STATE_TYPE_DEFAULT;
+                       rdev->pm.power_state[state_index].num_clock_modes = 1;
+                       rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk;
+                       rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk;
+                       rdev->pm.power_state[state_index].default_clock_mode =
+                               &rdev->pm.power_state[state_index].clock_info[0];
+                       rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
+                       rdev->pm.power_state[state_index].pcie_lanes = 16;
+                       rdev->pm.default_power_state_index = state_index;
+                       rdev->pm.power_state[state_index].flags = 0;
+                       state_index++;
+               }
        }
 
        rdev->pm.num_power_states = state_index;
@@ -2529,7 +2533,7 @@ uint32_t radeon_atom_get_engine_clock(struct radeon_device *rdev)
        int index = GetIndexIntoMasterTable(COMMAND, GetEngineClock);
 
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
-       return args.ulReturnEngineClock;
+       return le32_to_cpu(args.ulReturnEngineClock);
 }
 
 uint32_t radeon_atom_get_memory_clock(struct radeon_device *rdev)
@@ -2538,7 +2542,7 @@ uint32_t radeon_atom_get_memory_clock(struct radeon_device *rdev)
        int index = GetIndexIntoMasterTable(COMMAND, GetMemoryClock);
 
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
-       return args.ulReturnMemoryClock;
+       return le32_to_cpu(args.ulReturnMemoryClock);
 }
 
 void radeon_atom_set_engine_clock(struct radeon_device *rdev,
@@ -2547,7 +2551,7 @@ void radeon_atom_set_engine_clock(struct radeon_device *rdev,
        SET_ENGINE_CLOCK_PS_ALLOCATION args;
        int index = GetIndexIntoMasterTable(COMMAND, SetEngineClock);
 
-       args.ulTargetEngineClock = eng_clock;   /* 10 khz */
+       args.ulTargetEngineClock = cpu_to_le32(eng_clock);      /* 10 khz */
 
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
@@ -2561,7 +2565,7 @@ void radeon_atom_set_memory_clock(struct radeon_device *rdev,
        if (rdev->flags & RADEON_IS_IGP)
                return;
 
-       args.ulTargetMemoryClock = mem_clock;   /* 10 khz */
+       args.ulTargetMemoryClock = cpu_to_le32(mem_clock);      /* 10 khz */
 
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
@@ -2619,7 +2623,7 @@ void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev)
        bios_2_scratch &= ~ATOM_S2_VRI_BRIGHT_ENABLE;
 
        /* tell the bios not to handle mode switching */
-       bios_6_scratch |= (ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH | ATOM_S6_ACC_MODE);
+       bios_6_scratch |= ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH;
 
        if (rdev->family >= CHIP_R600) {
                WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch);
@@ -2670,10 +2674,13 @@ void radeon_atom_output_lock(struct drm_encoder *encoder, bool lock)
        else
                bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH);
 
-       if (lock)
+       if (lock) {
                bios_6_scratch |= ATOM_S6_CRITICAL_STATE;
-       else
+               bios_6_scratch &= ~ATOM_S6_ACC_MODE;
+       } else {
                bios_6_scratch &= ~ATOM_S6_CRITICAL_STATE;
+               bios_6_scratch |= ATOM_S6_ACC_MODE;
+       }
 
        if (rdev->family >= CHIP_R600)
                WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch);
index 591fcae..cf7c8d5 100644 (file)
@@ -1504,6 +1504,11 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                           (rdev->pdev->subsystem_device == 0x4a48)) {
                        /* Mac X800 */
                        rdev->mode_info.connector_table = CT_MAC_X800;
+               } else if ((rdev->pdev->device == 0x4150) &&
+                          (rdev->pdev->subsystem_vendor == 0x1002) &&
+                          (rdev->pdev->subsystem_device == 0x4150)) {
+                       /* Mac G5 9600 */
+                       rdev->mode_info.connector_table = CT_MAC_G5_9600;
                } else
 #endif /* CONFIG_PPC_PMAC */
 #ifdef CONFIG_PPC64
@@ -2022,6 +2027,48 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                                            CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I,
                                            &hpd);
                break;
+       case CT_MAC_G5_9600:
+               DRM_INFO("Connector Table: %d (mac g5 9600)\n",
+                        rdev->mode_info.connector_table);
+               /* DVI - tv dac, dvo */
+               ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
+               hpd.hpd = RADEON_HPD_1; /* ??? */
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_enum(dev,
+                                                                 ATOM_DEVICE_DFP2_SUPPORT,
+                                                                 0),
+                                         ATOM_DEVICE_DFP2_SUPPORT);
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_enum(dev,
+                                                                 ATOM_DEVICE_CRT2_SUPPORT,
+                                                                 2),
+                                         ATOM_DEVICE_CRT2_SUPPORT);
+               radeon_add_legacy_connector(dev, 0,
+                                           ATOM_DEVICE_DFP2_SUPPORT |
+                                           ATOM_DEVICE_CRT2_SUPPORT,
+                                           DRM_MODE_CONNECTOR_DVII, &ddc_i2c,
+                                           CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I,
+                                           &hpd);
+               /* ADC - primary dac, internal tmds */
+               ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
+               hpd.hpd = RADEON_HPD_2; /* ??? */
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_enum(dev,
+                                                                 ATOM_DEVICE_DFP1_SUPPORT,
+                                                                 0),
+                                         ATOM_DEVICE_DFP1_SUPPORT);
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_enum(dev,
+                                                                 ATOM_DEVICE_CRT1_SUPPORT,
+                                                                 1),
+                                         ATOM_DEVICE_CRT1_SUPPORT);
+               radeon_add_legacy_connector(dev, 1,
+                                           ATOM_DEVICE_DFP1_SUPPORT |
+                                           ATOM_DEVICE_CRT1_SUPPORT,
+                                           DRM_MODE_CONNECTOR_DVII, &ddc_i2c,
+                                           CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I,
+                                           &hpd);
+               break;
        default:
                DRM_INFO("Connector table: %d (invalid)\n",
                         rdev->mode_info.connector_table);
@@ -2442,6 +2489,17 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev)
 
        rdev->pm.default_power_state_index = -1;
 
+       /* allocate 2 power states */
+       rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * 2, GFP_KERNEL);
+       if (!rdev->pm.power_state) {
+               rdev->pm.default_power_state_index = state_index;
+               rdev->pm.num_power_states = 0;
+
+               rdev->pm.current_power_state_index = rdev->pm.default_power_state_index;
+               rdev->pm.current_clock_mode_index = 0;
+               return;
+       }
+
        if (rdev->flags & RADEON_IS_MOBILITY) {
                offset = combios_get_table_offset(dev, COMBIOS_POWERPLAY_INFO_TABLE);
                if (offset) {
index 26091d6..4954e2d 100644 (file)
@@ -891,9 +891,9 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
                pci_disable_device(dev->pdev);
                pci_set_power_state(dev->pdev, PCI_D3hot);
        }
-       acquire_console_sem();
+       console_lock();
        radeon_fbdev_set_suspend(rdev, 1);
-       release_console_sem();
+       console_unlock();
        return 0;
 }
 
@@ -905,11 +905,11 @@ int radeon_resume_kms(struct drm_device *dev)
        if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
                return 0;
 
-       acquire_console_sem();
+       console_lock();
        pci_set_power_state(dev->pdev, PCI_D0);
        pci_restore_state(dev->pdev);
        if (pci_enable_device(dev->pdev)) {
-               release_console_sem();
+               console_unlock();
                return -1;
        }
        pci_set_master(dev->pdev);
@@ -920,7 +920,7 @@ int radeon_resume_kms(struct drm_device *dev)
        radeon_restore_bios_scratch_regs(rdev);
 
        radeon_fbdev_set_suspend(rdev, 0);
-       release_console_sem();
+       console_unlock();
 
        /* reset hpd state */
        radeon_hpd_init(rdev);
@@ -936,8 +936,11 @@ int radeon_resume_kms(struct drm_device *dev)
 int radeon_gpu_reset(struct radeon_device *rdev)
 {
        int r;
+       int resched;
 
        radeon_save_bios_scratch_regs(rdev);
+       /* block TTM */
+       resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev);
        radeon_suspend(rdev);
 
        r = radeon_asic_reset(rdev);
@@ -946,6 +949,7 @@ int radeon_gpu_reset(struct radeon_device *rdev)
                radeon_resume(rdev);
                radeon_restore_bios_scratch_regs(rdev);
                drm_helper_resume_force_mode(rdev->ddev);
+               ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched);
                return 0;
        }
        /* bad news, how to tell it to userspace ? */
index d26dabf..3e7e7f9 100644 (file)
@@ -780,6 +780,125 @@ static int radeon_ddc_dump(struct drm_connector *connector)
        return ret;
 }
 
+/* avivo */
+static void avivo_get_fb_div(struct radeon_pll *pll,
+                            u32 target_clock,
+                            u32 post_div,
+                            u32 ref_div,
+                            u32 *fb_div,
+                            u32 *frac_fb_div)
+{
+       u32 tmp = post_div * ref_div;
+
+       tmp *= target_clock;
+       *fb_div = tmp / pll->reference_freq;
+       *frac_fb_div = tmp % pll->reference_freq;
+
+        if (*fb_div > pll->max_feedback_div)
+               *fb_div = pll->max_feedback_div;
+        else if (*fb_div < pll->min_feedback_div)
+                *fb_div = pll->min_feedback_div;
+}
+
+static u32 avivo_get_post_div(struct radeon_pll *pll,
+                             u32 target_clock)
+{
+       u32 vco, post_div, tmp;
+
+       if (pll->flags & RADEON_PLL_USE_POST_DIV)
+               return pll->post_div;
+
+       if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) {
+               if (pll->flags & RADEON_PLL_IS_LCD)
+                       vco = pll->lcd_pll_out_min;
+               else
+                       vco = pll->pll_out_min;
+       } else {
+               if (pll->flags & RADEON_PLL_IS_LCD)
+                       vco = pll->lcd_pll_out_max;
+               else
+                       vco = pll->pll_out_max;
+       }
+
+       post_div = vco / target_clock;
+       tmp = vco % target_clock;
+
+       if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) {
+               if (tmp)
+                       post_div++;
+       } else {
+               if (!tmp)
+                       post_div--;
+       }
+
+       if (post_div > pll->max_post_div)
+               post_div = pll->max_post_div;
+       else if (post_div < pll->min_post_div)
+               post_div = pll->min_post_div;
+
+       return post_div;
+}
+
+#define MAX_TOLERANCE 10
+
+void radeon_compute_pll_avivo(struct radeon_pll *pll,
+                             u32 freq,
+                             u32 *dot_clock_p,
+                             u32 *fb_div_p,
+                             u32 *frac_fb_div_p,
+                             u32 *ref_div_p,
+                             u32 *post_div_p)
+{
+       u32 target_clock = freq / 10;
+       u32 post_div = avivo_get_post_div(pll, target_clock);
+       u32 ref_div = pll->min_ref_div;
+       u32 fb_div = 0, frac_fb_div = 0, tmp;
+
+       if (pll->flags & RADEON_PLL_USE_REF_DIV)
+               ref_div = pll->reference_div;
+
+       if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
+               avivo_get_fb_div(pll, target_clock, post_div, ref_div, &fb_div, &frac_fb_div);
+               frac_fb_div = (100 * frac_fb_div) / pll->reference_freq;
+               if (frac_fb_div >= 5) {
+                       frac_fb_div -= 5;
+                       frac_fb_div = frac_fb_div / 10;
+                       frac_fb_div++;
+               }
+               if (frac_fb_div >= 10) {
+                       fb_div++;
+                       frac_fb_div = 0;
+               }
+       } else {
+               while (ref_div <= pll->max_ref_div) {
+                       avivo_get_fb_div(pll, target_clock, post_div, ref_div,
+                                        &fb_div, &frac_fb_div);
+                       if (frac_fb_div >= (pll->reference_freq / 2))
+                               fb_div++;
+                       frac_fb_div = 0;
+                       tmp = (pll->reference_freq * fb_div) / (post_div * ref_div);
+                       tmp = (tmp * 10000) / target_clock;
+
+                       if (tmp > (10000 + MAX_TOLERANCE))
+                               ref_div++;
+                       else if (tmp >= (10000 - MAX_TOLERANCE))
+                               break;
+                       else
+                               ref_div++;
+               }
+       }
+
+       *dot_clock_p = ((pll->reference_freq * fb_div * 10) + (pll->reference_freq * frac_fb_div)) /
+               (ref_div * post_div * 10);
+       *fb_div_p = fb_div;
+       *frac_fb_div_p = frac_fb_div;
+       *ref_div_p = ref_div;
+       *post_div_p = post_div;
+       DRM_DEBUG_KMS("%d, pll dividers - fb: %d.%d ref: %d, post %d\n",
+                     *dot_clock_p, fb_div, frac_fb_div, ref_div, post_div);
+}
+
+/* pre-avivo */
 static inline uint32_t radeon_div(uint64_t n, uint32_t d)
 {
        uint64_t mod;
@@ -790,13 +909,13 @@ static inline uint32_t radeon_div(uint64_t n, uint32_t d)
        return n;
 }
 
-void radeon_compute_pll(struct radeon_pll *pll,
-                       uint64_t freq,
-                       uint32_t *dot_clock_p,
-                       uint32_t *fb_div_p,
-                       uint32_t *frac_fb_div_p,
-                       uint32_t *ref_div_p,
-                       uint32_t *post_div_p)
+void radeon_compute_pll_legacy(struct radeon_pll *pll,
+                              uint64_t freq,
+                              uint32_t *dot_clock_p,
+                              uint32_t *fb_div_p,
+                              uint32_t *frac_fb_div_p,
+                              uint32_t *ref_div_p,
+                              uint32_t *post_div_p)
 {
        uint32_t min_ref_div = pll->min_ref_div;
        uint32_t max_ref_div = pll->max_ref_div;
@@ -826,6 +945,9 @@ void radeon_compute_pll(struct radeon_pll *pll,
                pll_out_max = pll->pll_out_max;
        }
 
+       if (pll_out_min > 64800)
+               pll_out_min = 64800;
+
        if (pll->flags & RADEON_PLL_USE_REF_DIV)
                min_ref_div = max_ref_div = pll->reference_div;
        else {
@@ -965,6 +1087,10 @@ void radeon_compute_pll(struct radeon_pll *pll,
        *frac_fb_div_p = best_frac_feedback_div;
        *ref_div_p = best_ref_div;
        *post_div_p = best_post_div;
+       DRM_DEBUG_KMS("%d %d, pll dividers - fb: %d.%d ref: %d, post %d\n",
+                     freq, best_freq / 1000, best_feedback_div, best_frac_feedback_div,
+                     best_ref_div, best_post_div);
+
 }
 
 static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb)
index 448eba8..5cba46b 100644 (file)
@@ -1524,6 +1524,7 @@ extern u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index);
 #define R600_CP_RB_CNTL                                        0xc104
 #       define R600_RB_BUFSZ(x)                                ((x) << 0)
 #       define R600_RB_BLKSZ(x)                                ((x) << 8)
+#      define R600_BUF_SWAP_32BIT                             (2 << 16)
 #       define R600_RB_NO_UPDATE                               (1 << 27)
 #       define R600_RB_RPTR_WR_ENA                             (1 << 31)
 #define R600_CP_RB_RPTR_WR                                     0xc108
index 8fd1842..b427488 100644 (file)
@@ -641,7 +641,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
        switch (connector->connector_type) {
        case DRM_MODE_CONNECTOR_DVII:
        case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */
-               if (drm_detect_monitor_audio(radeon_connector->edid)) {
+               if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) {
                        /* fix me */
                        if (ASIC_IS_DCE4(rdev))
                                return ATOM_ENCODER_MODE_DVI;
@@ -655,7 +655,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
        case DRM_MODE_CONNECTOR_DVID:
        case DRM_MODE_CONNECTOR_HDMIA:
        default:
-               if (drm_detect_monitor_audio(radeon_connector->edid)) {
+               if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) {
                        /* fix me */
                        if (ASIC_IS_DCE4(rdev))
                                return ATOM_ENCODER_MODE_DVI;
@@ -673,7 +673,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
                if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
                    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
                        return ATOM_ENCODER_MODE_DP;
-               else if (drm_detect_monitor_audio(radeon_connector->edid)) {
+               else if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) {
                        /* fix me */
                        if (ASIC_IS_DCE4(rdev))
                                return ATOM_ENCODER_MODE_DVI;
@@ -910,7 +910,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
 
        args.v1.ucAction = action;
        if (action == ATOM_TRANSMITTER_ACTION_INIT) {
-               args.v1.usInitInfo = connector_object_id;
+               args.v1.usInitInfo = cpu_to_le16(connector_object_id);
        } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
                args.v1.asMode.ucLaneSel = lane_num;
                args.v1.asMode.ucLaneSet = lane_set;
@@ -1063,7 +1063,7 @@ atombios_set_edp_panel_power(struct drm_connector *connector, int action)
        if (!ASIC_IS_DCE4(rdev))
                return;
 
-       if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) ||
+       if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) &&
            (action != ATOM_TRANSMITTER_ACTION_POWER_OFF))
                return;
 
@@ -1140,7 +1140,7 @@ atombios_external_encoder_setup(struct drm_encoder *encoder,
                case 3:
                        args.v3.sExtEncoder.ucAction = action;
                        if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT)
-                               args.v3.sExtEncoder.usConnectorId = connector_object_id;
+                               args.v3.sExtEncoder.usConnectorId = cpu_to_le16(connector_object_id);
                        else
                                args.v3.sExtEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
                        args.v3.sExtEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder);
@@ -1570,11 +1570,21 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder,
        }
 
        /* set scaler clears this on some chips */
-       /* XXX check DCE4 */
-       if (!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))) {
-               if (ASIC_IS_AVIVO(rdev) && (mode->flags & DRM_MODE_FLAG_INTERLACE))
-                       WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset,
-                              AVIVO_D1MODE_INTERLEAVE_EN);
+       if (ASIC_IS_AVIVO(rdev) &&
+           (!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)))) {
+               if (ASIC_IS_DCE4(rdev)) {
+                       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+                               WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset,
+                                      EVERGREEN_INTERLEAVE_EN);
+                       else
+                               WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
+               } else {
+                       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+                               WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset,
+                                      AVIVO_D1MODE_INTERLEAVE_EN);
+                       else
+                               WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
+               }
        }
 }
 
index 66324b5..cc44bdf 100644 (file)
@@ -113,11 +113,14 @@ static int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev,
        u32 tiling_flags = 0;
        int ret;
        int aligned_size, size;
+       int height = mode_cmd->height;
 
        /* need to align pitch with crtc limits */
        mode_cmd->pitch = radeon_align_pitch(rdev, mode_cmd->width, mode_cmd->bpp, fb_tiled) * ((mode_cmd->bpp + 1) / 8);
 
-       size = mode_cmd->pitch * mode_cmd->height;
+       if (rdev->family >= CHIP_R600)
+               height = ALIGN(mode_cmd->height, 8);
+       size = mode_cmd->pitch * height;
        aligned_size = ALIGN(size, PAGE_SIZE);
        ret = radeon_gem_object_create(rdev, aligned_size, 0,
                                       RADEON_GEM_DOMAIN_VRAM,
index df95eb8..1fe95df 100644 (file)
@@ -156,9 +156,12 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data,
 {
        struct radeon_device *rdev = dev->dev_private;
        struct drm_radeon_gem_info *args = data;
+       struct ttm_mem_type_manager *man;
+
+       man = &rdev->mman.bdev.man[TTM_PL_VRAM];
 
        args->vram_size = rdev->mc.real_vram_size;
-       args->vram_visible = rdev->mc.real_vram_size;
+       args->vram_visible = (u64)man->size << PAGE_SHIFT;
        if (rdev->stollen_vga_memory)
                args->vram_visible -= radeon_bo_size(rdev->stollen_vga_memory);
        args->vram_visible -= radeon_fbdev_total_size(rdev);
index 9832129..8387d32 100644 (file)
@@ -247,6 +247,8 @@ void radeon_driver_preclose_kms(struct drm_device *dev,
        struct radeon_device *rdev = dev->dev_private;
        if (rdev->hyperz_filp == file_priv)
                rdev->hyperz_filp = NULL;
+       if (rdev->cmask_filp == file_priv)
+               rdev->cmask_filp = NULL;
 }
 
 /*
index ace2e63..78968b7 100644 (file)
@@ -443,7 +443,7 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc,
                       (target_fb->bits_per_pixel * 8));
        crtc_pitch |= crtc_pitch << 16;
 
-
+       crtc_offset_cntl |= RADEON_CRTC_GUI_TRIG_OFFSET_LEFT_EN;
        if (tiling_flags & RADEON_TILING_MACRO) {
                if (ASIC_IS_R300(rdev))
                        crtc_offset_cntl |= (R300_CRTC_X_Y_MODE_EN |
@@ -502,6 +502,7 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc,
        gen_cntl_val = RREG32(gen_cntl_reg);
        gen_cntl_val &= ~(0xf << 8);
        gen_cntl_val |= (format << 8);
+       gen_cntl_val &= ~RADEON_CRTC_VSTAT_MODE_MASK;
        WREG32(gen_cntl_reg, gen_cntl_val);
 
        crtc_offset = (u32)base;
@@ -778,9 +779,9 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
        DRM_DEBUG_KMS("\n");
 
        if (!use_bios_divs) {
-               radeon_compute_pll(pll, mode->clock,
-                                  &freq, &feedback_div, &frac_fb_div,
-                                  &reference_div, &post_divider);
+               radeon_compute_pll_legacy(pll, mode->clock,
+                                         &freq, &feedback_div, &frac_fb_div,
+                                         &reference_div, &post_divider);
 
                for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
                        if (post_div->divider == post_divider)
index 12bdeab..a670caa 100644 (file)
@@ -149,6 +149,7 @@ struct radeon_tmds_pll {
 #define RADEON_PLL_PREFER_CLOSEST_LOWER (1 << 11)
 #define RADEON_PLL_USE_POST_DIV         (1 << 12)
 #define RADEON_PLL_IS_LCD               (1 << 13)
+#define RADEON_PLL_PREFER_MINM_OVER_MAXP (1 << 14)
 
 struct radeon_pll {
        /* reference frequency */
@@ -208,6 +209,7 @@ enum radeon_connector_table {
        CT_EMAC,
        CT_RN50_POWER,
        CT_MAC_X800,
+       CT_MAC_G5_9600,
 };
 
 enum radeon_dvo_chip {
@@ -510,13 +512,21 @@ extern bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
                                             struct radeon_atom_ss *ss,
                                             int id, u32 clock);
 
-extern void radeon_compute_pll(struct radeon_pll *pll,
-                              uint64_t freq,
-                              uint32_t *dot_clock_p,
-                              uint32_t *fb_div_p,
-                              uint32_t *frac_fb_div_p,
-                              uint32_t *ref_div_p,
-                              uint32_t *post_div_p);
+extern void radeon_compute_pll_legacy(struct radeon_pll *pll,
+                                     uint64_t freq,
+                                     uint32_t *dot_clock_p,
+                                     uint32_t *fb_div_p,
+                                     uint32_t *frac_fb_div_p,
+                                     uint32_t *ref_div_p,
+                                     uint32_t *post_div_p);
+
+extern void radeon_compute_pll_avivo(struct radeon_pll *pll,
+                                    u32 freq,
+                                    u32 *dot_clock_p,
+                                    u32 *fb_div_p,
+                                    u32 *frac_fb_div_p,
+                                    u32 *ref_div_p,
+                                    u32 *post_div_p);
 
 extern void radeon_setup_encoder_clones(struct drm_device *dev);
 
index 3b1b2bf..2aed03b 100644 (file)
@@ -430,7 +430,7 @@ static ssize_t radeon_hwmon_show_temp(struct device *dev,
 {
        struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
        struct radeon_device *rdev = ddev->dev_private;
-       u32 temp;
+       int temp;
 
        switch (rdev->pm.int_thermal_type) {
        case THERMAL_TYPE_RV6XX:
@@ -646,6 +646,9 @@ void radeon_pm_fini(struct radeon_device *rdev)
 #endif
        }
 
+       if (rdev->pm.power_state)
+               kfree(rdev->pm.power_state);
+
        radeon_hwmon_fini(rdev);
 }
 
index 3cd4dac..ec93a75 100644 (file)
 #define RADEON_CONFIG_APER_SIZE             0x0108
 #define RADEON_CONFIG_BONDS                 0x00e8
 #define RADEON_CONFIG_CNTL                  0x00e0
+#       define RADEON_CFG_VGA_RAM_EN        (1 << 8)
+#       define RADEON_CFG_VGA_IO_DIS        (1 << 9)
 #       define RADEON_CFG_ATI_REV_A11       (0   << 16)
 #       define RADEON_CFG_ATI_REV_A12       (1   << 16)
 #       define RADEON_CFG_ATI_REV_A13       (2   << 16)
index 1272e4b..8389b4c 100644 (file)
@@ -589,6 +589,20 @@ void radeon_ttm_fini(struct radeon_device *rdev)
        DRM_INFO("radeon: ttm finalized\n");
 }
 
+/* this should only be called at bootup or when userspace
+ * isn't running */
+void radeon_ttm_set_active_vram_size(struct radeon_device *rdev, u64 size)
+{
+       struct ttm_mem_type_manager *man;
+
+       if (!rdev->mman.initialized)
+               return;
+
+       man = &rdev->mman.bdev.man[TTM_PL_VRAM];
+       /* this just adjusts TTM size idea, which sets lpfn to the correct value */
+       man->size = size >> PAGE_SHIFT;
+}
+
 static struct vm_operations_struct radeon_ttm_vm_ops;
 static const struct vm_operations_struct *ttm_vm_ops = NULL;
 
@@ -787,9 +801,9 @@ static int radeon_ttm_debugfs_init(struct radeon_device *rdev)
                radeon_mem_types_list[i].show = &radeon_mm_dump_table;
                radeon_mem_types_list[i].driver_features = 0;
                if (i == 0)
-                       radeon_mem_types_list[i].data = &rdev->mman.bdev.man[TTM_PL_VRAM].priv;
+                       radeon_mem_types_list[i].data = rdev->mman.bdev.man[TTM_PL_VRAM].priv;
                else
-                       radeon_mem_types_list[i].data = &rdev->mman.bdev.man[TTM_PL_TT].priv;
+                       radeon_mem_types_list[i].data = rdev->mman.bdev.man[TTM_PL_TT].priv;
 
        }
        /* Add ttm page pool to debugfs */
index b506ec1..e8a1786 100644 (file)
@@ -683,9 +683,7 @@ r300 0x4f60
 0x4DF4 US_ALU_CONST_G_31
 0x4DF8 US_ALU_CONST_B_31
 0x4DFC US_ALU_CONST_A_31
-0x4E04 RB3D_BLENDCNTL_R3
 0x4E08 RB3D_ABLENDCNTL_R3
-0x4E0C RB3D_COLOR_CHANNEL_MASK
 0x4E10 RB3D_CONSTANT_COLOR
 0x4E14 RB3D_COLOR_CLEAR_VALUE
 0x4E18 RB3D_ROPCNTL_R3
@@ -706,13 +704,11 @@ r300 0x4f60
 0x4E74 RB3D_CMASK_WRINDEX
 0x4E78 RB3D_CMASK_DWORD
 0x4E7C RB3D_CMASK_RDINDEX
-0x4E80 RB3D_AARESOLVE_OFFSET
-0x4E84 RB3D_AARESOLVE_PITCH
-0x4E88 RB3D_AARESOLVE_CTL
 0x4EA0 RB3D_DISCARD_SRC_PIXEL_LTE_THRESHOLD
 0x4EA4 RB3D_DISCARD_SRC_PIXEL_GTE_THRESHOLD
 0x4F04 ZB_ZSTENCILCNTL
 0x4F08 ZB_STENCILREFMASK
 0x4F14 ZB_ZTOP
 0x4F18 ZB_ZCACHE_CTLSTAT
+0x4F28 ZB_DEPTHCLEARVALUE
 0x4F58 ZB_ZPASS_DATA
index 8c1214c..722074e 100644 (file)
@@ -130,7 +130,6 @@ r420 0x4f60
 0x401C GB_SELECT
 0x4020 GB_AA_CONFIG
 0x4024 GB_FIFO_SIZE
-0x4028 GB_Z_PEQ_CONFIG
 0x4100 TX_INVALTAGS
 0x4200 GA_POINT_S0
 0x4204 GA_POINT_T0
@@ -750,9 +749,7 @@ r420 0x4f60
 0x4DF4 US_ALU_CONST_G_31
 0x4DF8 US_ALU_CONST_B_31
 0x4DFC US_ALU_CONST_A_31
-0x4E04 RB3D_BLENDCNTL_R3
 0x4E08 RB3D_ABLENDCNTL_R3
-0x4E0C RB3D_COLOR_CHANNEL_MASK
 0x4E10 RB3D_CONSTANT_COLOR
 0x4E14 RB3D_COLOR_CLEAR_VALUE
 0x4E18 RB3D_ROPCNTL_R3
@@ -773,13 +770,11 @@ r420 0x4f60
 0x4E74 RB3D_CMASK_WRINDEX
 0x4E78 RB3D_CMASK_DWORD
 0x4E7C RB3D_CMASK_RDINDEX
-0x4E80 RB3D_AARESOLVE_OFFSET
-0x4E84 RB3D_AARESOLVE_PITCH
-0x4E88 RB3D_AARESOLVE_CTL
 0x4EA0 RB3D_DISCARD_SRC_PIXEL_LTE_THRESHOLD
 0x4EA4 RB3D_DISCARD_SRC_PIXEL_GTE_THRESHOLD
 0x4F04 ZB_ZSTENCILCNTL
 0x4F08 ZB_STENCILREFMASK
 0x4F14 ZB_ZTOP
 0x4F18 ZB_ZCACHE_CTLSTAT
+0x4F28 ZB_DEPTHCLEARVALUE
 0x4F58 ZB_ZPASS_DATA
index 0828d80..d9f6286 100644 (file)
@@ -749,9 +749,7 @@ rs600 0x6d40
 0x4DF4 US_ALU_CONST_G_31
 0x4DF8 US_ALU_CONST_B_31
 0x4DFC US_ALU_CONST_A_31
-0x4E04 RB3D_BLENDCNTL_R3
 0x4E08 RB3D_ABLENDCNTL_R3
-0x4E0C RB3D_COLOR_CHANNEL_MASK
 0x4E10 RB3D_CONSTANT_COLOR
 0x4E14 RB3D_COLOR_CLEAR_VALUE
 0x4E18 RB3D_ROPCNTL_R3
@@ -772,13 +770,11 @@ rs600 0x6d40
 0x4E74 RB3D_CMASK_WRINDEX
 0x4E78 RB3D_CMASK_DWORD
 0x4E7C RB3D_CMASK_RDINDEX
-0x4E80 RB3D_AARESOLVE_OFFSET
-0x4E84 RB3D_AARESOLVE_PITCH
-0x4E88 RB3D_AARESOLVE_CTL
 0x4EA0 RB3D_DISCARD_SRC_PIXEL_LTE_THRESHOLD
 0x4EA4 RB3D_DISCARD_SRC_PIXEL_GTE_THRESHOLD
 0x4F04 ZB_ZSTENCILCNTL
 0x4F08 ZB_STENCILREFMASK
 0x4F14 ZB_ZTOP
 0x4F18 ZB_ZCACHE_CTLSTAT
+0x4F28 ZB_DEPTHCLEARVALUE
 0x4F58 ZB_ZPASS_DATA
index ef422bb..911a8fb 100644 (file)
@@ -164,7 +164,6 @@ rv515 0x6d40
 0x401C GB_SELECT
 0x4020 GB_AA_CONFIG
 0x4024 GB_FIFO_SIZE
-0x4028 GB_Z_PEQ_CONFIG
 0x4100 TX_INVALTAGS
 0x4114 SU_TEX_WRAP_PS3
 0x4118 PS3_ENABLE
@@ -461,9 +460,7 @@ rv515 0x6d40
 0x4DF4 US_ALU_CONST_G_31
 0x4DF8 US_ALU_CONST_B_31
 0x4DFC US_ALU_CONST_A_31
-0x4E04 RB3D_BLENDCNTL_R3
 0x4E08 RB3D_ABLENDCNTL_R3
-0x4E0C RB3D_COLOR_CHANNEL_MASK
 0x4E10 RB3D_CONSTANT_COLOR
 0x4E14 RB3D_COLOR_CLEAR_VALUE
 0x4E18 RB3D_ROPCNTL_R3
@@ -484,9 +481,6 @@ rv515 0x6d40
 0x4E74 RB3D_CMASK_WRINDEX
 0x4E78 RB3D_CMASK_DWORD
 0x4E7C RB3D_CMASK_RDINDEX
-0x4E80 RB3D_AARESOLVE_OFFSET
-0x4E84 RB3D_AARESOLVE_PITCH
-0x4E88 RB3D_AARESOLVE_CTL
 0x4EA0 RB3D_DISCARD_SRC_PIXEL_LTE_THRESHOLD
 0x4EA4 RB3D_DISCARD_SRC_PIXEL_GTE_THRESHOLD
 0x4EF8 RB3D_CONSTANT_COLOR_AR
@@ -496,4 +490,5 @@ rv515 0x6d40
 0x4F14 ZB_ZTOP
 0x4F18 ZB_ZCACHE_CTLSTAT
 0x4F58 ZB_ZPASS_DATA
+0x4F28 ZB_DEPTHCLEARVALUE
 0x4FD4 ZB_STENCILREFMASK_BF
index 5512e4e..c76283d 100644 (file)
@@ -203,6 +203,9 @@ void rs400_gart_fini(struct radeon_device *rdev)
        radeon_gart_table_ram_free(rdev);
 }
 
+#define RS400_PTE_WRITEABLE (1 << 2)
+#define RS400_PTE_READABLE  (1 << 3)
+
 int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
 {
        uint32_t entry;
@@ -213,7 +216,7 @@ int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
 
        entry = (lower_32_bits(addr) & PAGE_MASK) |
                ((upper_32_bits(addr) & 0xff) << 4) |
-               0xc;
+               RS400_PTE_WRITEABLE | RS400_PTE_READABLE;
        entry = cpu_to_le32(entry);
        rdev->gart.table.ram.ptr[i] = entry;
        return 0;
@@ -226,8 +229,8 @@ int rs400_mc_wait_for_idle(struct radeon_device *rdev)
 
        for (i = 0; i < rdev->usec_timeout; i++) {
                /* read MC_STATUS */
-               tmp = RREG32(0x0150);
-               if (tmp & (1 << 2)) {
+               tmp = RREG32(RADEON_MC_STATUS);
+               if (tmp & RADEON_MC_IDLE) {
                        return 0;
                }
                DRM_UDELAY(1);
@@ -241,7 +244,7 @@ void rs400_gpu_init(struct radeon_device *rdev)
        r420_pipes_init(rdev);
        if (rs400_mc_wait_for_idle(rdev)) {
                printk(KERN_WARNING "rs400: Failed to wait MC idle while "
-                      "programming pipes. Bad things might happen. %08x\n", RREG32(0x150));
+                      "programming pipes. Bad things might happen. %08x\n", RREG32(RADEON_MC_STATUS));
        }
 }
 
@@ -300,9 +303,9 @@ static int rs400_debugfs_gart_info(struct seq_file *m, void *data)
                seq_printf(m, "MCCFG_AGP_BASE_2 0x%08x\n", tmp);
                tmp = RREG32_MC(RS690_MCCFG_AGP_LOCATION);
                seq_printf(m, "MCCFG_AGP_LOCATION 0x%08x\n", tmp);
-               tmp = RREG32_MC(0x100);
+               tmp = RREG32_MC(RS690_MCCFG_FB_LOCATION);
                seq_printf(m, "MCCFG_FB_LOCATION 0x%08x\n", tmp);
-               tmp = RREG32(0x134);
+               tmp = RREG32(RS690_HDP_FB_LOCATION);
                seq_printf(m, "HDP_FB_LOCATION 0x%08x\n", tmp);
        } else {
                tmp = RREG32(RADEON_AGP_BASE);
index 5afe294..8af4679 100644 (file)
@@ -751,7 +751,6 @@ void rs600_mc_init(struct radeon_device *rdev)
        rdev->mc.real_vram_size = RREG32(RADEON_CONFIG_MEMSIZE);
        rdev->mc.mc_vram_size = rdev->mc.real_vram_size;
        rdev->mc.visible_vram_size = rdev->mc.aper_size;
-       rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
        rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev);
        base = RREG32_MC(R_000004_MC_FB_LOCATION);
        base = G_000004_MC_FB_START(base) << 16;
index 0137d3e..66c949b 100644 (file)
@@ -77,9 +77,9 @@ void rs690_pm_info(struct radeon_device *rdev)
                switch (crev) {
                case 1:
                        tmp.full = dfixed_const(100);
-                       rdev->pm.igp_sideport_mclk.full = dfixed_const(info->info.ulBootUpMemoryClock);
+                       rdev->pm.igp_sideport_mclk.full = dfixed_const(le32_to_cpu(info->info.ulBootUpMemoryClock));
                        rdev->pm.igp_sideport_mclk.full = dfixed_div(rdev->pm.igp_sideport_mclk, tmp);
-                       if (info->info.usK8MemoryClock)
+                       if (le16_to_cpu(info->info.usK8MemoryClock))
                                rdev->pm.igp_system_mclk.full = dfixed_const(le16_to_cpu(info->info.usK8MemoryClock));
                        else if (rdev->clock.default_mclk) {
                                rdev->pm.igp_system_mclk.full = dfixed_const(rdev->clock.default_mclk);
@@ -91,16 +91,16 @@ void rs690_pm_info(struct radeon_device *rdev)
                        break;
                case 2:
                        tmp.full = dfixed_const(100);
-                       rdev->pm.igp_sideport_mclk.full = dfixed_const(info->info_v2.ulBootUpSidePortClock);
+                       rdev->pm.igp_sideport_mclk.full = dfixed_const(le32_to_cpu(info->info_v2.ulBootUpSidePortClock));
                        rdev->pm.igp_sideport_mclk.full = dfixed_div(rdev->pm.igp_sideport_mclk, tmp);
-                       if (info->info_v2.ulBootUpUMAClock)
-                               rdev->pm.igp_system_mclk.full = dfixed_const(info->info_v2.ulBootUpUMAClock);
+                       if (le32_to_cpu(info->info_v2.ulBootUpUMAClock))
+                               rdev->pm.igp_system_mclk.full = dfixed_const(le32_to_cpu(info->info_v2.ulBootUpUMAClock));
                        else if (rdev->clock.default_mclk)
                                rdev->pm.igp_system_mclk.full = dfixed_const(rdev->clock.default_mclk);
                        else
                                rdev->pm.igp_system_mclk.full = dfixed_const(66700);
                        rdev->pm.igp_system_mclk.full = dfixed_div(rdev->pm.igp_system_mclk, tmp);
-                       rdev->pm.igp_ht_link_clk.full = dfixed_const(info->info_v2.ulHTLinkFreq);
+                       rdev->pm.igp_ht_link_clk.full = dfixed_const(le32_to_cpu(info->info_v2.ulHTLinkFreq));
                        rdev->pm.igp_ht_link_clk.full = dfixed_div(rdev->pm.igp_ht_link_clk, tmp);
                        rdev->pm.igp_ht_link_width.full = dfixed_const(le16_to_cpu(info->info_v2.usMinHTLinkWidth));
                        break;
@@ -157,7 +157,6 @@ void rs690_mc_init(struct radeon_device *rdev)
        rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0);
        rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0);
        rdev->mc.visible_vram_size = rdev->mc.aper_size;
-       rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
        base = RREG32_MC(R_000100_MCCFG_FB_LOCATION);
        base = G_000100_MC_FB_START(base) << 16;
        rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev);
index 5d569f4..64b57af 100644 (file)
@@ -69,13 +69,13 @@ void rv515_ring_start(struct radeon_device *rdev)
                          ISYNC_CPSCRATCH_IDLEGUI);
        radeon_ring_write(rdev, PACKET0(WAIT_UNTIL, 0));
        radeon_ring_write(rdev, WAIT_2D_IDLECLEAN | WAIT_3D_IDLECLEAN);
-       radeon_ring_write(rdev, PACKET0(0x170C, 0));
-       radeon_ring_write(rdev, 1 << 31);
+       radeon_ring_write(rdev, PACKET0(R300_DST_PIPE_CONFIG, 0));
+       radeon_ring_write(rdev, R300_PIPE_AUTO_CONFIG);
        radeon_ring_write(rdev, PACKET0(GB_SELECT, 0));
        radeon_ring_write(rdev, 0);
        radeon_ring_write(rdev, PACKET0(GB_ENABLE, 0));
        radeon_ring_write(rdev, 0);
-       radeon_ring_write(rdev, PACKET0(0x42C8, 0));
+       radeon_ring_write(rdev, PACKET0(R500_SU_REG_DEST, 0));
        radeon_ring_write(rdev, (1 << rdev->num_gb_pipes) - 1);
        radeon_ring_write(rdev, PACKET0(VAP_INDEX_OFFSET, 0));
        radeon_ring_write(rdev, 0);
@@ -153,8 +153,8 @@ void rv515_gpu_init(struct radeon_device *rdev)
        }
        rv515_vga_render_disable(rdev);
        r420_pipes_init(rdev);
-       gb_pipe_select = RREG32(0x402C);
-       tmp = RREG32(0x170C);
+       gb_pipe_select = RREG32(R400_GB_PIPE_SELECT);
+       tmp = RREG32(R300_DST_PIPE_CONFIG);
        pipe_select_current = (tmp >> 2) & 3;
        tmp = (1 << pipe_select_current) |
              (((gb_pipe_select >> 8) & 0xF) << 4);
index 491dc90..714ad45 100644 (file)
@@ -78,18 +78,23 @@ u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base)
 }
 
 /* get temperature in millidegrees */
-u32 rv770_get_temp(struct radeon_device *rdev)
+int rv770_get_temp(struct radeon_device *rdev)
 {
        u32 temp = (RREG32(CG_MULT_THERMAL_STATUS) & ASIC_T_MASK) >>
                ASIC_T_SHIFT;
-       u32 actual_temp = 0;
-
-       if ((temp >> 9) & 1)
-               actual_temp = 0;
-       else
-               actual_temp = (temp >> 1) & 0xff;
-
-       return actual_temp * 1000;
+       int actual_temp;
+
+       if (temp & 0x400)
+               actual_temp = -256;
+       else if (temp & 0x200)
+               actual_temp = 255;
+       else if (temp & 0x100) {
+               actual_temp = temp & 0x1ff;
+               actual_temp |= ~0x1ff;
+       } else
+               actual_temp = temp & 0xff;
+
+       return (actual_temp * 1000) / 2;
 }
 
 void rv770_pm_misc(struct radeon_device *rdev)
@@ -302,7 +307,7 @@ static void rv770_mc_program(struct radeon_device *rdev)
  */
 void r700_cp_stop(struct radeon_device *rdev)
 {
-       rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
+       radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
        WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT));
        WREG32(SCRATCH_UMSK, 0);
 }
@@ -316,7 +321,11 @@ static int rv770_cp_load_microcode(struct radeon_device *rdev)
                return -EINVAL;
 
        r700_cp_stop(rdev);
-       WREG32(CP_RB_CNTL, RB_NO_UPDATE | (15 << 8) | (3 << 0));
+       WREG32(CP_RB_CNTL,
+#ifdef __BIG_ENDIAN
+              BUF_SWAP_32BIT |
+#endif
+              RB_NO_UPDATE | RB_BLKSZ(15) | RB_BUFSZ(3));
 
        /* Reset cp */
        WREG32(GRBM_SOFT_RESET, SOFT_RESET_CP);
@@ -1114,7 +1123,6 @@ int rv770_mc_init(struct radeon_device *rdev)
        rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE);
        rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE);
        rdev->mc.visible_vram_size = rdev->mc.aper_size;
-       rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
        r700_vram_gtt_location(rdev, &rdev->mc);
        radeon_update_bandwidth_info(rdev);
 
index abc8cf5..79fa588 100644 (file)
 #define                ROQ_IB1_START(x)                                ((x) << 0)
 #define                ROQ_IB2_START(x)                                ((x) << 8)
 #define        CP_RB_CNTL                                      0xC104
-#define                RB_BUFSZ(x)                                     ((x)<<0)
-#define                RB_BLKSZ(x)                                     ((x)<<8)
-#define                RB_NO_UPDATE                                    (1<<27)
-#define                RB_RPTR_WR_ENA                                  (1<<31)
+#define                RB_BUFSZ(x)                                     ((x) << 0)
+#define                RB_BLKSZ(x)                                     ((x) << 8)
+#define                RB_NO_UPDATE                                    (1 << 27)
+#define                RB_RPTR_WR_ENA                                  (1 << 31)
 #define                BUF_SWAP_32BIT                                  (2 << 16)
 #define        CP_RB_RPTR                                      0x8700
 #define        CP_RB_RPTR_ADDR                                 0xC10C
index 09aea5f..70e60a4 100644 (file)
@@ -1,11 +1,13 @@
 config STUB_POULSBO
        tristate "Intel GMA500 Stub Driver"
        depends on PCI
+       depends on NET # for THERMAL
        # Poulsbo stub depends on ACPI_VIDEO when ACPI is enabled
        # but for select to work, need to select ACPI_VIDEO's dependencies, ick
        select BACKLIGHT_CLASS_DEVICE if ACPI
        select INPUT if ACPI
        select ACPI_VIDEO if ACPI
+       select THERMAL if ACPI
        help
          Choose this option if you have a system that has Intel GMA500
          (Poulsbo) integrated graphics. If M is selected, the module will
index 773e484..297bc9a 100644 (file)
@@ -238,13 +238,13 @@ config SENSORS_K8TEMP
          will be called k8temp.
 
 config SENSORS_K10TEMP
-       tristate "AMD Phenom/Sempron/Turion/Opteron temperature sensor"
+       tristate "AMD Family 10h/11h/12h/14h temperature sensor"
        depends on X86 && PCI
        help
          If you say yes here you get support for the temperature
          sensor(s) inside your CPU. Supported are later revisions of
-         the AMD Family 10h and all revisions of the AMD Family 11h
-         microarchitectures.
+         the AMD Family 10h and all revisions of the AMD Family 11h,
+         12h (Llano), and 14h (Brazos) microarchitectures.
 
          This driver can also be built as a module.  If so, the module
          will be called k10temp.
@@ -455,13 +455,14 @@ config SENSORS_JZ4740
          called jz4740-hwmon.
 
 config SENSORS_JC42
-       tristate "JEDEC JC42.4 compliant temperature sensors"
+       tristate "JEDEC JC42.4 compliant memory module temperature sensors"
        depends on I2C
        help
-         If you say yes here you get support for Jedec JC42.4 compliant
-         temperature sensors. Support will include, but not be limited to,
-         ADT7408, CAT34TS02,, CAT6095, MAX6604, MCP9805, MCP98242, MCP98243,
-         MCP9843, SE97, SE98, STTS424, TSE2002B3, and TS3000B3.
+         If you say yes here, you get support for JEDEC JC42.4 compliant
+         temperature sensors, which are used on many DDR3 memory modules for
+         mobile devices and servers.  Support will include, but not be limited
+         to, ADT7408, CAT34TS02, CAT6095, MAX6604, MCP9805, MCP98242, MCP98243,
+         MCP9843, SE97, SE98, STTS424(E), TSE2002B3, and TS3000B3.
 
          This driver can also be built as a module.  If so, the module
          will be called jc42.
@@ -574,7 +575,7 @@ config SENSORS_LM85
        help
          If you say yes here you get support for National Semiconductor LM85
          sensor chips and clones: ADM1027, ADT7463, ADT7468, EMC6D100,
-         EMC6D101 and EMC6D102.
+         EMC6D101, EMC6D102, and EMC6D103.
 
          This driver can also be built as a module.  If so, the module
          will be called lm85.
index 86d822a..d46c0c7 100644 (file)
@@ -242,6 +242,7 @@ static const struct i2c_device_id ad7414_id[] = {
        { "ad7414", 0 },
        {}
 };
+MODULE_DEVICE_TABLE(i2c, ad7414_id);
 
 static struct i2c_driver ad7414_driver = {
        .driver = {
index f13c843..5cc3e37 100644 (file)
@@ -334,6 +334,7 @@ static const struct i2c_device_id adt7411_id[] = {
        { "adt7411", 0 },
        { }
 };
+MODULE_DEVICE_TABLE(i2c, adt7411_id);
 
 static struct i2c_driver adt7411_driver = {
        .driver         = {
index ce0372f..4c07436 100644 (file)
@@ -1072,6 +1072,7 @@ static int applesmc_create_nodes(struct applesmc_node_group *groups, int num)
                        node->sda.dev_attr.show = grp->show;
                        node->sda.dev_attr.store = grp->store;
                        attr = &node->sda.dev_attr.attr;
+                       sysfs_attr_init(attr);
                        attr->name = node->name;
                        attr->mode = S_IRUGO | (grp->store ? S_IWUSR : 0);
                        ret = sysfs_create_file(&pdev->dev.kobj, attr);
index 2d68cf3..b5e8920 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/dmi.h>
 
 #include <acpi/acpi.h>
 #include <acpi/acpixf.h>
 
 #define ATK_HID "ATK0110"
 
+static bool new_if;
+module_param(new_if, bool, 0);
+MODULE_PARM_DESC(new_if, "Override detection heuristic and force the use of the new ATK0110 interface");
+
+static const struct dmi_system_id __initconst atk_force_new_if[] = {
+       {
+               /* Old interface has broken MCH temp monitoring */
+               .ident = "Asus Sabertooth X58",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_NAME, "SABERTOOTH X58")
+               }
+       },
+       { }
+};
+
 /* Minimum time between readings, enforced in order to avoid
  * hogging the CPU.
  */
@@ -1302,7 +1318,9 @@ static int atk_probe_if(struct atk_data *data)
         * analysis of multiple DSDTs indicates that when both interfaces
         * are present the new one (GGRP/GITM) is not functional.
         */
-       if (data->rtmp_handle && data->rvlt_handle && data->rfan_handle)
+       if (new_if)
+               dev_info(dev, "Overriding interface detection\n");
+       if (data->rtmp_handle && data->rvlt_handle && data->rfan_handle && !new_if)
                data->old_interface = true;
        else if (data->enumerate_handle && data->read_handle &&
                        data->write_handle)
@@ -1420,6 +1438,9 @@ static int __init atk0110_init(void)
                return -EBUSY;
        }
 
+       if (dmi_check_system(atk_force_new_if))
+               new_if = true;
+
        ret = acpi_bus_register_driver(&atk_driver);
        if (ret)
                pr_info("acpi_bus_register_driver failed: %d\n", ret);
index 5dea9fa..cd2a6e4 100644 (file)
@@ -344,7 +344,7 @@ static int emc1403_remove(struct i2c_client *client)
 }
 
 static const unsigned short emc1403_address_list[] = {
-       0x18, 0x2a, 0x4c, 0x4d, I2C_CLIENT_END
+       0x18, 0x29, 0x4c, 0x4d, I2C_CLIENT_END
 };
 
 static const struct i2c_device_id emc1403_idtable[] = {
index 3f49dd3..6e06019 100644 (file)
@@ -37,7 +37,7 @@
 #define SIO_F71858FG_LD_HWM    0x02    /* Hardware monitor logical device */
 #define SIO_F71882FG_LD_HWM    0x04    /* Hardware monitor logical device */
 #define SIO_UNLOCK_KEY         0x87    /* Key to enable Super-I/O */
-#define SIO_LOCK_KEY           0xAA    /* Key to diasble Super-I/O */
+#define SIO_LOCK_KEY           0xAA    /* Key to disable Super-I/O */
 
 #define SIO_REG_LDSEL          0x07    /* Logical device select */
 #define SIO_REG_DEVID          0x20    /* Device ID (2 bytes) */
@@ -2111,7 +2111,6 @@ static int f71882fg_remove(struct platform_device *pdev)
        int nr_fans = (data->type == f71882fg) ? 4 : 3;
        u8 start_reg = f71882fg_read8(data, F71882FG_REG_START);
 
-       platform_set_drvdata(pdev, NULL);
        if (data->hwmon_dev)
                hwmon_device_unregister(data->hwmon_dev);
 
@@ -2178,6 +2177,7 @@ static int f71882fg_remove(struct platform_device *pdev)
                }
        }
 
+       platform_set_drvdata(pdev, NULL);
        kfree(data);
 
        return 0;
index 340fc78..9349912 100644 (file)
@@ -53,6 +53,8 @@ static const unsigned short normal_i2c[] = {
 
 /* Configuration register defines */
 #define JC42_CFG_CRIT_ONLY     (1 << 2)
+#define JC42_CFG_TCRIT_LOCK    (1 << 6)
+#define JC42_CFG_EVENT_LOCK    (1 << 7)
 #define JC42_CFG_SHUTDOWN      (1 << 8)
 #define JC42_CFG_HYST_SHIFT    9
 #define JC42_CFG_HYST_MASK     0x03
@@ -332,7 +334,7 @@ static ssize_t set_temp_crit_hyst(struct device *dev,
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct jc42_data *data = i2c_get_clientdata(client);
-       long val;
+       unsigned long val;
        int diff, hyst;
        int err;
        int ret = count;
@@ -380,14 +382,14 @@ static ssize_t show_alarm(struct device *dev,
 
 static DEVICE_ATTR(temp1_input, S_IRUGO,
                   show_temp_input, NULL);
-static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
+static DEVICE_ATTR(temp1_crit, S_IRUGO,
                   show_temp_crit, set_temp_crit);
-static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
+static DEVICE_ATTR(temp1_min, S_IRUGO,
                   show_temp_min, set_temp_min);
-static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+static DEVICE_ATTR(temp1_max, S_IRUGO,
                   show_temp_max, set_temp_max);
 
-static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO,
+static DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
                   show_temp_crit_hyst, set_temp_crit_hyst);
 static DEVICE_ATTR(temp1_max_hyst, S_IRUGO,
                   show_temp_max_hyst, NULL);
@@ -412,8 +414,31 @@ static struct attribute *jc42_attributes[] = {
        NULL
 };
 
+static mode_t jc42_attribute_mode(struct kobject *kobj,
+                                 struct attribute *attr, int index)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct jc42_data *data = i2c_get_clientdata(client);
+       unsigned int config = data->config;
+       bool readonly;
+
+       if (attr == &dev_attr_temp1_crit.attr)
+               readonly = config & JC42_CFG_TCRIT_LOCK;
+       else if (attr == &dev_attr_temp1_min.attr ||
+                attr == &dev_attr_temp1_max.attr)
+               readonly = config & JC42_CFG_EVENT_LOCK;
+       else if (attr == &dev_attr_temp1_crit_hyst.attr)
+               readonly = config & (JC42_CFG_EVENT_LOCK | JC42_CFG_TCRIT_LOCK);
+       else
+               readonly = true;
+
+       return S_IRUGO | (readonly ? 0 : S_IWUSR);
+}
+
 static const struct attribute_group jc42_group = {
        .attrs = jc42_attributes,
+       .is_visible = jc42_attribute_mode,
 };
 
 /* Return 0 if detection is successful, -ENODEV otherwise */
index da5a240..82bf65a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * k10temp.c - AMD Family 10h/11h processor hardware monitoring
+ * k10temp.c - AMD Family 10h/11h/12h/14h processor hardware monitoring
  *
  * Copyright (c) 2009 Clemens Ladisch <clemens@ladisch.de>
  *
@@ -25,7 +25,7 @@
 #include <linux/pci.h>
 #include <asm/processor.h>
 
-MODULE_DESCRIPTION("AMD Family 10h/11h CPU core temperature monitor");
+MODULE_DESCRIPTION("AMD Family 10h/11h/12h/14h CPU core temperature monitor");
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_LICENSE("GPL");
 
@@ -208,6 +208,7 @@ static void __devexit k10temp_remove(struct pci_dev *pdev)
 static const struct pci_device_id k10temp_id_table[] = {
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) },
+       { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) },
        {}
 };
 MODULE_DEVICE_TABLE(pci, k10temp_id_table);
index 1b674b7..d805e8e 100644 (file)
@@ -957,7 +957,7 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
 
        /* bail if we did not get an IRQ from the bus layer */
        if (!dev->irq) {
-               pr_err("No IRQ. Disabling /dev/freefall\n");
+               pr_debug("No IRQ. Disabling /dev/freefall\n");
                goto out;
        }
 
index 776aeb3..508cb29 100644 (file)
@@ -98,6 +98,9 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
  * value, it uses signed 8-bit values with LSB = 1 degree Celsius.
  * For remote temperature, low and high limits, it uses signed 11-bit values
  * with LSB = 0.125 degree Celsius, left-justified in 16-bit registers.
+ * For LM64 the actual remote diode temperature is 16 degree Celsius higher
+ * than the register reading. Remote temperature setpoints have to be
+ * adapted accordingly.
  */
 
 #define FAN_FROM_REG(reg)      ((reg) == 0xFFFC || (reg) == 0 ? 0 : \
@@ -165,6 +168,8 @@ struct lm63_data {
        struct mutex update_lock;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* in jiffies */
+       int kind;
+       int temp2_offset;
 
        /* registers values */
        u8 config, config_fan;
@@ -247,16 +252,34 @@ static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *dum
        return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2);
 }
 
-static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr,
-                         char *buf)
+/*
+ * There are 8bit registers for both local(temp1) and remote(temp2) sensor.
+ * For remote sensor registers temp2_offset has to be considered,
+ * for local sensor it must not.
+ * So we need separate 8bit accessors for local and remote sensor.
+ */
+static ssize_t show_local_temp8(struct device *dev,
+                               struct device_attribute *devattr,
+                               char *buf)
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct lm63_data *data = lm63_update_device(dev);
        return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index]));
 }
 
-static ssize_t set_temp8(struct device *dev, struct device_attribute *dummy,
-                        const char *buf, size_t count)
+static ssize_t show_remote_temp8(struct device *dev,
+                                struct device_attribute *devattr,
+                                char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct lm63_data *data = lm63_update_device(dev);
+       return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index])
+                      + data->temp2_offset);
+}
+
+static ssize_t set_local_temp8(struct device *dev,
+                              struct device_attribute *dummy,
+                              const char *buf, size_t count)
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct lm63_data *data = i2c_get_clientdata(client);
@@ -274,7 +297,8 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
        struct lm63_data *data = lm63_update_device(dev);
-       return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[attr->index]));
+       return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[attr->index])
+                      + data->temp2_offset);
 }
 
 static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
@@ -294,7 +318,7 @@ static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
        int nr = attr->index;
 
        mutex_lock(&data->update_lock);
-       data->temp11[nr] = TEMP11_TO_REG(val);
+       data->temp11[nr] = TEMP11_TO_REG(val - data->temp2_offset);
        i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2],
                                  data->temp11[nr] >> 8);
        i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1],
@@ -310,6 +334,7 @@ static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute
 {
        struct lm63_data *data = lm63_update_device(dev);
        return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[2])
+                      + data->temp2_offset
                       - TEMP8_FROM_REG(data->temp2_crit_hyst));
 }
 
@@ -324,7 +349,7 @@ static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *
        long hyst;
 
        mutex_lock(&data->update_lock);
-       hyst = TEMP8_FROM_REG(data->temp8[2]) - val;
+       hyst = TEMP8_FROM_REG(data->temp8[2]) + data->temp2_offset - val;
        i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST,
                                  HYST_TO_REG(hyst));
        mutex_unlock(&data->update_lock);
@@ -355,16 +380,21 @@ static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan,
 static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1);
 static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL);
 
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0);
-static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8,
-       set_temp8, 1);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_local_temp8, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_local_temp8,
+       set_local_temp8, 1);
 
 static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11,
        set_temp11, 1);
 static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11,
        set_temp11, 2);
-static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp8, NULL, 2);
+/*
+ * On LM63, temp2_crit can be set only once, which should be job
+ * of the bootloader.
+ */
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_remote_temp8,
+       NULL, 2);
 static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst,
        set_temp2_crit_hyst);
 
@@ -479,7 +509,12 @@ static int lm63_probe(struct i2c_client *new_client,
        data->valid = 0;
        mutex_init(&data->update_lock);
 
-       /* Initialize the LM63 chip */
+       /* Set the device type */
+       data->kind = id->driver_data;
+       if (data->kind == lm64)
+               data->temp2_offset = 16000;
+
+       /* Initialize chip */
        lm63_init_client(new_client);
 
        /* Register sysfs hooks */
index 1e22984..d2cc286 100644 (file)
@@ -41,7 +41,7 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
 enum chips {
        any_chip, lm85b, lm85c,
        adm1027, adt7463, adt7468,
-       emc6d100, emc6d102
+       emc6d100, emc6d102, emc6d103
 };
 
 /* The LM85 registers */
@@ -90,6 +90,9 @@ enum chips {
 #define        LM85_VERSTEP_EMC6D100_A0        0x60
 #define        LM85_VERSTEP_EMC6D100_A1        0x61
 #define        LM85_VERSTEP_EMC6D102           0x65
+#define        LM85_VERSTEP_EMC6D103_A0        0x68
+#define        LM85_VERSTEP_EMC6D103_A1        0x69
+#define        LM85_VERSTEP_EMC6D103S          0x6A    /* Also known as EMC6D103:A2 */
 
 #define        LM85_REG_CONFIG                 0x40
 
@@ -348,6 +351,7 @@ static const struct i2c_device_id lm85_id[] = {
        { "emc6d100", emc6d100 },
        { "emc6d101", emc6d100 },
        { "emc6d102", emc6d102 },
+       { "emc6d103", emc6d103 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, lm85_id);
@@ -1250,6 +1254,20 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info)
                case LM85_VERSTEP_EMC6D102:
                        type_name = "emc6d102";
                        break;
+               case LM85_VERSTEP_EMC6D103_A0:
+               case LM85_VERSTEP_EMC6D103_A1:
+                       type_name = "emc6d103";
+                       break;
+               /*
+                * Registers apparently missing in EMC6D103S/EMC6D103:A2
+                * compared to EMC6D103:A0, EMC6D103:A1, and EMC6D102
+                * (according to the data sheets), but used unconditionally
+                * in the driver: 62[5:7], 6D[0:7], and 6E[0:7].
+                * So skip EMC6D103S for now.
+               case LM85_VERSTEP_EMC6D103S:
+                       type_name = "emc6d103s";
+                       break;
+                */
                }
        } else {
                dev_dbg(&adapter->dev,
@@ -1283,6 +1301,7 @@ static int lm85_probe(struct i2c_client *client,
        case adt7468:
        case emc6d100:
        case emc6d102:
+       case emc6d103:
                data->freq_map = adm1027_freq_map;
                break;
        default:
@@ -1468,7 +1487,7 @@ static struct lm85_data *lm85_update_device(struct device *dev)
                        /* More alarm bits */
                        data->alarms |= lm85_read_value(client,
                                                EMC6D100_REG_ALARM3) << 16;
-               } else if (data->type == emc6d102) {
+               } else if (data->type == emc6d102 || data->type == emc6d103) {
                        /* Have to read LSB bits after the MSB ones because
                           the reading of the MSB bits has frozen the
                           LSBs (backward from the ADM1027).
index 2e067dd..50ea1f4 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/pci.h>
 #include <linux/mutex.h>
 #include <linux/ktime.h>
+#include <linux/slab.h>
 
 #define PCH_EVENT_SET  0       /* I2C Interrupt Event Set Status */
 #define PCH_EVENT_NONE 1       /* I2C Interrupt Event Clear Status */
index ef3bcb1..1b46a9d 100644 (file)
@@ -249,7 +249,7 @@ static struct i2c_adapter ocores_adapter = {
 static int ocores_i2c_of_probe(struct platform_device* pdev,
                                struct ocores_i2c* i2c)
 {
-       __be32* val;
+       const __be32* val;
 
        val = of_get_property(pdev->dev.of_node, "regstep", NULL);
        if (!val) {
@@ -330,9 +330,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
        i2c->adap = ocores_adapter;
        i2c_set_adapdata(&i2c->adap, i2c);
        i2c->adap.dev.parent = &pdev->dev;
-#ifdef CONFIG_OF
        i2c->adap.dev.of_node = pdev->dev.of_node;
-#endif
 
        /* add i2c adapter to i2c tree */
        ret = i2c_add_adapter(&i2c->adap);
@@ -390,15 +388,11 @@ static int ocores_i2c_resume(struct platform_device *pdev)
 #define ocores_i2c_resume      NULL
 #endif
 
-#ifdef CONFIG_OF
 static struct of_device_id ocores_i2c_match[] = {
-        {
-                .compatible = "opencores,i2c-ocores",
-        },
-        {},
+       { .compatible = "opencores,i2c-ocores", },
+       {},
 };
 MODULE_DEVICE_TABLE(of, ocores_i2c_match);
-#endif
 
 /* work with hotplug and coldplug */
 MODULE_ALIAS("platform:ocores-i2c");
@@ -411,9 +405,7 @@ static struct platform_driver ocores_i2c_driver = {
        .driver  = {
                .owner = THIS_MODULE,
                .name = "ocores-i2c",
-#ifdef CONFIG_OF
-                .of_match_table = ocores_i2c_match,
-#endif
+               .of_match_table = ocores_i2c_match,
        },
 };
 
index b605ff3..58a58c7 100644 (file)
@@ -378,9 +378,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
                         * REVISIT: Some wkup sources might not be needed.
                         */
                        dev->westate = OMAP_I2C_WE_ALL;
-                       if (dev->rev < OMAP_I2C_REV_ON_4430)
-                               omap_i2c_write_reg(dev, OMAP_I2C_WE_REG,
-                                                               dev->westate);
+                       omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate);
                }
        }
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
@@ -847,11 +845,15 @@ complete:
                        dev_err(dev->dev, "Arbitration lost\n");
                        err |= OMAP_I2C_STAT_AL;
                }
+               /*
+                * ProDB0017052: Clear ARDY bit twice
+                */
                if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
                                        OMAP_I2C_STAT_AL)) {
                        omap_i2c_ack_stat(dev, stat &
                                (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
-                               OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
+                               OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR |
+                               OMAP_I2C_STAT_ARDY));
                        omap_i2c_complete_cmd(dev, err);
                        return IRQ_HANDLED;
                }
@@ -1137,12 +1139,41 @@ omap_i2c_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_SUSPEND
+static int omap_i2c_suspend(struct device *dev)
+{
+       if (!pm_runtime_suspended(dev))
+               if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend)
+                       dev->bus->pm->runtime_suspend(dev);
+
+       return 0;
+}
+
+static int omap_i2c_resume(struct device *dev)
+{
+       if (!pm_runtime_suspended(dev))
+               if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume)
+                       dev->bus->pm->runtime_resume(dev);
+
+       return 0;
+}
+
+static struct dev_pm_ops omap_i2c_pm_ops = {
+       .suspend = omap_i2c_suspend,
+       .resume = omap_i2c_resume,
+};
+#define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops)
+#else
+#define OMAP_I2C_PM_OPS NULL
+#endif
+
 static struct platform_driver omap_i2c_driver = {
        .probe          = omap_i2c_probe,
        .remove         = omap_i2c_remove,
        .driver         = {
                .name   = "omap_i2c",
                .owner  = THIS_MODULE,
+               .pm     = OMAP_I2C_PM_OPS,
        },
 };
 
index 495be45..266135d 100644 (file)
@@ -942,7 +942,7 @@ stu300_probe(struct platform_device *pdev)
        adap->owner = THIS_MODULE;
        /* DDC class but actually often used for more generic I2C */
        adap->class = I2C_CLASS_DDC;
-       strncpy(adap->name, "ST Microelectronics DDC I2C adapter",
+       strlcpy(adap->name, "ST Microelectronics DDC I2C adapter",
                sizeof(adap->name));
        adap->nr = bus_nr;
        adap->algo = &stu300_algo;
index f0bd5bc..045ba6e 100644 (file)
@@ -537,9 +537,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
        client->dev.parent = &client->adapter->dev;
        client->dev.bus = &i2c_bus_type;
        client->dev.type = &i2c_client_type;
-#ifdef CONFIG_OF
        client->dev.of_node = info->of_node;
-#endif
 
        dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
                     client->addr);
index 1fa091e..4a5c4a4 100644 (file)
@@ -62,6 +62,7 @@
 #include <linux/notifier.h>
 #include <linux/cpu.h>
 #include <asm/mwait.h>
+#include <asm/msr.h>
 
 #define INTEL_IDLE_VERSION "0.4"
 #define PREFIX "intel_idle: "
@@ -84,6 +85,12 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state);
 
 static struct cpuidle_state *cpuidle_state_table;
 
+/*
+ * Hardware C-state auto-demotion may not always be optimal.
+ * Indicate which enable bits to clear here.
+ */
+static unsigned long long auto_demotion_disable_flags;
+
 /*
  * Set this flag for states where the HW flushes the TLB for us
  * and so we don't need cross-calls to keep it consistent.
@@ -281,6 +288,15 @@ static struct notifier_block setup_broadcast_notifier = {
        .notifier_call = setup_broadcast_cpuhp_notify,
 };
 
+static void auto_demotion_disable(void *dummy)
+{
+       unsigned long long msr_bits;
+
+       rdmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits);
+       msr_bits &= ~auto_demotion_disable_flags;
+       wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits);
+}
+
 /*
  * intel_idle_probe()
  */
@@ -324,11 +340,17 @@ static int intel_idle_probe(void)
        case 0x25:      /* Westmere */
        case 0x2C:      /* Westmere */
                cpuidle_state_table = nehalem_cstates;
+               auto_demotion_disable_flags =
+                       (NHM_C1_AUTO_DEMOTE | NHM_C3_AUTO_DEMOTE);
                break;
 
        case 0x1C:      /* 28 - Atom Processor */
+               cpuidle_state_table = atom_cstates;
+               break;
+
        case 0x26:      /* 38 - Lincroft Atom Processor */
                cpuidle_state_table = atom_cstates;
+               auto_demotion_disable_flags = ATM_LNC_C6_AUTO_DEMOTE;
                break;
 
        case 0x2A:      /* SNB */
@@ -436,6 +458,8 @@ static int intel_idle_cpuidle_devices_init(void)
                        return -EIO;
                }
        }
+       if (auto_demotion_disable_flags)
+               smp_call_function(auto_demotion_disable, NULL, 1);
 
        return 0;
 }
index e38be1b..fbbfa24 100644 (file)
@@ -1079,7 +1079,7 @@ static void ib_sa_remove_one(struct ib_device *device)
 
        ib_unregister_event_handler(&sa_dev->event_handler);
 
-       flush_scheduled_work();
+       flush_workqueue(ib_wq);
 
        for (i = 0; i <= sa_dev->end_port - sa_dev->start_port; ++i) {
                if (rdma_port_get_link_layer(device, i + 1) == IB_LINK_LAYER_INFINIBAND) {
index ca12acf..ec1e9da 100644 (file)
@@ -636,6 +636,16 @@ static void ucma_copy_iboe_route(struct rdma_ucm_query_route_resp *resp,
        }
 }
 
+static void ucma_copy_iw_route(struct rdma_ucm_query_route_resp *resp,
+                              struct rdma_route *route)
+{
+       struct rdma_dev_addr *dev_addr;
+
+       dev_addr = &route->addr.dev_addr;
+       rdma_addr_get_dgid(dev_addr, (union ib_gid *) &resp->ib_route[0].dgid);
+       rdma_addr_get_sgid(dev_addr, (union ib_gid *) &resp->ib_route[0].sgid);
+}
+
 static ssize_t ucma_query_route(struct ucma_file *file,
                                const char __user *inbuf,
                                int in_len, int out_len)
@@ -670,8 +680,10 @@ static ssize_t ucma_query_route(struct ucma_file *file,
 
        resp.node_guid = (__force __u64) ctx->cm_id->device->node_guid;
        resp.port_num = ctx->cm_id->port_num;
-       if (rdma_node_get_transport(ctx->cm_id->device->node_type) == RDMA_TRANSPORT_IB) {
-               switch (rdma_port_get_link_layer(ctx->cm_id->device, ctx->cm_id->port_num)) {
+       switch (rdma_node_get_transport(ctx->cm_id->device->node_type)) {
+       case RDMA_TRANSPORT_IB:
+               switch (rdma_port_get_link_layer(ctx->cm_id->device,
+                       ctx->cm_id->port_num)) {
                case IB_LINK_LAYER_INFINIBAND:
                        ucma_copy_ib_route(&resp, &ctx->cm_id->route);
                        break;
@@ -681,6 +693,12 @@ static ssize_t ucma_query_route(struct ucma_file *file,
                default:
                        break;
                }
+               break;
+       case RDMA_TRANSPORT_IWARP:
+               ucma_copy_iw_route(&resp, &ctx->cm_id->route);
+               break;
+       default:
+               break;
        }
 
 out:
index 9ce7819..2ec716f 100644 (file)
@@ -107,7 +107,7 @@ struct c2_vq_req *vq_req_alloc(struct c2_dev *c2dev)
        r = kmalloc(sizeof(struct c2_vq_req), GFP_KERNEL);
        if (r) {
                init_waitqueue_head(&r->wait_object);
-               r->reply_msg = (u64) NULL;
+               r->reply_msg = 0;
                r->event = 0;
                r->cm_id = NULL;
                r->qp = NULL;
@@ -123,7 +123,7 @@ struct c2_vq_req *vq_req_alloc(struct c2_dev *c2dev)
  */
 void vq_req_free(struct c2_dev *c2dev, struct c2_vq_req *r)
 {
-       r->reply_msg = (u64) NULL;
+       r->reply_msg = 0;
        if (atomic_dec_and_test(&r->refcnt)) {
                kfree(r);
        }
@@ -151,7 +151,7 @@ void vq_req_get(struct c2_dev *c2dev, struct c2_vq_req *r)
 void vq_req_put(struct c2_dev *c2dev, struct c2_vq_req *r)
 {
        if (atomic_dec_and_test(&r->refcnt)) {
-               if (r->reply_msg != (u64) NULL)
+               if (r->reply_msg != 0)
                        vq_repbuf_free(c2dev,
                                       (void *) (unsigned long) r->reply_msg);
                kfree(r);
index 0dc62b1..8b00e6c 100644 (file)
@@ -380,7 +380,7 @@ static void send_flowc(struct c4iw_ep *ep, struct sk_buff *skb)
                                          16)) | FW_WR_FLOWID(ep->hwtid));
 
        flowc->mnemval[0].mnemonic = FW_FLOWC_MNEM_PFNVFN;
-       flowc->mnemval[0].val = cpu_to_be32(0);
+       flowc->mnemval[0].val = cpu_to_be32(PCI_FUNC(ep->com.dev->rdev.lldi.pdev->devfn) << 8);
        flowc->mnemval[1].mnemonic = FW_FLOWC_MNEM_CH;
        flowc->mnemval[1].val = cpu_to_be32(ep->tx_chan);
        flowc->mnemval[2].mnemonic = FW_FLOWC_MNEM_PORT;
index 2080090..4f0be25 100644 (file)
@@ -220,7 +220,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
                V_FW_RI_RES_WR_DCAEN(0) |
                V_FW_RI_RES_WR_DCACPU(0) |
                V_FW_RI_RES_WR_FBMIN(2) |
-               V_FW_RI_RES_WR_FBMAX(3) |
+               V_FW_RI_RES_WR_FBMAX(2) |
                V_FW_RI_RES_WR_CIDXFTHRESHO(0) |
                V_FW_RI_RES_WR_CIDXFTHRESH(0) |
                V_FW_RI_RES_WR_EQSIZE(eqsize));
@@ -243,7 +243,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
                V_FW_RI_RES_WR_DCAEN(0) |
                V_FW_RI_RES_WR_DCACPU(0) |
                V_FW_RI_RES_WR_FBMIN(2) |
-               V_FW_RI_RES_WR_FBMAX(3) |
+               V_FW_RI_RES_WR_FBMAX(2) |
                V_FW_RI_RES_WR_CIDXFTHRESHO(0) |
                V_FW_RI_RES_WR_CIDXFTHRESH(0) |
                V_FW_RI_RES_WR_EQSIZE(eqsize));
index 8b606fd..08c1948 100644 (file)
@@ -2610,9 +2610,11 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
                                        netif_carrier_on(nesvnic->netdev);
 
                                        spin_lock(&nesvnic->port_ibevent_lock);
-                                       if (nesdev->iw_status == 0) {
-                                               nesdev->iw_status = 1;
-                                               nes_port_ibevent(nesvnic);
+                                       if (nesvnic->of_device_registered) {
+                                               if (nesdev->iw_status == 0) {
+                                                       nesdev->iw_status = 1;
+                                                       nes_port_ibevent(nesvnic);
+                                               }
                                        }
                                        spin_unlock(&nesvnic->port_ibevent_lock);
                                }
@@ -2642,9 +2644,11 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
                                        netif_carrier_off(nesvnic->netdev);
 
                                        spin_lock(&nesvnic->port_ibevent_lock);
-                                       if (nesdev->iw_status == 1) {
-                                               nesdev->iw_status = 0;
-                                               nes_port_ibevent(nesvnic);
+                                       if (nesvnic->of_device_registered) {
+                                               if (nesdev->iw_status == 1) {
+                                                       nesdev->iw_status = 0;
+                                                       nes_port_ibevent(nesvnic);
+                                               }
                                        }
                                        spin_unlock(&nesvnic->port_ibevent_lock);
                                }
@@ -2703,9 +2707,11 @@ void nes_recheck_link_status(struct work_struct *work)
                                netif_carrier_on(nesvnic->netdev);
 
                                spin_lock(&nesvnic->port_ibevent_lock);
-                               if (nesdev->iw_status == 0) {
-                                       nesdev->iw_status = 1;
-                                       nes_port_ibevent(nesvnic);
+                               if (nesvnic->of_device_registered) {
+                                       if (nesdev->iw_status == 0) {
+                                               nesdev->iw_status = 1;
+                                               nes_port_ibevent(nesvnic);
+                                       }
                                }
                                spin_unlock(&nesvnic->port_ibevent_lock);
                        }
@@ -2723,9 +2729,11 @@ void nes_recheck_link_status(struct work_struct *work)
                                netif_carrier_off(nesvnic->netdev);
 
                                spin_lock(&nesvnic->port_ibevent_lock);
-                               if (nesdev->iw_status == 1) {
-                                       nesdev->iw_status = 0;
-                                       nes_port_ibevent(nesvnic);
+                               if (nesvnic->of_device_registered) {
+                                       if (nesdev->iw_status == 1) {
+                                               nesdev->iw_status = 0;
+                                               nes_port_ibevent(nesvnic);
+                                       }
                                }
                                spin_unlock(&nesvnic->port_ibevent_lock);
                        }
index 50cceb3..b01809a 100644 (file)
@@ -623,7 +623,6 @@ struct qib_chippport_specific {
        u8 ibmalfusesnap;
        struct qib_qsfp_data qsfp_data;
        char epmsgbuf[192]; /* for port error interrupt msg buffer */
-       u8 bounced;
 };
 
 static struct {
@@ -1881,23 +1880,7 @@ static noinline void handle_7322_p_errors(struct qib_pportdata *ppd)
                    IB_PHYSPORTSTATE_DISABLED)
                        qib_set_ib_7322_lstate(ppd, 0,
                               QLOGIC_IB_IBCC_LINKINITCMD_DISABLE);
-               else {
-                       u32 lstate;
-                       /*
-                        * We need the current logical link state before
-                        * lflags are set in handle_e_ibstatuschanged.
-                        */
-                       lstate = qib_7322_iblink_state(ibcs);
-
-                       if (IS_QMH(dd) && !ppd->cpspec->bounced &&
-                           ltstate == IB_PHYSPORTSTATE_LINKUP &&
-                           (lstate >= IB_PORT_INIT &&
-                               lstate <= IB_PORT_ACTIVE)) {
-                               ppd->cpspec->bounced = 1;
-                               qib_7322_set_ib_cfg(ppd, QIB_IB_CFG_LSTATE,
-                                       IB_LINKCMD_DOWN | IB_LINKINITCMD_POLL);
-                       }
-
+               else
                        /*
                         * Since going into a recovery state causes the link
                         * state to go down and since recovery is transitory,
@@ -1911,7 +1894,6 @@ static noinline void handle_7322_p_errors(struct qib_pportdata *ppd)
                            ltstate != IB_PHYSPORTSTATE_RECOVERY_WAITRMT &&
                            ltstate != IB_PHYSPORTSTATE_RECOVERY_IDLE)
                                qib_handle_e_ibstatuschanged(ppd, ibcs);
-               }
        }
        if (*msg && iserr)
                qib_dev_porterr(dd, ppd->port, "%s error\n", msg);
@@ -2381,6 +2363,11 @@ static int qib_7322_bringup_serdes(struct qib_pportdata *ppd)
        qib_write_kreg_port(ppd, krp_rcvctrl, ppd->p_rcvctrl);
        spin_unlock_irqrestore(&dd->cspec->rcvmod_lock, flags);
 
+       /* Hold the link state machine for mezz boards */
+       if (IS_QMH(dd) || IS_QME(dd))
+               qib_set_ib_7322_lstate(ppd, 0,
+                                      QLOGIC_IB_IBCC_LINKINITCMD_DISABLE);
+
        /* Also enable IBSTATUSCHG interrupt.  */
        val = qib_read_kreg_port(ppd, krp_errmask);
        qib_write_kreg_port(ppd, krp_errmask,
@@ -5702,6 +5689,11 @@ static void set_no_qsfp_atten(struct qib_devdata *dd, int change)
                                ppd->cpspec->h1_val = h1;
                        /* now change the IBC and serdes, overriding generic */
                        init_txdds_table(ppd, 1);
+                       /* Re-enable the physical state machine on mezz boards
+                        * now that the correct settings have been set. */
+                       if (IS_QMH(dd) || IS_QME(dd))
+                               qib_set_ib_7322_lstate(ppd, 0,
+                                           QLOGIC_IB_IBCC_LINKINITCMD_SLEEP);
                        any++;
                }
                if (*nxt == '\n')
index 8245237..eca0c41 100644 (file)
@@ -1005,7 +1005,8 @@ void qib_rc_send_complete(struct qib_qp *qp, struct qib_ib_header *hdr)
         * there are still requests that haven't been acked.
         */
        if ((psn & IB_BTH_REQ_ACK) && qp->s_acked != qp->s_tail &&
-           !(qp->s_flags & (QIB_S_TIMER | QIB_S_WAIT_RNR | QIB_S_WAIT_PSN)))
+           !(qp->s_flags & (QIB_S_TIMER | QIB_S_WAIT_RNR | QIB_S_WAIT_PSN)) &&
+           (ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK))
                start_timer(qp);
 
        while (qp->s_last != qp->s_acked) {
@@ -1439,6 +1440,8 @@ static void qib_rc_rcv_resp(struct qib_ibport *ibp,
        }
 
        spin_lock_irqsave(&qp->s_lock, flags);
+       if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK))
+               goto ack_done;
 
        /* Ignore invalid responses. */
        if (qib_cmp24(psn, qp->s_next_psn) >= 0)
index 23cf8fc..5b8f59d 100644 (file)
@@ -360,7 +360,7 @@ static int gameport_queue_event(void *object, struct module *owner,
        event->owner = owner;
 
        list_add_tail(&event->node, &gameport_event_list);
-       schedule_work(&gameport_event_work);
+       queue_work(system_long_wq, &gameport_event_work);
 
 out:
        spin_unlock_irqrestore(&gameport_event_lock, flags);
index 7985114..11905b6 100644 (file)
@@ -75,7 +75,6 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz)
  * dev->event_lock held and interrupts disabled.
  */
 static void input_pass_event(struct input_dev *dev,
-                            struct input_handler *src_handler,
                             unsigned int type, unsigned int code, int value)
 {
        struct input_handler *handler;
@@ -94,15 +93,6 @@ static void input_pass_event(struct input_dev *dev,
                                continue;
 
                        handler = handle->handler;
-
-                       /*
-                        * If this is the handler that injected this
-                        * particular event we want to skip it to avoid
-                        * filters firing again and again.
-                        */
-                       if (handler == src_handler)
-                               continue;
-
                        if (!handler->filter) {
                                if (filtered)
                                        break;
@@ -132,7 +122,7 @@ static void input_repeat_key(unsigned long data)
        if (test_bit(dev->repeat_key, dev->key) &&
            is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
 
-               input_pass_event(dev, NULL, EV_KEY, dev->repeat_key, 2);
+               input_pass_event(dev, EV_KEY, dev->repeat_key, 2);
 
                if (dev->sync) {
                        /*
@@ -141,7 +131,7 @@ static void input_repeat_key(unsigned long data)
                         * Otherwise assume that the driver will send
                         * SYN_REPORT once it's done.
                         */
-                       input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1);
+                       input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
                }
 
                if (dev->rep[REP_PERIOD])
@@ -174,7 +164,6 @@ static void input_stop_autorepeat(struct input_dev *dev)
 #define INPUT_PASS_TO_ALL      (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
 
 static int input_handle_abs_event(struct input_dev *dev,
-                                 struct input_handler *src_handler,
                                  unsigned int code, int *pval)
 {
        bool is_mt_event;
@@ -218,15 +207,13 @@ static int input_handle_abs_event(struct input_dev *dev,
        /* Flush pending "slot" event */
        if (is_mt_event && dev->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
                input_abs_set_val(dev, ABS_MT_SLOT, dev->slot);
-               input_pass_event(dev, src_handler,
-                                EV_ABS, ABS_MT_SLOT, dev->slot);
+               input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot);
        }
 
        return INPUT_PASS_TO_HANDLERS;
 }
 
 static void input_handle_event(struct input_dev *dev,
-                              struct input_handler *src_handler,
                               unsigned int type, unsigned int code, int value)
 {
        int disposition = INPUT_IGNORE_EVENT;
@@ -279,8 +266,7 @@ static void input_handle_event(struct input_dev *dev,
 
        case EV_ABS:
                if (is_event_supported(code, dev->absbit, ABS_MAX))
-                       disposition = input_handle_abs_event(dev, src_handler,
-                                                            code, &value);
+                       disposition = input_handle_abs_event(dev, code, &value);
 
                break;
 
@@ -338,7 +324,7 @@ static void input_handle_event(struct input_dev *dev,
                dev->event(dev, type, code, value);
 
        if (disposition & INPUT_PASS_TO_HANDLERS)
-               input_pass_event(dev, src_handler, type, code, value);
+               input_pass_event(dev, type, code, value);
 }
 
 /**
@@ -367,7 +353,7 @@ void input_event(struct input_dev *dev,
 
                spin_lock_irqsave(&dev->event_lock, flags);
                add_input_randomness(type, code, value);
-               input_handle_event(dev, NULL, type, code, value);
+               input_handle_event(dev, type, code, value);
                spin_unlock_irqrestore(&dev->event_lock, flags);
        }
 }
@@ -397,8 +383,7 @@ void input_inject_event(struct input_handle *handle,
                rcu_read_lock();
                grab = rcu_dereference(dev->grab);
                if (!grab || grab == handle)
-                       input_handle_event(dev, handle->handler,
-                                          type, code, value);
+                       input_handle_event(dev, type, code, value);
                rcu_read_unlock();
 
                spin_unlock_irqrestore(&dev->event_lock, flags);
@@ -611,10 +596,10 @@ static void input_dev_release_keys(struct input_dev *dev)
                for (code = 0; code <= KEY_MAX; code++) {
                        if (is_event_supported(code, dev->keybit, KEY_MAX) &&
                            __test_and_clear_bit(code, dev->key)) {
-                               input_pass_event(dev, NULL, EV_KEY, code, 0);
+                               input_pass_event(dev, EV_KEY, code, 0);
                        }
                }
-               input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1);
+               input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
        }
 }
 
@@ -889,9 +874,9 @@ int input_set_keycode(struct input_dev *dev,
            !is_event_supported(old_keycode, dev->keybit, KEY_MAX) &&
            __test_and_clear_bit(old_keycode, dev->key)) {
 
-               input_pass_event(dev, NULL, EV_KEY, old_keycode, 0);
+               input_pass_event(dev, EV_KEY, old_keycode, 0);
                if (dev->sync)
-                       input_pass_event(dev, NULL, EV_SYN, SYN_REPORT, 1);
+                       input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
        }
 
  out:
index 4175073..c7a9202 100644 (file)
@@ -343,6 +343,16 @@ config KEYBOARD_NOMADIK
          To compile this driver as a module, choose M here: the
          module will be called nmk-ske-keypad.
 
+config KEYBOARD_TEGRA
+       tristate "NVIDIA Tegra internal matrix keyboard controller support"
+       depends on ARCH_TEGRA
+       help
+         Say Y here if you want to use a matrix keyboard connected directly
+         to the internal keyboard controller on Tegra SoCs.
+
+         To compile this driver as a module, choose M here: the
+         module will be called tegra-kbc.
+
 config KEYBOARD_OPENCORES
        tristate "OpenCores Keyboard Controller"
        help
index 4e5571b..468c627 100644 (file)
@@ -42,6 +42,7 @@ obj-$(CONFIG_KEYBOARD_STMPE)          += stmpe-keypad.o
 obj-$(CONFIG_KEYBOARD_STOWAWAY)                += stowaway.o
 obj-$(CONFIG_KEYBOARD_SUNKBD)          += sunkbd.o
 obj-$(CONFIG_KEYBOARD_TC3589X)         += tc3589x-keypad.o
+obj-$(CONFIG_KEYBOARD_TEGRA)           += tegra-kbc.o
 obj-$(CONFIG_KEYBOARD_TNETV107X)       += tnetv107x-keypad.o
 obj-$(CONFIG_KEYBOARD_TWL4030)         += twl4030_keypad.o
 obj-$(CONFIG_KEYBOARD_XTKBD)           += xtkbd.o
index 6069abe..eb30063 100644 (file)
@@ -322,7 +322,7 @@ static void gpio_keys_report_event(struct gpio_button_data *bdata)
        struct gpio_keys_button *button = bdata->button;
        struct input_dev *input = bdata->input;
        unsigned int type = button->type ?: EV_KEY;
-       int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low;
+       int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low;
 
        input_event(input, type, button->code, !!state);
        input_sync(input);
@@ -410,8 +410,8 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
        if (!button->can_disable)
                irqflags |= IRQF_SHARED;
 
-       error = request_irq(irq, gpio_keys_isr, irqflags, desc, bdata);
-       if (error) {
+       error = request_any_context_irq(irq, gpio_keys_isr, irqflags, desc, bdata);
+       if (error < 0) {
                dev_err(dev, "Unable to claim irq %d; error %d\n",
                        irq, error);
                goto fail3;
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
new file mode 100644 (file)
index 0000000..99ce903
--- /dev/null
@@ -0,0 +1,783 @@
+/*
+ * Keyboard class input driver for the NVIDIA Tegra SoC internal matrix
+ * keyboard controller
+ *
+ * Copyright (c) 2009-2011, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <mach/clk.h>
+#include <mach/kbc.h>
+
+#define KBC_MAX_DEBOUNCE_CNT   0x3ffu
+
+/* KBC row scan time and delay for beginning the row scan. */
+#define KBC_ROW_SCAN_TIME      16
+#define KBC_ROW_SCAN_DLY       5
+
+/* KBC uses a 32KHz clock so a cycle = 1/32Khz */
+#define KBC_CYCLE_USEC 32
+
+/* KBC Registers */
+
+/* KBC Control Register */
+#define KBC_CONTROL_0  0x0
+#define KBC_FIFO_TH_CNT_SHIFT(cnt)     (cnt << 14)
+#define KBC_DEBOUNCE_CNT_SHIFT(cnt)    (cnt << 4)
+#define KBC_CONTROL_FIFO_CNT_INT_EN    (1 << 3)
+#define KBC_CONTROL_KBC_EN             (1 << 0)
+
+/* KBC Interrupt Register */
+#define KBC_INT_0      0x4
+#define KBC_INT_FIFO_CNT_INT_STATUS    (1 << 2)
+
+#define KBC_ROW_CFG0_0 0x8
+#define KBC_COL_CFG0_0 0x18
+#define KBC_INIT_DLY_0 0x28
+#define KBC_RPT_DLY_0  0x2c
+#define KBC_KP_ENT0_0  0x30
+#define KBC_KP_ENT1_0  0x34
+#define KBC_ROW0_MASK_0        0x38
+
+#define KBC_ROW_SHIFT  3
+
+struct tegra_kbc {
+       void __iomem *mmio;
+       struct input_dev *idev;
+       unsigned int irq;
+       unsigned int wake_enable_rows;
+       unsigned int wake_enable_cols;
+       spinlock_t lock;
+       unsigned int repoll_dly;
+       unsigned long cp_dly_jiffies;
+       bool use_fn_map;
+       const struct tegra_kbc_platform_data *pdata;
+       unsigned short keycode[KBC_MAX_KEY * 2];
+       unsigned short current_keys[KBC_MAX_KPENT];
+       unsigned int num_pressed_keys;
+       struct timer_list timer;
+       struct clk *clk;
+};
+
+static const u32 tegra_kbc_default_keymap[] = {
+       KEY(0, 2, KEY_W),
+       KEY(0, 3, KEY_S),
+       KEY(0, 4, KEY_A),
+       KEY(0, 5, KEY_Z),
+       KEY(0, 7, KEY_FN),
+
+       KEY(1, 7, KEY_LEFTMETA),
+
+       KEY(2, 6, KEY_RIGHTALT),
+       KEY(2, 7, KEY_LEFTALT),
+
+       KEY(3, 0, KEY_5),
+       KEY(3, 1, KEY_4),
+       KEY(3, 2, KEY_R),
+       KEY(3, 3, KEY_E),
+       KEY(3, 4, KEY_F),
+       KEY(3, 5, KEY_D),
+       KEY(3, 6, KEY_X),
+
+       KEY(4, 0, KEY_7),
+       KEY(4, 1, KEY_6),
+       KEY(4, 2, KEY_T),
+       KEY(4, 3, KEY_H),
+       KEY(4, 4, KEY_G),
+       KEY(4, 5, KEY_V),
+       KEY(4, 6, KEY_C),
+       KEY(4, 7, KEY_SPACE),
+
+       KEY(5, 0, KEY_9),
+       KEY(5, 1, KEY_8),
+       KEY(5, 2, KEY_U),
+       KEY(5, 3, KEY_Y),
+       KEY(5, 4, KEY_J),
+       KEY(5, 5, KEY_N),
+       KEY(5, 6, KEY_B),
+       KEY(5, 7, KEY_BACKSLASH),
+
+       KEY(6, 0, KEY_MINUS),
+       KEY(6, 1, KEY_0),
+       KEY(6, 2, KEY_O),
+       KEY(6, 3, KEY_I),
+       KEY(6, 4, KEY_L),
+       KEY(6, 5, KEY_K),
+       KEY(6, 6, KEY_COMMA),
+       KEY(6, 7, KEY_M),
+
+       KEY(7, 1, KEY_EQUAL),
+       KEY(7, 2, KEY_RIGHTBRACE),
+       KEY(7, 3, KEY_ENTER),
+       KEY(7, 7, KEY_MENU),
+
+       KEY(8, 4, KEY_RIGHTSHIFT),
+       KEY(8, 5, KEY_LEFTSHIFT),
+
+       KEY(9, 5, KEY_RIGHTCTRL),
+       KEY(9, 7, KEY_LEFTCTRL),
+
+       KEY(11, 0, KEY_LEFTBRACE),
+       KEY(11, 1, KEY_P),
+       KEY(11, 2, KEY_APOSTROPHE),
+       KEY(11, 3, KEY_SEMICOLON),
+       KEY(11, 4, KEY_SLASH),
+       KEY(11, 5, KEY_DOT),
+
+       KEY(12, 0, KEY_F10),
+       KEY(12, 1, KEY_F9),
+       KEY(12, 2, KEY_BACKSPACE),
+       KEY(12, 3, KEY_3),
+       KEY(12, 4, KEY_2),
+       KEY(12, 5, KEY_UP),
+       KEY(12, 6, KEY_PRINT),
+       KEY(12, 7, KEY_PAUSE),
+
+       KEY(13, 0, KEY_INSERT),
+       KEY(13, 1, KEY_DELETE),
+       KEY(13, 3, KEY_PAGEUP),
+       KEY(13, 4, KEY_PAGEDOWN),
+       KEY(13, 5, KEY_RIGHT),
+       KEY(13, 6, KEY_DOWN),
+       KEY(13, 7, KEY_LEFT),
+
+       KEY(14, 0, KEY_F11),
+       KEY(14, 1, KEY_F12),
+       KEY(14, 2, KEY_F8),
+       KEY(14, 3, KEY_Q),
+       KEY(14, 4, KEY_F4),
+       KEY(14, 5, KEY_F3),
+       KEY(14, 6, KEY_1),
+       KEY(14, 7, KEY_F7),
+
+       KEY(15, 0, KEY_ESC),
+       KEY(15, 1, KEY_GRAVE),
+       KEY(15, 2, KEY_F5),
+       KEY(15, 3, KEY_TAB),
+       KEY(15, 4, KEY_F1),
+       KEY(15, 5, KEY_F2),
+       KEY(15, 6, KEY_CAPSLOCK),
+       KEY(15, 7, KEY_F6),
+
+       /* Software Handled Function Keys */
+       KEY(20, 0, KEY_KP7),
+
+       KEY(21, 0, KEY_KP9),
+       KEY(21, 1, KEY_KP8),
+       KEY(21, 2, KEY_KP4),
+       KEY(21, 4, KEY_KP1),
+
+       KEY(22, 1, KEY_KPSLASH),
+       KEY(22, 2, KEY_KP6),
+       KEY(22, 3, KEY_KP5),
+       KEY(22, 4, KEY_KP3),
+       KEY(22, 5, KEY_KP2),
+       KEY(22, 7, KEY_KP0),
+
+       KEY(27, 1, KEY_KPASTERISK),
+       KEY(27, 3, KEY_KPMINUS),
+       KEY(27, 4, KEY_KPPLUS),
+       KEY(27, 5, KEY_KPDOT),
+
+       KEY(28, 5, KEY_VOLUMEUP),
+
+       KEY(29, 3, KEY_HOME),
+       KEY(29, 4, KEY_END),
+       KEY(29, 5, KEY_BRIGHTNESSDOWN),
+       KEY(29, 6, KEY_VOLUMEDOWN),
+       KEY(29, 7, KEY_BRIGHTNESSUP),
+
+       KEY(30, 0, KEY_NUMLOCK),
+       KEY(30, 1, KEY_SCROLLLOCK),
+       KEY(30, 2, KEY_MUTE),
+
+       KEY(31, 4, KEY_HELP),
+};
+
+static const struct matrix_keymap_data tegra_kbc_default_keymap_data = {
+       .keymap         = tegra_kbc_default_keymap,
+       .keymap_size    = ARRAY_SIZE(tegra_kbc_default_keymap),
+};
+
+static void tegra_kbc_report_released_keys(struct input_dev *input,
+                                          unsigned short old_keycodes[],
+                                          unsigned int old_num_keys,
+                                          unsigned short new_keycodes[],
+                                          unsigned int new_num_keys)
+{
+       unsigned int i, j;
+
+       for (i = 0; i < old_num_keys; i++) {
+               for (j = 0; j < new_num_keys; j++)
+                       if (old_keycodes[i] == new_keycodes[j])
+                               break;
+
+               if (j == new_num_keys)
+                       input_report_key(input, old_keycodes[i], 0);
+       }
+}
+
+static void tegra_kbc_report_pressed_keys(struct input_dev *input,
+                                         unsigned char scancodes[],
+                                         unsigned short keycodes[],
+                                         unsigned int num_pressed_keys)
+{
+       unsigned int i;
+
+       for (i = 0; i < num_pressed_keys; i++) {
+               input_event(input, EV_MSC, MSC_SCAN, scancodes[i]);
+               input_report_key(input, keycodes[i], 1);
+       }
+}
+
+static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
+{
+       unsigned char scancodes[KBC_MAX_KPENT];
+       unsigned short keycodes[KBC_MAX_KPENT];
+       u32 val = 0;
+       unsigned int i;
+       unsigned int num_down = 0;
+       unsigned long flags;
+       bool fn_keypress = false;
+
+       spin_lock_irqsave(&kbc->lock, flags);
+       for (i = 0; i < KBC_MAX_KPENT; i++) {
+               if ((i % 4) == 0)
+                       val = readl(kbc->mmio + KBC_KP_ENT0_0 + i);
+
+               if (val & 0x80) {
+                       unsigned int col = val & 0x07;
+                       unsigned int row = (val >> 3) & 0x0f;
+                       unsigned char scancode =
+                               MATRIX_SCAN_CODE(row, col, KBC_ROW_SHIFT);
+
+                       scancodes[num_down] = scancode;
+                       keycodes[num_down] = kbc->keycode[scancode];
+                       /* If driver uses Fn map, do not report the Fn key. */
+                       if ((keycodes[num_down] == KEY_FN) && kbc->use_fn_map)
+                               fn_keypress = true;
+                       else
+                               num_down++;
+               }
+
+               val >>= 8;
+       }
+
+       /*
+        * If the platform uses Fn keymaps, translate keys on a Fn keypress.
+        * Function keycodes are KBC_MAX_KEY apart from the plain keycodes.
+        */
+       if (fn_keypress) {
+               for (i = 0; i < num_down; i++) {
+                       scancodes[i] += KBC_MAX_KEY;
+                       keycodes[i] = kbc->keycode[scancodes[i]];
+               }
+       }
+
+       spin_unlock_irqrestore(&kbc->lock, flags);
+
+       tegra_kbc_report_released_keys(kbc->idev,
+                                      kbc->current_keys, kbc->num_pressed_keys,
+                                      keycodes, num_down);
+       tegra_kbc_report_pressed_keys(kbc->idev, scancodes, keycodes, num_down);
+       input_sync(kbc->idev);
+
+       memcpy(kbc->current_keys, keycodes, sizeof(kbc->current_keys));
+       kbc->num_pressed_keys = num_down;
+}
+
+static void tegra_kbc_keypress_timer(unsigned long data)
+{
+       struct tegra_kbc *kbc = (struct tegra_kbc *)data;
+       unsigned long flags;
+       u32 val;
+       unsigned int i;
+
+       val = (readl(kbc->mmio + KBC_INT_0) >> 4) & 0xf;
+       if (val) {
+               unsigned long dly;
+
+               tegra_kbc_report_keys(kbc);
+
+               /*
+                * If more than one keys are pressed we need not wait
+                * for the repoll delay.
+                */
+               dly = (val == 1) ? kbc->repoll_dly : 1;
+               mod_timer(&kbc->timer, jiffies + msecs_to_jiffies(dly));
+       } else {
+               /* Release any pressed keys and exit the polling loop */
+               for (i = 0; i < kbc->num_pressed_keys; i++)
+                       input_report_key(kbc->idev, kbc->current_keys[i], 0);
+               input_sync(kbc->idev);
+
+               kbc->num_pressed_keys = 0;
+
+               /* All keys are released so enable the keypress interrupt */
+               spin_lock_irqsave(&kbc->lock, flags);
+               val = readl(kbc->mmio + KBC_CONTROL_0);
+               val |= KBC_CONTROL_FIFO_CNT_INT_EN;
+               writel(val, kbc->mmio + KBC_CONTROL_0);
+               spin_unlock_irqrestore(&kbc->lock, flags);
+       }
+}
+
+static irqreturn_t tegra_kbc_isr(int irq, void *args)
+{
+       struct tegra_kbc *kbc = args;
+       u32 val, ctl;
+
+       /*
+        * Until all keys are released, defer further processing to
+        * the polling loop in tegra_kbc_keypress_timer
+        */
+       ctl = readl(kbc->mmio + KBC_CONTROL_0);
+       ctl &= ~KBC_CONTROL_FIFO_CNT_INT_EN;
+       writel(ctl, kbc->mmio + KBC_CONTROL_0);
+
+       /*
+        * Quickly bail out & reenable interrupts if the fifo threshold
+        * count interrupt wasn't the interrupt source
+        */
+       val = readl(kbc->mmio + KBC_INT_0);
+       writel(val, kbc->mmio + KBC_INT_0);
+
+       if (val & KBC_INT_FIFO_CNT_INT_STATUS) {
+               /*
+                * Schedule timer to run when hardware is in continuous
+                * polling mode.
+                */
+               mod_timer(&kbc->timer, jiffies + kbc->cp_dly_jiffies);
+       } else {
+               ctl |= KBC_CONTROL_FIFO_CNT_INT_EN;
+               writel(ctl, kbc->mmio + KBC_CONTROL_0);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void tegra_kbc_setup_wakekeys(struct tegra_kbc *kbc, bool filter)
+{
+       const struct tegra_kbc_platform_data *pdata = kbc->pdata;
+       int i;
+       unsigned int rst_val;
+
+       BUG_ON(pdata->wake_cnt > KBC_MAX_KEY);
+       rst_val = (filter && pdata->wake_cnt) ? ~0 : 0;
+
+       for (i = 0; i < KBC_MAX_ROW; i++)
+               writel(rst_val, kbc->mmio + KBC_ROW0_MASK_0 + i * 4);
+
+       if (filter) {
+               for (i = 0; i < pdata->wake_cnt; i++) {
+                       u32 val, addr;
+                       addr = pdata->wake_cfg[i].row * 4 + KBC_ROW0_MASK_0;
+                       val = readl(kbc->mmio + addr);
+                       val &= ~(1 << pdata->wake_cfg[i].col);
+                       writel(val, kbc->mmio + addr);
+               }
+       }
+}
+
+static void tegra_kbc_config_pins(struct tegra_kbc *kbc)
+{
+       const struct tegra_kbc_platform_data *pdata = kbc->pdata;
+       int i;
+
+       for (i = 0; i < KBC_MAX_GPIO; i++) {
+               u32 r_shft = 5 * (i % 6);
+               u32 c_shft = 4 * (i % 8);
+               u32 r_mask = 0x1f << r_shft;
+               u32 c_mask = 0x0f << c_shft;
+               u32 r_offs = (i / 6) * 4 + KBC_ROW_CFG0_0;
+               u32 c_offs = (i / 8) * 4 + KBC_COL_CFG0_0;
+               u32 row_cfg = readl(kbc->mmio + r_offs);
+               u32 col_cfg = readl(kbc->mmio + c_offs);
+
+               row_cfg &= ~r_mask;
+               col_cfg &= ~c_mask;
+
+               if (pdata->pin_cfg[i].is_row)
+                       row_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << r_shft;
+               else
+                       col_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << c_shft;
+
+               writel(row_cfg, kbc->mmio + r_offs);
+               writel(col_cfg, kbc->mmio + c_offs);
+       }
+}
+
+static int tegra_kbc_start(struct tegra_kbc *kbc)
+{
+       const struct tegra_kbc_platform_data *pdata = kbc->pdata;
+       unsigned long flags;
+       unsigned int debounce_cnt;
+       u32 val = 0;
+
+       clk_enable(kbc->clk);
+
+       /* Reset the KBC controller to clear all previous status.*/
+       tegra_periph_reset_assert(kbc->clk);
+       udelay(100);
+       tegra_periph_reset_deassert(kbc->clk);
+       udelay(100);
+
+       tegra_kbc_config_pins(kbc);
+       tegra_kbc_setup_wakekeys(kbc, false);
+
+       writel(pdata->repeat_cnt, kbc->mmio + KBC_RPT_DLY_0);
+
+       /* Keyboard debounce count is maximum of 12 bits. */
+       debounce_cnt = min(pdata->debounce_cnt, KBC_MAX_DEBOUNCE_CNT);
+       val = KBC_DEBOUNCE_CNT_SHIFT(debounce_cnt);
+       val |= KBC_FIFO_TH_CNT_SHIFT(1); /* set fifo interrupt threshold to 1 */
+       val |= KBC_CONTROL_FIFO_CNT_INT_EN;  /* interrupt on FIFO threshold */
+       val |= KBC_CONTROL_KBC_EN;     /* enable */
+       writel(val, kbc->mmio + KBC_CONTROL_0);
+
+       /*
+        * Compute the delay(ns) from interrupt mode to continuous polling
+        * mode so the timer routine is scheduled appropriately.
+        */
+       val = readl(kbc->mmio + KBC_INIT_DLY_0);
+       kbc->cp_dly_jiffies = usecs_to_jiffies((val & 0xfffff) * 32);
+
+       kbc->num_pressed_keys = 0;
+
+       /*
+        * Atomically clear out any remaining entries in the key FIFO
+        * and enable keyboard interrupts.
+        */
+       spin_lock_irqsave(&kbc->lock, flags);
+       while (1) {
+               val = readl(kbc->mmio + KBC_INT_0);
+               val >>= 4;
+               if (!val)
+                       break;
+
+               val = readl(kbc->mmio + KBC_KP_ENT0_0);
+               val = readl(kbc->mmio + KBC_KP_ENT1_0);
+       }
+       writel(0x7, kbc->mmio + KBC_INT_0);
+       spin_unlock_irqrestore(&kbc->lock, flags);
+
+       enable_irq(kbc->irq);
+
+       return 0;
+}
+
+static void tegra_kbc_stop(struct tegra_kbc *kbc)
+{
+       unsigned long flags;
+       u32 val;
+
+       spin_lock_irqsave(&kbc->lock, flags);
+       val = readl(kbc->mmio + KBC_CONTROL_0);
+       val &= ~1;
+       writel(val, kbc->mmio + KBC_CONTROL_0);
+       spin_unlock_irqrestore(&kbc->lock, flags);
+
+       disable_irq(kbc->irq);
+       del_timer_sync(&kbc->timer);
+
+       clk_disable(kbc->clk);
+}
+
+static int tegra_kbc_open(struct input_dev *dev)
+{
+       struct tegra_kbc *kbc = input_get_drvdata(dev);
+
+       return tegra_kbc_start(kbc);
+}
+
+static void tegra_kbc_close(struct input_dev *dev)
+{
+       struct tegra_kbc *kbc = input_get_drvdata(dev);
+
+       return tegra_kbc_stop(kbc);
+}
+
+static bool __devinit
+tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata,
+                       struct device *dev, unsigned int *num_rows)
+{
+       int i;
+
+       *num_rows = 0;
+
+       for (i = 0; i < KBC_MAX_GPIO; i++) {
+               const struct tegra_kbc_pin_cfg *pin_cfg = &pdata->pin_cfg[i];
+
+               if (pin_cfg->is_row) {
+                       if (pin_cfg->num >= KBC_MAX_ROW) {
+                               dev_err(dev,
+                                       "pin_cfg[%d]: invalid row number %d\n",
+                                       i, pin_cfg->num);
+                               return false;
+                       }
+                       (*num_rows)++;
+               } else {
+                       if (pin_cfg->num >= KBC_MAX_COL) {
+                               dev_err(dev,
+                                       "pin_cfg[%d]: invalid column number %d\n",
+                                       i, pin_cfg->num);
+                               return false;
+                       }
+               }
+       }
+
+       return true;
+}
+
+static int __devinit tegra_kbc_probe(struct platform_device *pdev)
+{
+       const struct tegra_kbc_platform_data *pdata = pdev->dev.platform_data;
+       const struct matrix_keymap_data *keymap_data;
+       struct tegra_kbc *kbc;
+       struct input_dev *input_dev;
+       struct resource *res;
+       int irq;
+       int err;
+       int i;
+       int num_rows = 0;
+       unsigned int debounce_cnt;
+       unsigned int scan_time_rows;
+
+       if (!pdata)
+               return -EINVAL;
+
+       if (!tegra_kbc_check_pin_cfg(pdata, &pdev->dev, &num_rows))
+               return -EINVAL;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "failed to get I/O memory\n");
+               return -ENXIO;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "failed to get keyboard IRQ\n");
+               return -ENXIO;
+       }
+
+       kbc = kzalloc(sizeof(*kbc), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!kbc || !input_dev) {
+               err = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       kbc->pdata = pdata;
+       kbc->idev = input_dev;
+       kbc->irq = irq;
+       spin_lock_init(&kbc->lock);
+       setup_timer(&kbc->timer, tegra_kbc_keypress_timer, (unsigned long)kbc);
+
+       res = request_mem_region(res->start, resource_size(res), pdev->name);
+       if (!res) {
+               dev_err(&pdev->dev, "failed to request I/O memory\n");
+               err = -EBUSY;
+               goto err_free_mem;
+       }
+
+       kbc->mmio = ioremap(res->start, resource_size(res));
+       if (!kbc->mmio) {
+               dev_err(&pdev->dev, "failed to remap I/O memory\n");
+               err = -ENXIO;
+               goto err_free_mem_region;
+       }
+
+       kbc->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(kbc->clk)) {
+               dev_err(&pdev->dev, "failed to get keyboard clock\n");
+               err = PTR_ERR(kbc->clk);
+               goto err_iounmap;
+       }
+
+       kbc->wake_enable_rows = 0;
+       kbc->wake_enable_cols = 0;
+       for (i = 0; i < pdata->wake_cnt; i++) {
+               kbc->wake_enable_rows |= (1 << pdata->wake_cfg[i].row);
+               kbc->wake_enable_cols |= (1 << pdata->wake_cfg[i].col);
+       }
+
+       /*
+        * The time delay between two consecutive reads of the FIFO is
+        * the sum of the repeat time and the time taken for scanning
+        * the rows. There is an additional delay before the row scanning
+        * starts. The repoll delay is computed in milliseconds.
+        */
+       debounce_cnt = min(pdata->debounce_cnt, KBC_MAX_DEBOUNCE_CNT);
+       scan_time_rows = (KBC_ROW_SCAN_TIME + debounce_cnt) * num_rows;
+       kbc->repoll_dly = KBC_ROW_SCAN_DLY + scan_time_rows + pdata->repeat_cnt;
+       kbc->repoll_dly = ((kbc->repoll_dly * KBC_CYCLE_USEC) + 999) / 1000;
+
+       input_dev->name = pdev->name;
+       input_dev->id.bustype = BUS_HOST;
+       input_dev->dev.parent = &pdev->dev;
+       input_dev->open = tegra_kbc_open;
+       input_dev->close = tegra_kbc_close;
+
+       input_set_drvdata(input_dev, kbc);
+
+       input_dev->evbit[0] = BIT_MASK(EV_KEY);
+       input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+
+       input_dev->keycode = kbc->keycode;
+       input_dev->keycodesize = sizeof(kbc->keycode[0]);
+       input_dev->keycodemax = KBC_MAX_KEY;
+       if (pdata->use_fn_map)
+               input_dev->keycodemax *= 2;
+
+       kbc->use_fn_map = pdata->use_fn_map;
+       keymap_data = pdata->keymap_data ?: &tegra_kbc_default_keymap_data;
+       matrix_keypad_build_keymap(keymap_data, KBC_ROW_SHIFT,
+                                  input_dev->keycode, input_dev->keybit);
+
+       err = request_irq(kbc->irq, tegra_kbc_isr, IRQF_TRIGGER_HIGH,
+                         pdev->name, kbc);
+       if (err) {
+               dev_err(&pdev->dev, "failed to request keyboard IRQ\n");
+               goto err_put_clk;
+       }
+
+       disable_irq(kbc->irq);
+
+       err = input_register_device(kbc->idev);
+       if (err) {
+               dev_err(&pdev->dev, "failed to register input device\n");
+               goto err_free_irq;
+       }
+
+       platform_set_drvdata(pdev, kbc);
+       device_init_wakeup(&pdev->dev, pdata->wakeup);
+
+       return 0;
+
+err_free_irq:
+       free_irq(kbc->irq, pdev);
+err_put_clk:
+       clk_put(kbc->clk);
+err_iounmap:
+       iounmap(kbc->mmio);
+err_free_mem_region:
+       release_mem_region(res->start, resource_size(res));
+err_free_mem:
+       input_free_device(kbc->idev);
+       kfree(kbc);
+
+       return err;
+}
+
+static int __devexit tegra_kbc_remove(struct platform_device *pdev)
+{
+       struct tegra_kbc *kbc = platform_get_drvdata(pdev);
+       struct resource *res;
+
+       free_irq(kbc->irq, pdev);
+       clk_put(kbc->clk);
+
+       input_unregister_device(kbc->idev);
+       iounmap(kbc->mmio);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, resource_size(res));
+
+       kfree(kbc);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int tegra_kbc_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct tegra_kbc *kbc = platform_get_drvdata(pdev);
+
+       if (device_may_wakeup(&pdev->dev)) {
+               tegra_kbc_setup_wakekeys(kbc, true);
+               enable_irq_wake(kbc->irq);
+               /* Forcefully clear the interrupt status */
+               writel(0x7, kbc->mmio + KBC_INT_0);
+               msleep(30);
+       } else {
+               mutex_lock(&kbc->idev->mutex);
+               if (kbc->idev->users)
+                       tegra_kbc_stop(kbc);
+               mutex_unlock(&kbc->idev->mutex);
+       }
+
+       return 0;
+}
+
+static int tegra_kbc_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct tegra_kbc *kbc = platform_get_drvdata(pdev);
+       int err = 0;
+
+       if (device_may_wakeup(&pdev->dev)) {
+               disable_irq_wake(kbc->irq);
+               tegra_kbc_setup_wakekeys(kbc, false);
+       } else {
+               mutex_lock(&kbc->idev->mutex);
+               if (kbc->idev->users)
+                       err = tegra_kbc_start(kbc);
+               mutex_unlock(&kbc->idev->mutex);
+       }
+
+       return err;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(tegra_kbc_pm_ops, tegra_kbc_suspend, tegra_kbc_resume);
+
+static struct platform_driver tegra_kbc_driver = {
+       .probe          = tegra_kbc_probe,
+       .remove         = __devexit_p(tegra_kbc_remove),
+       .driver = {
+               .name   = "tegra-kbc",
+               .owner  = THIS_MODULE,
+               .pm     = &tegra_kbc_pm_ops,
+       },
+};
+
+static void __exit tegra_kbc_exit(void)
+{
+       platform_driver_unregister(&tegra_kbc_driver);
+}
+module_exit(tegra_kbc_exit);
+
+static int __init tegra_kbc_init(void)
+{
+       return platform_driver_register(&tegra_kbc_driver);
+}
+module_init(tegra_kbc_init);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Rakesh Iyer <riyer@nvidia.com>");
+MODULE_DESCRIPTION("Tegra matrix keyboard controller driver");
+MODULE_ALIAS("platform:tegra-kbc");
index b4a81eb..c8f097a 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/err.h>
 #include <linux/errno.h>
 #include <linux/input.h>
 #include <linux/platform_device.h>
@@ -219,9 +220,9 @@ static int __devinit keypad_probe(struct platform_device *pdev)
        }
 
        kp->clk = clk_get(dev, NULL);
-       if (!kp->clk) {
+       if (IS_ERR(kp->clk)) {
                dev_err(dev, "cannot claim device clock\n");
-               error = -EINVAL;
+               error = PTR_ERR(kp->clk);
                goto error_clk;
        }
 
index 9dfd6e5..1f38302 100644 (file)
@@ -69,11 +69,7 @@ static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned
        }
 
        if (value > 20 && value < 32767)
-#ifndef FREQ
-               count = (ixp4xx_get_board_tick_rate() / (value * 4)) - 1;
-#else
-               count = (FREQ / (value * 4)) - 1;
-#endif
+               count = (IXP4XX_TIMER_FREQ / (value * 4)) - 1;
 
        ixp4xx_spkr_control(pin, count);
 
index 1f8e010..7e64d01 100644 (file)
@@ -176,7 +176,7 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
 
        /* request the IRQs */
        err = request_irq(encoder->irq_a, &rotary_encoder_irq,
-                         IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE,
+                         IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
                          DRV_NAME, encoder);
        if (err) {
                dev_err(&pdev->dev, "unable to request IRQ %d\n",
@@ -185,7 +185,7 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
        }
 
        err = request_irq(encoder->irq_b, &rotary_encoder_irq,
-                         IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_LOWEDGE,
+                         IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
                          DRV_NAME, encoder);
        if (err) {
                dev_err(&pdev->dev, "unable to request IRQ %d\n",
index da392c2..aa186cf 100644 (file)
@@ -755,23 +755,26 @@ static int synaptics_reconnect(struct psmouse *psmouse)
 {
        struct synaptics_data *priv = psmouse->private;
        struct synaptics_data old_priv = *priv;
+       int retry = 0;
+       int error;
 
-       psmouse_reset(psmouse);
+       do {
+               psmouse_reset(psmouse);
+               error = synaptics_detect(psmouse, 0);
+       } while (error && ++retry < 3);
 
-       if (synaptics_detect(psmouse, 0))
+       if (error)
                return -1;
 
+       if (retry > 1)
+               printk(KERN_DEBUG "Synaptics reconnected after %d tries\n",
+                       retry);
+
        if (synaptics_query_hardware(psmouse)) {
                printk(KERN_ERR "Unable to query Synaptics hardware.\n");
                return -1;
        }
 
-       if (old_priv.identity != priv->identity ||
-           old_priv.model_id != priv->model_id ||
-           old_priv.capabilities != priv->capabilities ||
-           old_priv.ext_cap != priv->ext_cap)
-               return -1;
-
        if (synaptics_set_absolute_mode(psmouse)) {
                printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
                return -1;
@@ -782,6 +785,19 @@ static int synaptics_reconnect(struct psmouse *psmouse)
                return -1;
        }
 
+       if (old_priv.identity != priv->identity ||
+           old_priv.model_id != priv->model_id ||
+           old_priv.capabilities != priv->capabilities ||
+           old_priv.ext_cap != priv->ext_cap) {
+               printk(KERN_ERR "Synaptics hardware appears to be different: "
+                       "id(%ld-%ld), model(%ld-%ld), caps(%lx-%lx), ext(%lx-%lx).\n",
+                       old_priv.identity, priv->identity,
+                       old_priv.model_id, priv->model_id,
+                       old_priv.capabilities, priv->capabilities,
+                       old_priv.ext_cap, priv->ext_cap);
+               return -1;
+       }
+
        return 0;
 }
 
index 25e5d04..7453938 100644 (file)
 #define SYN_EXT_CAP_REQUESTS(c)                (((c) & 0x700000) >> 20)
 #define SYN_CAP_MULTI_BUTTON_NO(ec)    (((ec) & 0x00f000) >> 12)
 #define SYN_CAP_PRODUCT_ID(ec)         (((ec) & 0xff0000) >> 16)
+
+/*
+ * The following describes response for the 0x0c query.
+ *
+ * byte        mask    name                    meaning
+ * ----        ----    -------                 ------------
+ * 1   0x01    adjustable threshold    capacitive button sensitivity
+ *                                     can be adjusted
+ * 1   0x02    report max              query 0x0d gives max coord reported
+ * 1   0x04    clearpad                sensor is ClearPad product
+ * 1   0x08    advanced gesture        not particularly meaningful
+ * 1   0x10    clickpad bit 0          1-button ClickPad
+ * 1   0x60    multifinger mode        identifies firmware finger counting
+ *                                     (not reporting!) algorithm.
+ *                                     Not particularly meaningful
+ * 1   0x80    covered pad             W clipped to 14, 15 == pad mostly covered
+ * 2   0x01    clickpad bit 1          2-button ClickPad
+ * 2   0x02    deluxe LED controls     touchpad support LED commands
+ *                                     ala multimedia control bar
+ * 2   0x04    reduced filtering       firmware does less filtering on
+ *                                     position data, driver should watch
+ *                                     for noise.
+ */
 #define SYN_CAP_CLICKPAD(ex0c)         ((ex0c) & 0x100000) /* 1-button ClickPad */
 #define SYN_CAP_CLICKPAD2BTN(ex0c)     ((ex0c) & 0x000100) /* 2-button ClickPad */
 #define SYN_CAP_MAX_DIMENSIONS(ex0c)   ((ex0c) & 0x020000)
index 448c772..8528165 100644 (file)
@@ -111,9 +111,11 @@ static void ct82c710_close(struct serio *serio)
 static int ct82c710_open(struct serio *serio)
 {
        unsigned char status;
+       int err;
 
-       if (request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL))
-               return -1;
+       err = request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL);
+       if (err)
+               return err;
 
        status = inb_p(CT82C710_STATUS);
 
@@ -131,7 +133,7 @@ static int ct82c710_open(struct serio *serio)
                status &= ~(CT82C710_ENABLE | CT82C710_INTS_ON);
                outb_p(status, CT82C710_STATUS);
                free_irq(CT82C710_IRQ, NULL);
-               return -1;
+               return -EBUSY;
        }
 
        return 0;
index db5b0bc..ba70058 100644 (file)
@@ -188,7 +188,8 @@ static void serio_free_event(struct serio_event *event)
        kfree(event);
 }
 
-static void serio_remove_duplicate_events(struct serio_event *event)
+static void serio_remove_duplicate_events(void *object,
+                                         enum serio_event_type type)
 {
        struct serio_event *e, *next;
        unsigned long flags;
@@ -196,13 +197,13 @@ static void serio_remove_duplicate_events(struct serio_event *event)
        spin_lock_irqsave(&serio_event_lock, flags);
 
        list_for_each_entry_safe(e, next, &serio_event_list, node) {
-               if (event->object == e->object) {
+               if (object == e->object) {
                        /*
                         * If this event is of different type we should not
                         * look further - we only suppress duplicate events
                         * that were sent back-to-back.
                         */
-                       if (event->type != e->type)
+                       if (type != e->type)
                                break;
 
                        list_del_init(&e->node);
@@ -245,7 +246,7 @@ static void serio_handle_event(struct work_struct *work)
                        break;
                }
 
-               serio_remove_duplicate_events(event);
+               serio_remove_duplicate_events(event->object, event->type);
                serio_free_event(event);
        }
 
@@ -298,7 +299,7 @@ static int serio_queue_event(void *object, struct module *owner,
        event->owner = owner;
 
        list_add_tail(&event->node, &serio_event_list);
-       schedule_work(&serio_event_work);
+       queue_work(system_long_wq, &serio_event_work);
 
 out:
        spin_unlock_irqrestore(&serio_event_lock, flags);
@@ -436,10 +437,12 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *
        } else if (!strncmp(buf, "rescan", count)) {
                serio_disconnect_port(serio);
                serio_find_driver(serio);
+               serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT);
        } else if ((drv = driver_find(buf, &serio_bus)) != NULL) {
                serio_disconnect_port(serio);
                error = serio_bind_driver(serio, to_serio_driver(drv));
                put_driver(drv);
+               serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT);
        } else {
                error = -EINVAL;
        }
index 6e362de..8755f5f 100644 (file)
@@ -116,14 +116,15 @@ static void serport_ldisc_close(struct tty_struct *tty)
 
 /*
  * serport_ldisc_receive() is called by the low level tty driver when characters
- * are ready for us. We forward the characters, one by one to the 'interrupt'
- * routine.
+ * are ready for us. We forward the characters and flags, one by one to the
+ * 'interrupt' routine.
  */
 
 static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
 {
        struct serport *serport = (struct serport*) tty->disc_data;
        unsigned long flags;
+       unsigned int ch_flags;
        int i;
 
        spin_lock_irqsave(&serport->lock, flags);
@@ -131,8 +132,23 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c
        if (!test_bit(SERPORT_ACTIVE, &serport->flags))
                goto out;
 
-       for (i = 0; i < count; i++)
-               serio_interrupt(serport->serio, cp[i], 0);
+       for (i = 0; i < count; i++) {
+               switch (fp[i]) {
+               case TTY_FRAME:
+                       ch_flags = SERIO_FRAME;
+                       break;
+
+               case TTY_PARITY:
+                       ch_flags = SERIO_PARITY;
+                       break;
+
+               default:
+                       ch_flags = 0;
+                       break;
+               }
+
+               serio_interrupt(serport->serio, cp[i], ch_flags);
+       }
 
 out:
        spin_unlock_irqrestore(&serport->lock, flags);
index a29a781..7729e54 100644 (file)
@@ -201,6 +201,7 @@ int sparse_keymap_setup(struct input_dev *dev,
                        break;
 
                case KE_SW:
+               case KE_VSW:
                        __set_bit(EV_SW, dev->evbit);
                        __set_bit(entry->sw.code, dev->swbit);
                        break;
index fc38149..cf8fb9f 100644 (file)
@@ -519,7 +519,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
        /* Retrieve the physical and logical size for OEM devices */
        error = wacom_retrieve_hid_descriptor(intf, features);
        if (error)
-               goto fail2;
+               goto fail3;
 
        wacom_setup_device_quirks(features);
 
index 5187829..367fa82 100644 (file)
@@ -1101,6 +1101,13 @@ void wacom_setup_device_quirks(struct wacom_features *features)
        }
 }
 
+static unsigned int wacom_calculate_touch_res(unsigned int logical_max,
+                                             unsigned int physical_max)
+{
+       /* Touch physical dimensions are in 100th of mm */
+       return (logical_max * 100) / physical_max;
+}
+
 void wacom_setup_input_capabilities(struct input_dev *input_dev,
                                    struct wacom_wac *wacom_wac)
 {
@@ -1228,8 +1235,12 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
        case TABLETPC:
                if (features->device_type == BTN_TOOL_DOUBLETAP ||
                    features->device_type == BTN_TOOL_TRIPLETAP) {
-                       input_set_abs_params(input_dev, ABS_RX, 0, features->x_phy, 0, 0);
-                       input_set_abs_params(input_dev, ABS_RY, 0, features->y_phy, 0, 0);
+                       input_abs_set_res(input_dev, ABS_X,
+                               wacom_calculate_touch_res(features->x_max,
+                                                       features->x_phy));
+                       input_abs_set_res(input_dev, ABS_Y,
+                               wacom_calculate_touch_res(features->y_max,
+                                                       features->y_phy));
                        __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
                }
 
@@ -1272,6 +1283,12 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
                        input_set_abs_params(input_dev, ABS_MT_PRESSURE,
                                             0, features->pressure_max,
                                             features->pressure_fuzz, 0);
+                       input_abs_set_res(input_dev, ABS_X,
+                               wacom_calculate_touch_res(features->x_max,
+                                                       features->x_phy));
+                       input_abs_set_res(input_dev, ABS_Y,
+                               wacom_calculate_touch_res(features->y_max,
+                                                       features->y_phy));
                } else if (features->device_type == BTN_TOOL_PEN) {
                        __set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
                        __set_bit(BTN_TOOL_PEN, input_dev->keybit);
@@ -1426,6 +1443,10 @@ static struct wacom_features wacom_features_0xD3 =
        { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN,     21648, 13530, 1023, 63, BAMBOO_PT };
 static const struct wacom_features wacom_features_0xD4 =
        { "Wacom Bamboo Pen",     WACOM_PKGLEN_BBFUN,     14720,  9200,  255, 63, BAMBOO_PT };
+static struct wacom_features wacom_features_0xD6 =
+       { "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN,   14720,  9200, 1023, 63, BAMBOO_PT };
+static struct wacom_features wacom_features_0xD7 =
+       { "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720,  9200, 1023, 63, BAMBOO_PT };
 static struct wacom_features wacom_features_0xD8 =
        { "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN,   21648, 13530, 1023, 63, BAMBOO_PT };
 static struct wacom_features wacom_features_0xDA =
@@ -1507,6 +1528,8 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0xD2) },
        { USB_DEVICE_WACOM(0xD3) },
        { USB_DEVICE_WACOM(0xD4) },
+       { USB_DEVICE_WACOM(0xD6) },
+       { USB_DEVICE_WACOM(0xD7) },
        { USB_DEVICE_WACOM(0xD8) },
        { USB_DEVICE_WACOM(0xDA) },
        { USB_DEVICE_WACOM(0xDB) },
index 14ea54b..4bf2316 100644 (file)
@@ -941,28 +941,29 @@ static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads784
        struct ads7846_platform_data *pdata = spi->dev.platform_data;
        int err;
 
-       /* REVISIT when the irq can be triggered active-low, or if for some
+       /*
+        * REVISIT when the irq can be triggered active-low, or if for some
         * reason the touchscreen isn't hooked up, we don't need to access
         * the pendown state.
         */
-       if (!pdata->get_pendown_state && !gpio_is_valid(pdata->gpio_pendown)) {
-               dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n");
-               return -EINVAL;
-       }
 
        if (pdata->get_pendown_state) {
                ts->get_pendown_state = pdata->get_pendown_state;
-               return 0;
-       }
+       } else if (gpio_is_valid(pdata->gpio_pendown)) {
 
-       err = gpio_request(pdata->gpio_pendown, "ads7846_pendown");
-       if (err) {
-               dev_err(&spi->dev, "failed to request pendown GPIO%d\n",
-                       pdata->gpio_pendown);
-               return err;
-       }
+               err = gpio_request(pdata->gpio_pendown, "ads7846_pendown");
+               if (err) {
+                       dev_err(&spi->dev, "failed to request pendown GPIO%d\n",
+                               pdata->gpio_pendown);
+                       return err;
+               }
 
-       ts->gpio_pendown = pdata->gpio_pendown;
+               ts->gpio_pendown = pdata->gpio_pendown;
+
+       } else {
+               dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n");
+               return -EINVAL;
+       }
 
        return 0;
 }
@@ -1353,7 +1354,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
  err_put_regulator:
        regulator_put(ts->reg);
  err_free_gpio:
-       if (ts->gpio_pendown != -1)
+       if (!ts->get_pendown_state)
                gpio_free(ts->gpio_pendown);
  err_cleanup_filter:
        if (ts->filter_cleanup)
@@ -1383,8 +1384,13 @@ static int __devexit ads7846_remove(struct spi_device *spi)
        regulator_disable(ts->reg);
        regulator_put(ts->reg);
 
-       if (ts->gpio_pendown != -1)
+       if (!ts->get_pendown_state) {
+               /*
+                * If we are not using specialized pendown method we must
+                * have been relying on gpio we set up ourselves.
+                */
                gpio_free(ts->gpio_pendown);
+       }
 
        if (ts->filter_cleanup)
                ts->filter_cleanup(ts->filter_data);
index f7fa9ef..1507ce1 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/input.h>
 #include <linux/input/bu21013.h>
 #include <linux/slab.h>
+#include <linux/regulator/consumer.h>
 
 #define PEN_DOWN_INTR  0
 #define MAX_FINGERS    2
  * @chip: pointer to the touch panel controller
  * @in_dev: pointer to the input device structure
  * @intr_pin: interrupt pin value
+ * @regulator: pointer to the Regulator used for touch screen
  *
  * Touch panel device data structure
  */
@@ -149,6 +151,7 @@ struct bu21013_ts_data {
        const struct bu21013_platform_device *chip;
        struct input_dev *in_dev;
        unsigned int intr_pin;
+       struct regulator *regulator;
 };
 
 /**
@@ -456,6 +459,20 @@ static int __devinit bu21013_probe(struct i2c_client *client,
        bu21013_data->in_dev = in_dev;
        bu21013_data->chip = pdata;
        bu21013_data->client = client;
+
+       bu21013_data->regulator = regulator_get(&client->dev, "V-TOUCH");
+       if (IS_ERR(bu21013_data->regulator)) {
+               dev_err(&client->dev, "regulator_get failed\n");
+               error = PTR_ERR(bu21013_data->regulator);
+               goto err_free_mem;
+       }
+
+       error = regulator_enable(bu21013_data->regulator);
+       if (error < 0) {
+               dev_err(&client->dev, "regulator enable failed\n");
+               goto err_put_regulator;
+       }
+
        bu21013_data->touch_stopped = false;
        init_waitqueue_head(&bu21013_data->wait);
 
@@ -464,7 +481,7 @@ static int __devinit bu21013_probe(struct i2c_client *client,
                error = pdata->cs_en(pdata->cs_pin);
                if (error < 0) {
                        dev_err(&client->dev, "chip init failed\n");
-                       goto err_free_mem;
+                       goto err_disable_regulator;
                }
        }
 
@@ -485,9 +502,9 @@ static int __devinit bu21013_probe(struct i2c_client *client,
        __set_bit(EV_ABS, in_dev->evbit);
 
        input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0,
-                                               pdata->x_max_res, 0, 0);
+                                               pdata->touch_x_max, 0, 0);
        input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0,
-                                               pdata->y_max_res, 0, 0);
+                                               pdata->touch_y_max, 0, 0);
        input_set_drvdata(in_dev, bu21013_data);
 
        error = request_threaded_irq(pdata->irq, NULL, bu21013_gpio_irq,
@@ -513,6 +530,10 @@ err_free_irq:
        bu21013_free_irq(bu21013_data);
 err_cs_disable:
        pdata->cs_dis(pdata->cs_pin);
+err_disable_regulator:
+       regulator_disable(bu21013_data->regulator);
+err_put_regulator:
+       regulator_put(bu21013_data->regulator);
 err_free_mem:
        input_free_device(in_dev);
        kfree(bu21013_data);
@@ -535,6 +556,10 @@ static int __devexit bu21013_remove(struct i2c_client *client)
        bu21013_data->chip->cs_dis(bu21013_data->chip->cs_pin);
 
        input_unregister_device(bu21013_data->in_dev);
+
+       regulator_disable(bu21013_data->regulator);
+       regulator_put(bu21013_data->regulator);
+
        kfree(bu21013_data);
 
        device_init_wakeup(&client->dev, false);
@@ -561,6 +586,8 @@ static int bu21013_suspend(struct device *dev)
        else
                disable_irq(bu21013_data->chip->irq);
 
+       regulator_disable(bu21013_data->regulator);
+
        return 0;
 }
 
@@ -577,6 +604,12 @@ static int bu21013_resume(struct device *dev)
        struct i2c_client *client = bu21013_data->client;
        int retval;
 
+       retval = regulator_enable(bu21013_data->regulator);
+       if (retval < 0) {
+               dev_err(&client->dev, "bu21013 regulator enable failed\n");
+               return retval;
+       }
+
        retval = bu21013_init_chip(bu21013_data);
        if (retval < 0) {
                dev_err(&client->dev, "bu21013 controller config failed\n");
index cf1dba2..22a3411 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/err.h>
 #include <linux/errno.h>
 #include <linux/input.h>
 #include <linux/platform_device.h>
@@ -289,9 +290,9 @@ static int __devinit tsc_probe(struct platform_device *pdev)
        }
 
        ts->clk = clk_get(dev, NULL);
-       if (!ts->clk) {
+       if (IS_ERR(ts->clk)) {
                dev_err(dev, "cannot claim device clock\n");
-               error = -EINVAL;
+               error = PTR_ERR(ts->clk);
                goto error_clk;
        }
 
index c8c136c..4303149 100644 (file)
@@ -43,7 +43,6 @@ struct tps6507x_ts {
        struct input_dev        *input_dev;
        struct device           *dev;
        char                    phys[32];
-       struct workqueue_struct *wq;
        struct delayed_work     work;
        unsigned                polling;        /* polling is active */
        struct ts_event         tc;
@@ -220,8 +219,8 @@ done:
        poll = 1;
 
        if (poll) {
-               schd = queue_delayed_work(tsc->wq, &tsc->work,
-                                         msecs_to_jiffies(tsc->poll_period));
+               schd = schedule_delayed_work(&tsc->work,
+                                       msecs_to_jiffies(tsc->poll_period));
                if (schd)
                        tsc->polling = 1;
                else {
@@ -303,7 +302,6 @@ static int tps6507x_ts_probe(struct platform_device *pdev)
        tsc->input_dev = input_dev;
 
        INIT_DELAYED_WORK(&tsc->work, tps6507x_ts_handler);
-       tsc->wq = create_workqueue("TPS6507x Touchscreen");
 
        if (init_data) {
                tsc->poll_period = init_data->poll_period;
@@ -325,8 +323,8 @@ static int tps6507x_ts_probe(struct platform_device *pdev)
        if (error)
                goto err2;
 
-       schd = queue_delayed_work(tsc->wq, &tsc->work,
-                                 msecs_to_jiffies(tsc->poll_period));
+       schd = schedule_delayed_work(&tsc->work,
+                                    msecs_to_jiffies(tsc->poll_period));
 
        if (schd)
                tsc->polling = 1;
@@ -341,7 +339,6 @@ static int tps6507x_ts_probe(struct platform_device *pdev)
 
 err2:
        cancel_delayed_work_sync(&tsc->work);
-       destroy_workqueue(tsc->wq);
        input_free_device(input_dev);
 err1:
        kfree(tsc);
@@ -357,7 +354,6 @@ static int __devexit tps6507x_ts_remove(struct platform_device *pdev)
        struct input_dev *input_dev = tsc->input_dev;
 
        cancel_delayed_work_sync(&tsc->work);
-       destroy_workqueue(tsc->wq);
 
        input_unregister_device(input_dev);
 
index 5cb8449..c14412e 100644 (file)
@@ -51,6 +51,10 @@ MODULE_LICENSE("GPL");
 #define W8001_PKTLEN_TPCCTL    11      /* control packet */
 #define W8001_PKTLEN_TOUCH2FG  13
 
+/* resolution in points/mm */
+#define W8001_PEN_RESOLUTION    100
+#define W8001_TOUCH_RESOLUTION  10
+
 struct w8001_coord {
        u8 rdy;
        u8 tsw;
@@ -198,7 +202,7 @@ static void parse_touchquery(u8 *data, struct w8001_touch_query *query)
                query->y = 1024;
                if (query->panel_res)
                        query->x = query->y = (1 << query->panel_res);
-               query->panel_res = 10;
+               query->panel_res = W8001_TOUCH_RESOLUTION;
        }
 }
 
@@ -394,6 +398,8 @@ static int w8001_setup(struct w8001 *w8001)
 
                input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0);
                input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0);
+               input_abs_set_res(dev, ABS_X, W8001_PEN_RESOLUTION);
+               input_abs_set_res(dev, ABS_Y, W8001_PEN_RESOLUTION);
                input_set_abs_params(dev, ABS_PRESSURE, 0, coord.pen_pressure, 0, 0);
                if (coord.tilt_x && coord.tilt_y) {
                        input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0);
@@ -418,14 +424,17 @@ static int w8001_setup(struct w8001 *w8001)
                w8001->max_touch_x = touch.x;
                w8001->max_touch_y = touch.y;
 
-               /* scale to pen maximum */
                if (w8001->max_pen_x && w8001->max_pen_y) {
+                       /* if pen is supported scale to pen maximum */
                        touch.x = w8001->max_pen_x;
                        touch.y = w8001->max_pen_y;
+                       touch.panel_res = W8001_PEN_RESOLUTION;
                }
 
                input_set_abs_params(dev, ABS_X, 0, touch.x, 0, 0);
                input_set_abs_params(dev, ABS_Y, 0, touch.y, 0, 0);
+               input_abs_set_res(dev, ABS_X, touch.panel_res);
+               input_abs_set_res(dev, ABS_Y, touch.panel_res);
 
                switch (touch.sensor_id) {
                case 0:
index 18f8798..7bd5baa 100644 (file)
@@ -62,7 +62,7 @@ void diva_xdi_provide_istream_info (ADAPTER* a,
   stream interface.
   If synchronous service was requested, then function
   does return amount of data written to stream.
-  'final' does indicate that pice of data to be written is
+  'final' does indicate that piece of data to be written is
   final part of frame (necessary only by structured datatransfer)
   return  0 if zero lengh packet was written
   return -1 if stream is full
index 0858791..cfff0c4 100644 (file)
@@ -1247,10 +1247,10 @@ static void
 l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
-       struct sk_buff *skb, *oskb;
+       struct sk_buff *skb;
        struct Layer2 *l2 = &st->l2;
        u_char header[MAX_HEADER_LEN];
-       int i;
+       int i, hdr_space_needed;
        int unsigned p1;
        u_long flags;
 
@@ -1261,6 +1261,16 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
        if (!skb)
                return;
 
+       hdr_space_needed = l2headersize(l2, 0);
+       if (hdr_space_needed > skb_headroom(skb)) {
+               struct sk_buff *orig_skb = skb;
+
+               skb = skb_realloc_headroom(skb, hdr_space_needed);
+               if (!skb) {
+                       dev_kfree_skb(orig_skb);
+                       return;
+               }
+       }
        spin_lock_irqsave(&l2->lock, flags);
        if(test_bit(FLG_MOD128, &l2->flag))
                p1 = (l2->vs - l2->va) % 128;
@@ -1285,19 +1295,7 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
                l2->vs = (l2->vs + 1) % 8;
        }
        spin_unlock_irqrestore(&l2->lock, flags);
-       p1 = skb->data - skb->head;
-       if (p1 >= i)
-               memcpy(skb_push(skb, i), header, i);
-       else {
-               printk(KERN_WARNING
-               "isdl2 pull_iqueue skb header(%d/%d) too short\n", i, p1);
-               oskb = skb;
-               skb = alloc_skb(oskb->len + i, GFP_ATOMIC);
-               memcpy(skb_put(skb, i), header, i);
-               skb_copy_from_linear_data(oskb,
-                                         skb_put(skb, oskb->len), oskb->len);
-               dev_kfree_skb(oskb);
-       }
+       memcpy(skb_push(skb, i), header, i);
        st->l2.l2l1(st, PH_PULL | INDICATION, skb);
        test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
        if (!test_and_set_bit(FLG_T200_RUN, &st->l2.flag)) {
index 729df40..18b801a 100644 (file)
@@ -227,7 +227,6 @@ extern hysdn_card *card_root;       /* pointer to first card */
 /*************************/
 /* im/exported functions */
 /*************************/
-extern char *hysdn_getrev(const char *);
 
 /* hysdn_procconf.c */
 extern int hysdn_procconf_init(void);  /* init proc config filesys */
@@ -259,7 +258,6 @@ extern int hysdn_tx_cfgline(hysdn_card *, unsigned char *,
 
 /* hysdn_net.c */
 extern unsigned int hynet_enable; 
-extern char *hysdn_net_revision;
 extern int hysdn_net_create(hysdn_card *);     /* create a new net device */
 extern int hysdn_net_release(hysdn_card *);    /* delete the device */
 extern char *hysdn_net_getname(hysdn_card *);  /* get name of net interface */
index b7cc5c2..0ab42ac 100644 (file)
@@ -36,7 +36,6 @@ MODULE_DESCRIPTION("ISDN4Linux: Driver for HYSDN cards");
 MODULE_AUTHOR("Werner Cornelius");
 MODULE_LICENSE("GPL");
 
-static char *hysdn_init_revision = "$Revision: 1.6.6.6 $";
 static int cardmax;            /* number of found cards */
 hysdn_card *card_root = NULL;  /* pointer to first card */
 static hysdn_card *card_last = NULL;   /* pointer to first card */
@@ -49,25 +48,6 @@ static hysdn_card *card_last = NULL; /* pointer to first card */
 /* Additionally newer versions may be activated without rebooting.          */
 /****************************************************************************/
 
-/******************************************************/
-/* extract revision number from string for log output */
-/******************************************************/
-char *
-hysdn_getrev(const char *revision)
-{
-       char *rev;
-       char *p;
-
-       if ((p = strchr(revision, ':'))) {
-               rev = p + 2;
-               p = strchr(rev, '$');
-               *--p = 0;
-       } else
-               rev = "???";
-       return rev;
-}
-
-
 /****************************************************************************/
 /* init_module is called once when the module is loaded to do all necessary */
 /* things like autodetect...                                                */
@@ -175,13 +155,9 @@ static int hysdn_have_procfs;
 static int __init
 hysdn_init(void)
 {
-       char tmp[50];
        int rc;
 
-       strcpy(tmp, hysdn_init_revision);
-       printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp));
-       strcpy(tmp, hysdn_net_revision);
-       printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp));
+       printk(KERN_NOTICE "HYSDN: module loaded\n");
 
        rc = pci_register_driver(&hysdn_pci_driver);
        if (rc)
index feec8d8..11f2cce 100644 (file)
@@ -26,9 +26,6 @@
 unsigned int hynet_enable = 0xffffffff; 
 module_param(hynet_enable, uint, 0);
 
-/* store the actual version for log reporting */
-char *hysdn_net_revision = "$Revision: 1.8.6.4 $";
-
 #define MAX_SKB_BUFFERS 20     /* number of buffers for keeping TX-data */
 
 /****************************************************************************/
index 96b3e39..5fe83bd 100644 (file)
@@ -23,7 +23,6 @@
 #include "hysdn_defs.h"
 
 static DEFINE_MUTEX(hysdn_conf_mutex);
-static char *hysdn_procconf_revision = "$Revision: 1.8.6.4 $";
 
 #define INFO_OUT_LEN 80                /* length of info line including lf */
 
@@ -404,7 +403,7 @@ hysdn_procconf_init(void)
                card = card->next;      /* next entry */
        }
 
-       printk(KERN_NOTICE "HYSDN: procfs Rev. %s initialised\n", hysdn_getrev(hysdn_procconf_revision));
+       printk(KERN_NOTICE "HYSDN: procfs initialised\n");
        return (0);
 }                              /* hysdn_procconf_init */
 
index f2b5bab..1f355bb 100644 (file)
@@ -1627,7 +1627,7 @@ __setup("icn=", icn_setup);
 static int __init icn_init(void)
 {
        char *p;
-       char rev[20];
+       char rev[21];
 
        memset(&dev, 0, sizeof(icn_dev));
        dev.memaddr = (membase & 0x0ffc000);
@@ -1638,6 +1638,7 @@ static int __init icn_init(void)
 
        if ((p = strchr(revision, ':'))) {
                strncpy(rev, p + 1, 20);
+               rev[20] = '\0';
                p = strchr(rev, '$');
                if (p)
                        *p = 0;
index da3fa8d..666daf7 100644 (file)
@@ -69,6 +69,7 @@ static int led_pwm_probe(struct platform_device *pdev)
                led_dat->pwm = pwm_request(cur_led->pwm_id,
                                cur_led->name);
                if (IS_ERR(led_dat->pwm)) {
+                       ret = PTR_ERR(led_dat->pwm);
                        dev_err(&pdev->dev, "unable to request PWM %d\n",
                                        cur_led->pwm_id);
                        goto err;
index 8a2f767..0ed7f6b 100644 (file)
@@ -216,7 +216,6 @@ static int linear_run (mddev_t *mddev)
 
        if (md_check_no_bitmap(mddev))
                return -EINVAL;
-       mddev->queue->queue_lock = &mddev->queue->__queue_lock;
        conf = linear_conf(mddev, mddev->raid_disks);
 
        if (!conf)
index b76cfc8..d5ad772 100644 (file)
@@ -287,6 +287,7 @@ static int md_make_request(struct request_queue *q, struct bio *bio)
        mddev_t *mddev = q->queuedata;
        int rv;
        int cpu;
+       unsigned int sectors;
 
        if (mddev == NULL || mddev->pers == NULL
            || !mddev->ready) {
@@ -311,12 +312,16 @@ static int md_make_request(struct request_queue *q, struct bio *bio)
        atomic_inc(&mddev->active_io);
        rcu_read_unlock();
 
+       /*
+        * save the sectors now since our bio can
+        * go away inside make_request
+        */
+       sectors = bio_sectors(bio);
        rv = mddev->pers->make_request(mddev, bio);
 
        cpu = part_stat_lock();
        part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]);
-       part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw],
-                     bio_sectors(bio));
+       part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw], sectors);
        part_stat_unlock();
 
        if (atomic_dec_and_test(&mddev->active_io) && mddev->suspended)
@@ -548,6 +553,9 @@ static mddev_t * mddev_find(dev_t unit)
 {
        mddev_t *mddev, *new = NULL;
 
+       if (unit && MAJOR(unit) != MD_MAJOR)
+               unit &= ~((1<<MdpMinorShift)-1);
+
  retry:
        spin_lock(&all_mddevs_lock);
 
@@ -1947,8 +1955,6 @@ static int lock_rdev(mdk_rdev_t *rdev, dev_t dev, int shared)
                        __bdevname(dev, b));
                return PTR_ERR(bdev);
        }
-       if (!shared)
-               set_bit(AllReserved, &rdev->flags);
        rdev->bdev = bdev;
        return err;
 }
@@ -2465,6 +2471,9 @@ slot_store(mdk_rdev_t *rdev, const char *buf, size_t len)
                if (rdev->raid_disk != -1)
                        return -EBUSY;
 
+               if (test_bit(MD_RECOVERY_RUNNING, &rdev->mddev->recovery))
+                       return -EBUSY;
+
                if (rdev->mddev->pers->hot_add_disk == NULL)
                        return -EINVAL;
 
@@ -2610,12 +2619,11 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
 
                        mddev_lock(mddev);
                        list_for_each_entry(rdev2, &mddev->disks, same_set)
-                               if (test_bit(AllReserved, &rdev2->flags) ||
-                                   (rdev->bdev == rdev2->bdev &&
-                                    rdev != rdev2 &&
-                                    overlaps(rdev->data_offset, rdev->sectors,
-                                             rdev2->data_offset,
-                                             rdev2->sectors))) {
+                               if (rdev->bdev == rdev2->bdev &&
+                                   rdev != rdev2 &&
+                                   overlaps(rdev->data_offset, rdev->sectors,
+                                            rdev2->data_offset,
+                                            rdev2->sectors)) {
                                        overlap = 1;
                                        break;
                                }
@@ -4133,10 +4141,10 @@ array_size_store(mddev_t *mddev, const char *buf, size_t len)
        }
 
        mddev->array_sectors = sectors;
-       set_capacity(mddev->gendisk, mddev->array_sectors);
-       if (mddev->pers)
+       if (mddev->pers) {
+               set_capacity(mddev->gendisk, mddev->array_sectors);
                revalidate_disk(mddev->gendisk);
-
+       }
        return len;
 }
 
@@ -4619,6 +4627,7 @@ static int do_md_run(mddev_t *mddev)
        }
        set_capacity(mddev->gendisk, mddev->array_sectors);
        revalidate_disk(mddev->gendisk);
+       mddev->changed = 1;
        kobject_uevent(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE);
 out:
        return err;
@@ -4707,6 +4716,7 @@ static void md_clean(mddev_t *mddev)
        mddev->sync_speed_min = mddev->sync_speed_max = 0;
        mddev->recovery = 0;
        mddev->in_sync = 0;
+       mddev->changed = 0;
        mddev->degraded = 0;
        mddev->safemode = 0;
        mddev->bitmap_info.offset = 0;
@@ -4822,6 +4832,7 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
 
                set_capacity(disk, 0);
                mutex_unlock(&mddev->open_mutex);
+               mddev->changed = 1;
                revalidate_disk(disk);
 
                if (mddev->ro)
@@ -5578,6 +5589,8 @@ static int update_raid_disks(mddev_t *mddev, int raid_disks)
        mddev->delta_disks = raid_disks - mddev->raid_disks;
 
        rv = mddev->pers->check_reshape(mddev);
+       if (rv < 0)
+               mddev->delta_disks = 0;
        return rv;
 }
 
@@ -6004,7 +6017,7 @@ static int md_open(struct block_device *bdev, fmode_t mode)
        atomic_inc(&mddev->openers);
        mutex_unlock(&mddev->open_mutex);
 
-       check_disk_size_change(mddev->gendisk, bdev);
+       check_disk_change(bdev);
  out:
        return err;
 }
@@ -6019,6 +6032,21 @@ static int md_release(struct gendisk *disk, fmode_t mode)
 
        return 0;
 }
+
+static int md_media_changed(struct gendisk *disk)
+{
+       mddev_t *mddev = disk->private_data;
+
+       return mddev->changed;
+}
+
+static int md_revalidate(struct gendisk *disk)
+{
+       mddev_t *mddev = disk->private_data;
+
+       mddev->changed = 0;
+       return 0;
+}
 static const struct block_device_operations md_fops =
 {
        .owner          = THIS_MODULE,
@@ -6029,6 +6057,8 @@ static const struct block_device_operations md_fops =
        .compat_ioctl   = md_compat_ioctl,
 #endif
        .getgeo         = md_getgeo,
+       .media_changed  = md_media_changed,
+       .revalidate_disk= md_revalidate,
 };
 
 static int md_thread(void * arg)
@@ -6985,9 +7015,6 @@ void md_do_sync(mddev_t *mddev)
        } else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
                mddev->resync_min = mddev->curr_resync_completed;
        mddev->curr_resync = 0;
-       if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery))
-               mddev->curr_resync_completed = 0;
-       sysfs_notify(&mddev->kobj, NULL, "sync_completed");
        wake_up(&resync_wait);
        set_bit(MD_RECOVERY_DONE, &mddev->recovery);
        md_wakeup_thread(mddev->thread);
@@ -7028,7 +7055,7 @@ static int remove_and_add_spares(mddev_t *mddev)
                        }
                }
 
-       if (mddev->degraded && ! mddev->ro && !mddev->recovery_disabled) {
+       if (mddev->degraded && !mddev->recovery_disabled) {
                list_for_each_entry(rdev, &mddev->disks, same_set) {
                        if (rdev->raid_disk >= 0 &&
                            !test_bit(In_sync, &rdev->flags) &&
@@ -7151,7 +7178,20 @@ void md_check_recovery(mddev_t *mddev)
                        /* Only thing we do on a ro array is remove
                         * failed devices.
                         */
-                       remove_and_add_spares(mddev);
+                       mdk_rdev_t *rdev;
+                       list_for_each_entry(rdev, &mddev->disks, same_set)
+                               if (rdev->raid_disk >= 0 &&
+                                   !test_bit(Blocked, &rdev->flags) &&
+                                   test_bit(Faulty, &rdev->flags) &&
+                                   atomic_read(&rdev->nr_pending)==0) {
+                                       if (mddev->pers->hot_remove_disk(
+                                                   mddev, rdev->raid_disk)==0) {
+                                               char nm[20];
+                                               sprintf(nm,"rd%d", rdev->raid_disk);
+                                               sysfs_remove_link(&mddev->kobj, nm);
+                                               rdev->raid_disk = -1;
+                                       }
+                               }
                        clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
                        goto unlock;
                }
@@ -7321,7 +7361,7 @@ static int __init md_init(void)
 {
        int ret = -ENOMEM;
 
-       md_wq = alloc_workqueue("md", WQ_RESCUER, 0);
+       md_wq = alloc_workqueue("md", WQ_MEM_RECLAIM, 0);
        if (!md_wq)
                goto err_wq;
 
index eec517c..12215d4 100644 (file)
@@ -93,8 +93,6 @@ struct mdk_rdev_s
 #define        Faulty          1               /* device is known to have a fault */
 #define        In_sync         2               /* device is in_sync with rest of array */
 #define        WriteMostly     4               /* Avoid reading if at all possible */
-#define        AllReserved     6               /* If whole device is reserved for
-                                        * one array */
 #define        AutoDetected    7               /* added by auto-detect */
 #define Blocked                8               /* An error occured on an externally
                                         * managed array, don't allow writes
@@ -276,6 +274,8 @@ struct mddev_s
        atomic_t                        active;         /* general refcount */
        atomic_t                        openers;        /* number of active opens */
 
+       int                             changed;        /* True if we might need to
+                                                        * reread partition info */
        int                             degraded;       /* whether md should consider
                                                         * adding a spare
                                                         */
index 6d7ddf3..3a62d44 100644 (file)
@@ -435,7 +435,6 @@ static int multipath_run (mddev_t *mddev)
         * bookkeeping area. [whatever we allocate in multipath_run(),
         * should be freed in multipath_stop()]
         */
-       mddev->queue->queue_lock = &mddev->queue->__queue_lock;
 
        conf = kzalloc(sizeof(multipath_conf_t), GFP_KERNEL);
        mddev->private = conf;
index a39f4c3..c0ac457 100644 (file)
@@ -179,6 +179,14 @@ static int create_strip_zones(mddev_t *mddev, raid0_conf_t **private_conf)
                        rdev1->new_raid_disk = j;
                }
 
+               if (mddev->level == 1) {
+                       /* taiking over a raid1 array-
+                        * we have only one active disk
+                        */
+                       j = 0;
+                       rdev1->new_raid_disk = j;
+               }
+
                if (j < 0 || j >= mddev->raid_disks) {
                        printk(KERN_ERR "md/raid0:%s: bad disk number %d - "
                               "aborting!\n", mdname(mddev), j);
@@ -353,7 +361,6 @@ static int raid0_run(mddev_t *mddev)
        if (md_check_no_bitmap(mddev))
                return -EINVAL;
        blk_queue_max_hw_sectors(mddev->queue, mddev->chunk_sectors);
-       mddev->queue->queue_lock = &mddev->queue->__queue_lock;
 
        /* if private is not null, we are here after takeover */
        if (mddev->private == NULL) {
@@ -644,12 +651,39 @@ static void *raid0_takeover_raid10(mddev_t *mddev)
        return priv_conf;
 }
 
+static void *raid0_takeover_raid1(mddev_t *mddev)
+{
+       raid0_conf_t *priv_conf;
+
+       /* Check layout:
+        *  - (N - 1) mirror drives must be already faulty
+        */
+       if ((mddev->raid_disks - 1) != mddev->degraded) {
+               printk(KERN_ERR "md/raid0:%s: (N - 1) mirrors drives must be already faulty!\n",
+                      mdname(mddev));
+               return ERR_PTR(-EINVAL);
+       }
+
+       /* Set new parameters */
+       mddev->new_level = 0;
+       mddev->new_layout = 0;
+       mddev->new_chunk_sectors = 128; /* by default set chunk size to 64k */
+       mddev->delta_disks = 1 - mddev->raid_disks;
+       mddev->raid_disks = 1;
+       /* make sure it will be not marked as dirty */
+       mddev->recovery_cp = MaxSector;
+
+       create_strip_zones(mddev, &priv_conf);
+       return priv_conf;
+}
+
 static void *raid0_takeover(mddev_t *mddev)
 {
        /* raid0 can take over:
         *  raid4 - if all data disks are active.
         *  raid5 - providing it is Raid4 layout and one disk is faulty
         *  raid10 - assuming we have all necessary active disks
+        *  raid1 - with (N -1) mirror drives faulty
         */
        if (mddev->level == 4)
                return raid0_takeover_raid45(mddev);
@@ -665,6 +699,12 @@ static void *raid0_takeover(mddev_t *mddev)
        if (mddev->level == 10)
                return raid0_takeover_raid10(mddev);
 
+       if (mddev->level == 1)
+               return raid0_takeover_raid1(mddev);
+
+       printk(KERN_ERR "Takeover from raid%i to raid0 not supported\n",
+               mddev->level);
+
        return ERR_PTR(-EINVAL);
 }
 
index a23ffa3..06cd712 100644 (file)
@@ -593,7 +593,10 @@ static int flush_pending_writes(conf_t *conf)
        if (conf->pending_bio_list.head) {
                struct bio *bio;
                bio = bio_list_get(&conf->pending_bio_list);
+               /* Only take the spinlock to quiet a warning */
+               spin_lock(conf->mddev->queue->queue_lock);
                blk_remove_plug(conf->mddev->queue);
+               spin_unlock(conf->mddev->queue->queue_lock);
                spin_unlock_irq(&conf->device_lock);
                /* flush any pending bitmap writes to
                 * disk before proceeding w/ I/O */
@@ -959,7 +962,7 @@ static int make_request(mddev_t *mddev, struct bio * bio)
                atomic_inc(&r1_bio->remaining);
                spin_lock_irqsave(&conf->device_lock, flags);
                bio_list_add(&conf->pending_bio_list, mbio);
-               blk_plug_device(mddev->queue);
+               blk_plug_device_unlocked(mddev->queue);
                spin_unlock_irqrestore(&conf->device_lock, flags);
        }
        r1_bio_write_done(r1_bio, bio->bi_vcnt, behind_pages, behind_pages != NULL);
@@ -2021,7 +2024,6 @@ static int run(mddev_t *mddev)
        if (IS_ERR(conf))
                return PTR_ERR(conf);
 
-       mddev->queue->queue_lock = &conf->device_lock;
        list_for_each_entry(rdev, &mddev->disks, same_set) {
                disk_stack_limits(mddev->gendisk, rdev->bdev,
                                  rdev->data_offset << 9);
index 69b6595..747d061 100644 (file)
@@ -662,7 +662,10 @@ static int flush_pending_writes(conf_t *conf)
        if (conf->pending_bio_list.head) {
                struct bio *bio;
                bio = bio_list_get(&conf->pending_bio_list);
+               /* Spinlock only taken to quiet a warning */
+               spin_lock(conf->mddev->queue->queue_lock);
                blk_remove_plug(conf->mddev->queue);
+               spin_unlock(conf->mddev->queue->queue_lock);
                spin_unlock_irq(&conf->device_lock);
                /* flush any pending bitmap writes to disk
                 * before proceeding w/ I/O */
@@ -971,7 +974,7 @@ static int make_request(mddev_t *mddev, struct bio * bio)
                atomic_inc(&r10_bio->remaining);
                spin_lock_irqsave(&conf->device_lock, flags);
                bio_list_add(&conf->pending_bio_list, mbio);
-               blk_plug_device(mddev->queue);
+               blk_plug_device_unlocked(mddev->queue);
                spin_unlock_irqrestore(&conf->device_lock, flags);
        }
 
@@ -2304,8 +2307,6 @@ static int run(mddev_t *mddev)
        if (!conf)
                goto out;
 
-       mddev->queue->queue_lock = &conf->device_lock;
-
        mddev->thread = conf->thread;
        conf->thread = NULL;
 
@@ -2463,11 +2464,13 @@ static void *raid10_takeover_raid0(mddev_t *mddev)
        mddev->recovery_cp = MaxSector;
 
        conf = setup_conf(mddev);
-       if (!IS_ERR(conf))
+       if (!IS_ERR(conf)) {
                list_for_each_entry(rdev, &mddev->disks, same_set)
                        if (rdev->raid_disk >= 0)
                                rdev->new_raid_disk = rdev->raid_disk * 2;
-               
+               conf->barrier = 1;
+       }
+
        return conf;
 }
 
index 5044bab..78536fd 100644 (file)
@@ -5204,7 +5204,6 @@ static int run(mddev_t *mddev)
 
                mddev->queue->backing_dev_info.congested_data = mddev;
                mddev->queue->backing_dev_info.congested_fn = raid5_congested;
-               mddev->queue->queue_lock = &conf->device_lock;
                mddev->queue->unplug_fn = raid5_unplug_queue;
 
                chunk_size = mddev->chunk_sectors << 9;
@@ -5517,7 +5516,6 @@ static int raid5_start_reshape(mddev_t *mddev)
        raid5_conf_t *conf = mddev->private;
        mdk_rdev_t *rdev;
        int spares = 0;
-       int added_devices = 0;
        unsigned long flags;
 
        if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
@@ -5527,8 +5525,8 @@ static int raid5_start_reshape(mddev_t *mddev)
                return -ENOSPC;
 
        list_for_each_entry(rdev, &mddev->disks, same_set)
-               if ((rdev->raid_disk < 0 || rdev->raid_disk >= conf->raid_disks)
-                    && !test_bit(Faulty, &rdev->flags))
+               if (!test_bit(In_sync, &rdev->flags)
+                   && !test_bit(Faulty, &rdev->flags))
                        spares++;
 
        if (spares - mddev->degraded < mddev->delta_disks - conf->max_degraded)
@@ -5571,34 +5569,35 @@ static int raid5_start_reshape(mddev_t *mddev)
         * to correctly record the "partially reconstructed" state of
         * such devices during the reshape and confusion could result.
         */
-       if (mddev->delta_disks >= 0)
-           list_for_each_entry(rdev, &mddev->disks, same_set)
-               if (rdev->raid_disk < 0 &&
-                   !test_bit(Faulty, &rdev->flags)) {
-                       if (raid5_add_disk(mddev, rdev) == 0) {
-                               char nm[20];
-                               if (rdev->raid_disk >= conf->previous_raid_disks) {
-                                       set_bit(In_sync, &rdev->flags);
-                                       added_devices++;
-                               } else
-                                       rdev->recovery_offset = 0;
-                               sprintf(nm, "rd%d", rdev->raid_disk);
-                               if (sysfs_create_link(&mddev->kobj,
-                                                     &rdev->kobj, nm))
-                                       /* Failure here is OK */;
-                       } else
-                               break;
-               } else if (rdev->raid_disk >= conf->previous_raid_disks
-                          && !test_bit(Faulty, &rdev->flags)) {
-                       /* This is a spare that was manually added */
-                       set_bit(In_sync, &rdev->flags);
-                       added_devices++;
-               }
+       if (mddev->delta_disks >= 0) {
+               int added_devices = 0;
+               list_for_each_entry(rdev, &mddev->disks, same_set)
+                       if (rdev->raid_disk < 0 &&
+                           !test_bit(Faulty, &rdev->flags)) {
+                               if (raid5_add_disk(mddev, rdev) == 0) {
+                                       char nm[20];
+                                       if (rdev->raid_disk
+                                           >= conf->previous_raid_disks) {
+                                               set_bit(In_sync, &rdev->flags);
+                                               added_devices++;
+                                       } else
+                                               rdev->recovery_offset = 0;
+                                       sprintf(nm, "rd%d", rdev->raid_disk);
+                                       if (sysfs_create_link(&mddev->kobj,
+                                                             &rdev->kobj, nm))
+                                               /* Failure here is OK */;
+                               }
+                       } else if (rdev->raid_disk >= conf->previous_raid_disks
+                                  && !test_bit(Faulty, &rdev->flags)) {
+                               /* This is a spare that was manually added */
+                               set_bit(In_sync, &rdev->flags);
+                               added_devices++;
+                       }
 
-       /* When a reshape changes the number of devices, ->degraded
-        * is measured against the larger of the pre and post number of
-        * devices.*/
-       if (mddev->delta_disks > 0) {
+               /* When a reshape changes the number of devices,
+                * ->degraded is measured against the larger of the
+                * pre and post number of devices.
+                */
                spin_lock_irqsave(&conf->device_lock, flags);
                mddev->degraded += (conf->raid_disks - conf->previous_raid_disks)
                        - added_devices;
index bc6a677..8c48521 100644 (file)
@@ -658,13 +658,13 @@ static int tda8290_probe(struct tuner_i2c_props *i2c_props)
 #define TDA8290_ID 0x89
        u8 reg = 0x1f, id;
        struct i2c_msg msg_read[] = {
-               { .addr = 0x4b, .flags = 0, .len = 1, .buf = &reg },
-               { .addr = 0x4b, .flags = I2C_M_RD, .len = 1, .buf = &id },
+               { .addr = i2c_props->addr, .flags = 0, .len = 1, .buf = &reg },
+               { .addr = i2c_props->addr, .flags = I2C_M_RD, .len = 1, .buf = &id },
        };
 
        /* detect tda8290 */
        if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) {
-               printk(KERN_WARNING "%s: tda8290 couldn't read register 0x%02x\n",
+               printk(KERN_WARNING "%s: couldn't read register 0x%02x\n",
                               __func__, reg);
                return -ENODEV;
        }
@@ -685,13 +685,13 @@ static int tda8295_probe(struct tuner_i2c_props *i2c_props)
 #define TDA8295C2_ID 0x8b
        u8 reg = 0x2f, id;
        struct i2c_msg msg_read[] = {
-               { .addr = 0x4b, .flags = 0, .len = 1, .buf = &reg },
-               { .addr = 0x4b, .flags = I2C_M_RD, .len = 1, .buf = &id },
+               { .addr = i2c_props->addr, .flags = 0, .len = 1, .buf = &reg },
+               { .addr = i2c_props->addr, .flags = I2C_M_RD, .len = 1, .buf = &id },
        };
 
-       /* detect tda8290 */
+       /* detect tda8295 */
        if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) {
-               printk(KERN_WARNING "%s: tda8290 couldn't read register 0x%02x\n",
+               printk(KERN_WARNING "%s: couldn't read register 0x%02x\n",
                               __func__, reg);
                return -ENODEV;
        }
index defd839..193cdb7 100644 (file)
@@ -870,6 +870,23 @@ static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap)
        return 0;
 }
 
+static int stk7700p_pid_filter(struct dvb_usb_adapter *adapter, int index,
+               u16 pid, int onoff)
+{
+       struct dib0700_state *st = adapter->dev->priv;
+       if (st->is_dib7000pc)
+               return dib7000p_pid_filter(adapter->fe, index, pid, onoff);
+       return dib7000m_pid_filter(adapter->fe, index, pid, onoff);
+}
+
+static int stk7700p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
+{
+       struct dib0700_state *st = adapter->dev->priv;
+       if (st->is_dib7000pc)
+               return dib7000p_pid_filter_ctrl(adapter->fe, onoff);
+       return dib7000m_pid_filter_ctrl(adapter->fe, onoff);
+}
+
 static int stk70x0p_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff)
 {
     return dib7000p_pid_filter(adapter->fe, index, pid, onoff);
@@ -1875,8 +1892,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        {
                                .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
                                .pid_filter_count = 32,
-                               .pid_filter       = stk70x0p_pid_filter,
-                               .pid_filter_ctrl  = stk70x0p_pid_filter_ctrl,
+                               .pid_filter       = stk7700p_pid_filter,
+                               .pid_filter_ctrl  = stk7700p_pid_filter_ctrl,
                                .frontend_attach  = stk7700p_frontend_attach,
                                .tuner_attach     = stk7700p_tuner_attach,
 
index 9eea418..46ccd01 100644 (file)
@@ -659,7 +659,7 @@ static int lme2510_download_firmware(struct usb_device *dev,
 }
 
 /* Default firmware for LME2510C */
-const char lme_firmware[50] = "dvb-usb-lme2510c-s7395.fw";
+char lme_firmware[50] = "dvb-usb-lme2510c-s7395.fw";
 
 static void lme_coldreset(struct usb_device *dev)
 {
@@ -1006,7 +1006,7 @@ static struct dvb_usb_device_properties lme2510c_properties = {
        .caps = DVB_USB_IS_AN_I2C_ADAPTER,
        .usb_ctrl = DEVICE_SPECIFIC,
        .download_firmware = lme2510_download_firmware,
-       .firmware = lme_firmware,
+       .firmware = (const char *)&lme_firmware,
        .size_of_priv = sizeof(struct lme2510_state),
        .num_adapters = 1,
        .adapter = {
@@ -1109,5 +1109,5 @@ module_exit(lme2510_module_exit);
 
 MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
 MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0");
-MODULE_VERSION("1.74");
+MODULE_VERSION("1.75");
 MODULE_LICENSE("GPL");
index c7f5ccf..289a798 100644 (file)
@@ -1285,6 +1285,25 @@ struct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *demod, enum di
 }
 EXPORT_SYMBOL(dib7000m_get_i2c_master);
 
+int dib7000m_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
+{
+       struct dib7000m_state *state = fe->demodulator_priv;
+       u16 val = dib7000m_read_word(state, 294 + state->reg_offs) & 0xffef;
+       val |= (onoff & 0x1) << 4;
+       dprintk("PID filter enabled %d", onoff);
+       return dib7000m_write_word(state, 294 + state->reg_offs, val);
+}
+EXPORT_SYMBOL(dib7000m_pid_filter_ctrl);
+
+int dib7000m_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
+{
+       struct dib7000m_state *state = fe->demodulator_priv;
+       dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
+       return dib7000m_write_word(state, 300 + state->reg_offs + id,
+                       onoff ? (1 << 13) | pid : 0);
+}
+EXPORT_SYMBOL(dib7000m_pid_filter);
+
 #if 0
 /* used with some prototype boards */
 int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods,
index 113819c..81fcf22 100644 (file)
@@ -46,6 +46,8 @@ extern struct dvb_frontend *dib7000m_attach(struct i2c_adapter *i2c_adap,
 extern struct i2c_adapter *dib7000m_get_i2c_master(struct dvb_frontend *,
                                                   enum dibx000_i2c_interface,
                                                   int);
+extern int dib7000m_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff);
+extern int dib7000m_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff);
 #else
 static inline
 struct dvb_frontend *dib7000m_attach(struct i2c_adapter *i2c_adap,
@@ -63,6 +65,19 @@ struct i2c_adapter *dib7000m_get_i2c_master(struct dvb_frontend *demod,
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
 }
+static inline int dib7000m_pid_filter(struct dvb_frontend *fe, u8 id,
+                                               u16 pid, u8 onoff)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
+
+static inline int dib7000m_pid_filter_ctrl(struct dvb_frontend *fe,
+                                               uint8_t onoff)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return -ENODEV;
+}
 #endif
 
 /* TODO
index 59feeb8..10a432a 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <asm/io.h>
-#include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/kmod.h>
 #include <linux/vmalloc.h>
index f011c5d..1c5cc65 100644 (file)
@@ -1,4 +1,4 @@
-/* ir-lirc-codec.c - ir-core to classic lirc interface bridge
+/* ir-lirc-codec.c - rc-core to classic lirc interface bridge
  *
  * Copyright (C) 2010 by Jarod Wilson <jarod@redhat.com>
  *
@@ -47,6 +47,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
        /* Carrier reports */
        if (ev.carrier_report) {
                sample = LIRC_FREQUENCY(ev.carrier);
+               IR_dprintk(2, "carrier report (freq: %d)\n", sample);
 
        /* Packet end */
        } else if (ev.timeout) {
@@ -62,6 +63,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
                        return 0;
 
                sample = LIRC_TIMEOUT(ev.duration / 1000);
+               IR_dprintk(2, "timeout report (duration: %d)\n", sample);
 
        /* Normal sample */
        } else {
@@ -85,6 +87,8 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
 
                sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) :
                                        LIRC_SPACE(ev.duration / 1000);
+               IR_dprintk(2, "delivering %uus %s to lirc_dev\n",
+                          TO_US(ev.duration), TO_STR(ev.pulse));
        }
 
        lirc_buffer_write(dev->raw->lirc.drv->rbuf,
index 73230ff..01f258a 100644 (file)
@@ -112,7 +112,7 @@ int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type)
 {
        ktime_t                 now;
        s64                     delta; /* ns */
-       struct ir_raw_event     ev;
+       DEFINE_IR_RAW_EVENT(ev);
        int                     rc = 0;
 
        if (!dev->raw)
@@ -125,7 +125,6 @@ int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type)
         * being called for the first time, note that delta can't
         * possibly be negative.
         */
-       ev.duration = 0;
        if (delta > IR_MAX_DURATION || !dev->raw->last_type)
                type |= IR_START_EVENT;
        else
index 3bf3337..2f5dc06 100644 (file)
@@ -3,6 +3,9 @@
  *
  * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
  *
+ * See http://mediacenterguides.com/book/export/html/31 for details on
+ * key mappings.
+ *
  * 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
@@ -60,6 +63,9 @@ static struct rc_map_table rc6_mce[] = {
        { 0x800f0426, KEY_EPG },                /* Guide */
        { 0x800f0427, KEY_ZOOM },               /* Aspect */
 
+       { 0x800f0432, KEY_MODE },               /* Visualization */
+       { 0x800f0433, KEY_PRESENTATION },       /* Slide Show */
+       { 0x800f0434, KEY_EJECTCD },
        { 0x800f043a, KEY_BRIGHTNESSUP },
 
        { 0x800f0446, KEY_TV },
index 079353e..e4f8eac 100644 (file)
@@ -148,6 +148,7 @@ enum mceusb_model_type {
        MCE_GEN2_TX_INV,
        POLARIS_EVK,
        CX_HYBRID_TV,
+       MULTIFUNCTION,
 };
 
 struct mceusb_model {
@@ -155,9 +156,10 @@ struct mceusb_model {
        u32 mce_gen2:1;
        u32 mce_gen3:1;
        u32 tx_mask_normal:1;
-       u32 is_polaris:1;
        u32 no_tx:1;
 
+       int ir_intfnum;
+
        const char *rc_map;     /* Allow specify a per-board map */
        const char *name;       /* per-board name */
 };
@@ -179,7 +181,6 @@ static const struct mceusb_model mceusb_model[] = {
                .tx_mask_normal = 1,
        },
        [POLARIS_EVK] = {
-               .is_polaris = 1,
                /*
                 * In fact, the EVK is shipped without
                 * remotes, but we should have something handy,
@@ -189,10 +190,13 @@ static const struct mceusb_model mceusb_model[] = {
                .name = "Conexant Hybrid TV (cx231xx) MCE IR",
        },
        [CX_HYBRID_TV] = {
-               .is_polaris = 1,
                .no_tx = 1, /* tx isn't wired up at all */
                .name = "Conexant Hybrid TV (cx231xx) MCE IR",
        },
+       [MULTIFUNCTION] = {
+               .mce_gen2 = 1,
+               .ir_intfnum = 2,
+       },
 };
 
 static struct usb_device_id mceusb_dev_table[] = {
@@ -216,8 +220,9 @@ static struct usb_device_id mceusb_dev_table[] = {
        { USB_DEVICE(VENDOR_PHILIPS, 0x206c) },
        /* Philips/Spinel plus IR transceiver for ASUS */
        { USB_DEVICE(VENDOR_PHILIPS, 0x2088) },
-       /* Realtek MCE IR Receiver */
-       { USB_DEVICE(VENDOR_REALTEK, 0x0161) },
+       /* Realtek MCE IR Receiver and card reader */
+       { USB_DEVICE(VENDOR_REALTEK, 0x0161),
+         .driver_info = MULTIFUNCTION },
        /* SMK/Toshiba G83C0004D410 */
        { USB_DEVICE(VENDOR_SMK, 0x031d),
          .driver_info = MCE_GEN2_TX_INV },
@@ -816,7 +821,7 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index)
        switch (ir->buf_in[index]) {
        /* 2-byte return value commands */
        case MCE_CMD_S_TIMEOUT:
-               ir->rc->timeout = MS_TO_NS((hi << 8 | lo) / 2);
+               ir->rc->timeout = US_TO_NS((hi << 8 | lo) / 2);
                break;
 
        /* 1-byte return value commands */
@@ -855,9 +860,10 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
                        break;
                case PARSE_IRDATA:
                        ir->rem--;
+                       init_ir_raw_event(&rawir);
                        rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0);
                        rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK)
-                                        * MS_TO_US(MCE_TIME_UNIT);
+                                        * US_TO_NS(MCE_TIME_UNIT);
 
                        dev_dbg(ir->dev, "Storing %s with duration %d\n",
                                rawir.pulse ? "pulse" : "space",
@@ -883,6 +889,8 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
                                             i, ir->rem + 1, false);
                        if (ir->rem)
                                ir->parser_state = PARSE_IRDATA;
+                       else
+                               ir_raw_event_reset(ir->rc);
                        break;
                }
 
@@ -1060,7 +1068,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
        rc->priv = ir;
        rc->driver_type = RC_DRIVER_IR_RAW;
        rc->allowed_protos = RC_TYPE_ALL;
-       rc->timeout = MS_TO_NS(1000);
+       rc->timeout = US_TO_NS(1000);
        if (!ir->flags.no_tx) {
                rc->s_tx_mask = mceusb_set_tx_mask;
                rc->s_tx_carrier = mceusb_set_tx_carrier;
@@ -1098,7 +1106,7 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
        bool is_gen3;
        bool is_microsoft_gen1;
        bool tx_mask_normal;
-       bool is_polaris;
+       int ir_intfnum;
 
        dev_dbg(&intf->dev, "%s called\n", __func__);
 
@@ -1107,13 +1115,11 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
        is_gen3 = mceusb_model[model].mce_gen3;
        is_microsoft_gen1 = mceusb_model[model].mce_gen1;
        tx_mask_normal = mceusb_model[model].tx_mask_normal;
-       is_polaris = mceusb_model[model].is_polaris;
+       ir_intfnum = mceusb_model[model].ir_intfnum;
 
-       if (is_polaris) {
-               /* Interface 0 is IR */
-               if (idesc->desc.bInterfaceNumber)
-                       return -ENODEV;
-       }
+       /* There are multi-function devices with non-IR interfaces */
+       if (idesc->desc.bInterfaceNumber != ir_intfnum)
+               return -ENODEV;
 
        /* step through the endpoints to find first bulk in and out endpoint */
        for (i = 0; i < idesc->desc.bNumEndpoints; ++i) {
index dd4caf8..d4d6449 100644 (file)
@@ -385,8 +385,9 @@ static void nvt_cir_regs_init(struct nvt_dev *nvt)
 
 static void nvt_cir_wake_regs_init(struct nvt_dev *nvt)
 {
-       /* set number of bytes needed for wake key comparison (default 67) */
-       nvt_cir_wake_reg_write(nvt, CIR_WAKE_FIFO_LEN, CIR_WAKE_FIFO_CMP_DEEP);
+       /* set number of bytes needed for wake from s3 (default 65) */
+       nvt_cir_wake_reg_write(nvt, CIR_WAKE_FIFO_CMP_BYTES,
+                              CIR_WAKE_FIFO_CMP_DEEP);
 
        /* set tolerance/variance allowed per byte during wake compare */
        nvt_cir_wake_reg_write(nvt, CIR_WAKE_CMP_TOLERANCE,
@@ -460,7 +461,7 @@ static u32 nvt_rx_carrier_detect(struct nvt_dev *nvt)
                return 0;
        }
 
-       carrier = (count * 1000000) / duration;
+       carrier = MS_TO_NS(count) / duration;
 
        if ((carrier > MAX_CARRIER) || (carrier < MIN_CARRIER))
                nvt_dbg("WTF? Carrier frequency out of range!");
@@ -612,8 +613,8 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
                sample = nvt->buf[i];
 
                rawir.pulse = ((sample & BUF_PULSE_BIT) != 0);
-               rawir.duration = (sample & BUF_LEN_MASK)
-                                       * SAMPLE_PERIOD * 1000;
+               rawir.duration = US_TO_NS((sample & BUF_LEN_MASK)
+                                         * SAMPLE_PERIOD);
 
                if ((sample & BUF_LEN_MASK) == BUF_LEN_MASK) {
                        if (nvt->rawir.pulse == rawir.pulse)
index 1df8235..048135e 100644 (file)
@@ -305,8 +305,11 @@ struct nvt_dev {
 #define CIR_WAKE_IRFIFOSTS_RX_EMPTY    0x20
 #define CIR_WAKE_IRFIFOSTS_RX_FULL     0x10
 
-/* CIR Wake FIFO buffer is 67 bytes long */
-#define CIR_WAKE_FIFO_LEN              67
+/*
+ * The CIR Wake FIFO buffer is 67 bytes long, but the stock remote wakes
+ * the system comparing only 65 bytes (fails with this set to 67)
+ */
+#define CIR_WAKE_FIFO_CMP_BYTES                65
 /* CIR Wake byte comparison tolerance */
 #define CIR_WAKE_CMP_TOLERANCE         5
 
index 72be8a0..5b4422e 100644 (file)
@@ -458,21 +458,27 @@ static int ir_getkeycode(struct input_dev *idev,
                index = ir_lookup_by_scancode(rc_map, scancode);
        }
 
-       if (index >= rc_map->len) {
-               if (!(ke->flags & INPUT_KEYMAP_BY_INDEX))
-                       IR_dprintk(1, "unknown key for scancode 0x%04x\n",
-                                  scancode);
+       if (index < rc_map->len) {
+               entry = &rc_map->scan[index];
+
+               ke->index = index;
+               ke->keycode = entry->keycode;
+               ke->len = sizeof(entry->scancode);
+               memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode));
+
+       } else if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) {
+               /*
+                * We do not really know the valid range of scancodes
+                * so let's respond with KEY_RESERVED to anything we
+                * do not have mapping for [yet].
+                */
+               ke->index = index;
+               ke->keycode = KEY_RESERVED;
+       } else {
                retval = -EINVAL;
                goto out;
        }
 
-       entry = &rc_map->scan[index];
-
-       ke->index = index;
-       ke->keycode = entry->keycode;
-       ke->len = sizeof(entry->scancode);
-       memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode));
-
        retval = 0;
 
 out:
@@ -844,7 +850,7 @@ static ssize_t store_protocols(struct device *device,
                        count++;
                } else {
                        for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
-                               if (!strncasecmp(tmp, proto_names[i].name, strlen(proto_names[i].name))) {
+                               if (!strcasecmp(tmp, proto_names[i].name)) {
                                        tmp += strlen(proto_names[i].name);
                                        mask = proto_names[i].type;
                                        break;
index 6e2911c..e435d94 100644 (file)
@@ -164,7 +164,7 @@ static void sz_push_full_pulse(struct streamzap_ir *sz,
                                sz->signal_start.tv_usec -
                                sz->signal_last.tv_usec);
                        rawir.duration -= sz->sum;
-                       rawir.duration *= 1000;
+                       rawir.duration = US_TO_NS(rawir.duration);
                        rawir.duration &= IR_MAX_DURATION;
                }
                sz_push(sz, rawir);
@@ -177,7 +177,7 @@ static void sz_push_full_pulse(struct streamzap_ir *sz,
        rawir.duration = ((int) value) * SZ_RESOLUTION;
        rawir.duration += SZ_RESOLUTION / 2;
        sz->sum += rawir.duration;
-       rawir.duration *= 1000;
+       rawir.duration = US_TO_NS(rawir.duration);
        rawir.duration &= IR_MAX_DURATION;
        sz_push(sz, rawir);
 }
@@ -197,7 +197,7 @@ static void sz_push_full_space(struct streamzap_ir *sz,
        rawir.duration = ((int) value) * SZ_RESOLUTION;
        rawir.duration += SZ_RESOLUTION / 2;
        sz->sum += rawir.duration;
-       rawir.duration *= 1000;
+       rawir.duration = US_TO_NS(rawir.duration);
        sz_push(sz, rawir);
 }
 
@@ -273,6 +273,7 @@ static void streamzap_callback(struct urb *urb)
                                if (sz->timeout_enabled)
                                        sz_push(sz, rawir);
                                ir_raw_event_handle(sz->rdev);
+                               ir_raw_event_reset(sz->rdev);
                        } else {
                                sz_push_full_space(sz, sz->buf_in[i]);
                        }
@@ -290,6 +291,7 @@ static void streamzap_callback(struct urb *urb)
                }
        }
 
+       ir_raw_event_handle(sz->rdev);
        usb_submit_urb(urb, GFP_ATOMIC);
 
        return;
@@ -430,13 +432,13 @@ static int __devinit streamzap_probe(struct usb_interface *intf,
        sz->decoder_state = PulseSpace;
        /* FIXME: don't yet have a way to set this */
        sz->timeout_enabled = true;
-       sz->rdev->timeout = (((SZ_TIMEOUT * SZ_RESOLUTION * 1000) &
+       sz->rdev->timeout = ((US_TO_NS(SZ_TIMEOUT * SZ_RESOLUTION) &
                                IR_MAX_DURATION) | 0x03000000);
        #if 0
        /* not yet supported, depends on patches from maxim */
        /* see also: LIRC_GET_REC_RESOLUTION and LIRC_SET_REC_TIMEOUT */
-       sz->min_timeout = SZ_TIMEOUT * SZ_RESOLUTION * 1000;
-       sz->max_timeout = SZ_TIMEOUT * SZ_RESOLUTION * 1000;
+       sz->min_timeout = US_TO_NS(SZ_TIMEOUT * SZ_RESOLUTION);
+       sz->max_timeout = US_TO_NS(SZ_TIMEOUT * SZ_RESOLUTION);
        #endif
 
        do_gettimeofday(&sz->signal_start);
index e41e4ad..9c475c6 100644 (file)
@@ -1758,7 +1758,12 @@ static int vidioc_reqbufs(struct file *file, void *priv,
        if (rc < 0)
                return rc;
 
-       return videobuf_reqbufs(&fh->vb_vidq, rb);
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               rc = videobuf_reqbufs(&fh->vb_vidq, rb);
+       else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               rc = videobuf_reqbufs(&fh->vb_vbiq, rb);
+
+       return rc;
 }
 
 static int vidioc_querybuf(struct file *file, void *priv,
@@ -1772,7 +1777,12 @@ static int vidioc_querybuf(struct file *file, void *priv,
        if (rc < 0)
                return rc;
 
-       return videobuf_querybuf(&fh->vb_vidq, b);
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               rc = videobuf_querybuf(&fh->vb_vidq, b);
+       else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               rc = videobuf_querybuf(&fh->vb_vbiq, b);
+
+       return rc;
 }
 
 static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
@@ -1785,7 +1795,12 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
        if (rc < 0)
                return rc;
 
-       return videobuf_qbuf(&fh->vb_vidq, b);
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               rc = videobuf_qbuf(&fh->vb_vidq, b);
+       else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               rc = videobuf_qbuf(&fh->vb_vbiq, b);
+
+       return rc;
 }
 
 static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
@@ -1806,7 +1821,12 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
                dev->greenscreen_detected = 0;
        }
 
-       return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               rc = videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
+       else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               rc = videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags & O_NONBLOCK);
+
+       return rc;
 }
 
 static struct v4l2_file_operations au0828_v4l_fops = {
index 8717773..68ad196 100644 (file)
@@ -95,6 +95,53 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
        .i2c = &cx18_i2c_std,
 };
 
+static const struct cx18_card cx18_card_hvr1600_s5h1411 = {
+       .type = CX18_CARD_HVR_1600_S5H1411,
+       .name = "Hauppauge HVR-1600",
+       .comment = "Simultaneous Digital and Analog TV capture supported\n",
+       .v4l2_capabilities = CX18_CAP_ENCODER,
+       .hw_audio_ctrl = CX18_HW_418_AV,
+       .hw_muxer = CX18_HW_CS5345,
+       .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
+                 CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL |
+                 CX18_HW_Z8F0811_IR_HAUP,
+       .video_inputs = {
+               { CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE7 },
+               { CX18_CARD_INPUT_SVIDEO1,    1, CX18_AV_SVIDEO1    },
+               { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 },
+               { CX18_CARD_INPUT_SVIDEO2,    2, CX18_AV_SVIDEO2    },
+               { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE4 },
+       },
+       .audio_inputs = {
+               { CX18_CARD_INPUT_AUD_TUNER,
+                 CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
+               { CX18_CARD_INPUT_LINE_IN1,
+                 CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 },
+               { CX18_CARD_INPUT_LINE_IN2,
+                 CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 },
+       },
+       .radio_input = { CX18_CARD_INPUT_AUD_TUNER,
+                        CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 },
+       .ddr = {
+               /* ESMT M13S128324A-5B memory */
+               .chip_config = 0x003,
+               .refresh = 0x30c,
+               .timing1 = 0x44220e82,
+               .timing2 = 0x08,
+               .tune_lane = 0,
+               .initial_emrs = 0,
+       },
+       .gpio_init.initial_value = 0x3001,
+       .gpio_init.direction = 0x3001,
+       .gpio_i2c_slave_reset = {
+               .active_lo_mask = 0x3001,
+               .msecs_asserted = 10,
+               .msecs_recovery = 40,
+               .ir_reset_mask  = 0x0001,
+       },
+       .i2c = &cx18_i2c_std,
+};
+
 static const struct cx18_card cx18_card_hvr1600_samsung = {
        .type = CX18_CARD_HVR_1600_SAMSUNG,
        .name = "Hauppauge HVR-1600 (Preproduction)",
@@ -523,7 +570,8 @@ static const struct cx18_card *cx18_card_list[] = {
        &cx18_card_toshiba_qosmio_dvbt,
        &cx18_card_leadtek_pvr2100,
        &cx18_card_leadtek_dvr3100h,
-       &cx18_card_gotview_dvd3
+       &cx18_card_gotview_dvd3,
+       &cx18_card_hvr1600_s5h1411
 };
 
 const struct cx18_card *cx18_get_card(u16 index)
index 944af8a..b1c3cbd 100644 (file)
@@ -157,6 +157,7 @@ MODULE_PARM_DESC(cardtype,
                 "\t\t\t 7 = Leadtek WinFast PVR2100\n"
                 "\t\t\t 8 = Leadtek WinFast DVR3100 H\n"
                 "\t\t\t 9 = GoTView PCI DVD3 Hybrid\n"
+                "\t\t\t 10 = Hauppauge HVR 1600 (S5H1411)\n"
                 "\t\t\t 0 = Autodetect (default)\n"
                 "\t\t\t-1 = Ignore this card\n\t\t");
 MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
@@ -337,6 +338,7 @@ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
        switch (cx->card->type) {
        case CX18_CARD_HVR_1600_ESMT:
        case CX18_CARD_HVR_1600_SAMSUNG:
+       case CX18_CARD_HVR_1600_S5H1411:
                tveeprom_hauppauge_analog(&c, tv, eedata);
                break;
        case CX18_CARD_YUAN_MPC718:
@@ -365,7 +367,25 @@ static void cx18_process_eeprom(struct cx18 *cx)
           from the model number. Use the cardtype module option if you
           have one of these preproduction models. */
        switch (tv.model) {
-       case 74000 ... 74999:
+       case 74301: /* Retail models */
+       case 74321:
+       case 74351: /* OEM models */
+       case 74361:
+               /* Digital side is s5h1411/tda18271 */
+               cx->card = cx18_get_card(CX18_CARD_HVR_1600_S5H1411);
+               break;
+       case 74021: /* Retail models */
+       case 74031:
+       case 74041:
+       case 74141:
+       case 74541: /* OEM models */
+       case 74551:
+       case 74591:
+       case 74651:
+       case 74691:
+       case 74751:
+       case 74891:
+               /* Digital side is s5h1409/mxl5005s */
                cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
                break;
        case 0x718:
@@ -377,7 +397,8 @@ static void cx18_process_eeprom(struct cx18 *cx)
                CX18_ERR("Invalid EEPROM\n");
                return;
        default:
-               CX18_ERR("Unknown model %d, defaulting to HVR-1600\n", tv.model);
+               CX18_ERR("Unknown model %d, defaulting to original HVR-1600 "
+                        "(cardtype=1)\n", tv.model);
                cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
                break;
        }
index 306caac..f736679 100644 (file)
@@ -85,7 +85,8 @@
 #define CX18_CARD_LEADTEK_PVR2100     6 /* Leadtek WinFast PVR2100 */
 #define CX18_CARD_LEADTEK_DVR3100H    7 /* Leadtek WinFast DVR3100 H */
 #define CX18_CARD_GOTVIEW_PCI_DVD3    8 /* GoTView PCI DVD3 Hybrid */
-#define CX18_CARD_LAST               8
+#define CX18_CARD_HVR_1600_S5H1411    9 /* Hauppauge HVR 1600 s5h1411/tda18271*/
+#define CX18_CARD_LAST               9
 
 #define CX18_ENC_STREAM_TYPE_MPG  0
 #define CX18_ENC_STREAM_TYPE_TS   1
index f0381d6..f41922b 100644 (file)
@@ -29,6 +29,8 @@
 #include "cx18-gpio.h"
 #include "s5h1409.h"
 #include "mxl5005s.h"
+#include "s5h1411.h"
+#include "tda18271.h"
 #include "zl10353.h"
 
 #include <linux/firmware.h>
@@ -76,6 +78,32 @@ static struct s5h1409_config hauppauge_hvr1600_config = {
        .hvr1600_opt   = S5H1409_HVR1600_OPTIMIZE
 };
 
+/*
+ * CX18_CARD_HVR_1600_S5H1411
+ */
+static struct s5h1411_config hcw_s5h1411_config = {
+       .output_mode   = S5H1411_SERIAL_OUTPUT,
+       .gpio          = S5H1411_GPIO_OFF,
+       .vsb_if        = S5H1411_IF_44000,
+       .qam_if        = S5H1411_IF_4000,
+       .inversion     = S5H1411_INVERSION_ON,
+       .status_mode   = S5H1411_DEMODLOCKING,
+       .mpeg_timing   = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct tda18271_std_map hauppauge_tda18271_std_map = {
+       .atsc_6   = { .if_freq = 5380, .agc_mode = 3, .std = 3,
+                     .if_lvl = 6, .rfagc_top = 0x37 },
+       .qam_6    = { .if_freq = 4000, .agc_mode = 3, .std = 0,
+                     .if_lvl = 6, .rfagc_top = 0x37 },
+};
+
+static struct tda18271_config hauppauge_tda18271_config = {
+       .std_map = &hauppauge_tda18271_std_map,
+       .gate    = TDA18271_GATE_DIGITAL,
+       .output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
 /*
  * CX18_CARD_LEADTEK_DVR3100H
  */
@@ -244,6 +272,7 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
        switch (cx->card->type) {
        case CX18_CARD_HVR_1600_ESMT:
        case CX18_CARD_HVR_1600_SAMSUNG:
+       case CX18_CARD_HVR_1600_S5H1411:
                v = cx18_read_reg(cx, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
                v |= 0x00400000; /* Serial Mode */
                v |= 0x00002000; /* Data Length - Byte */
@@ -455,6 +484,15 @@ static int dvb_register(struct cx18_stream *stream)
                        ret = 0;
                }
                break;
+       case CX18_CARD_HVR_1600_S5H1411:
+               dvb->fe = dvb_attach(s5h1411_attach,
+                                    &hcw_s5h1411_config,
+                                    &cx->i2c_adap[0]);
+               if (dvb->fe != NULL)
+                       dvb_attach(tda18271_attach, dvb->fe,
+                                  0x60, &cx->i2c_adap[0],
+                                  &hauppauge_tda18271_config);
+               break;
        case CX18_CARD_LEADTEK_DVR3100H:
                dvb->fe = dvb_attach(zl10353_attach,
                                     &leadtek_dvr3100h_demod,
index ed3d8f5..307ff54 100644 (file)
@@ -122,10 +122,6 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
 
        if (!i2c_wait_done(i2c_adap))
                goto eio;
-       if (!i2c_slave_did_ack(i2c_adap)) {
-               retval = -ENXIO;
-               goto err;
-       }
        if (i2c_debug) {
                printk(" <W %02x %02x", msg->addr << 1, msg->buf[0]);
                if (!(ctrl & I2C_NOSTOP))
@@ -158,7 +154,6 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
 
  eio:
        retval = -EIO;
- err:
        if (i2c_debug)
                printk(KERN_ERR " ERR: %d\n", retval);
        return retval;
@@ -209,10 +204,6 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
 
                if (!i2c_wait_done(i2c_adap))
                        goto eio;
-               if (cnt == 0 && !i2c_slave_did_ack(i2c_adap)) {
-                       retval = -ENXIO;
-                       goto err;
-               }
                msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff;
                if (i2c_debug) {
                        dprintk(1, " %02x", msg->buf[cnt]);
@@ -224,7 +215,6 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
 
  eio:
        retval = -EIO;
- err:
        if (i2c_debug)
                printk(KERN_ERR " ERR: %d\n", retval);
        return retval;
index 6fc09dd..35796e0 100644 (file)
@@ -2015,7 +2015,8 @@ static int cx25840_probe(struct i2c_client *client,
                kfree(state);
                return err;
        }
-       v4l2_ctrl_cluster(2, &state->volume);
+       if (!is_cx2583x(state))
+               v4l2_ctrl_cluster(2, &state->volume);
        v4l2_ctrl_handler_setup(&state->hdl);
 
        if (client->dev.platform_data) {
index 865216e..47236a5 100644 (file)
@@ -5793,7 +5793,7 @@ static void usb_exchange(struct gspca_dev *gspca_dev,
                        break;
                default:
 /*             case 0xdd:       * delay */
-                       msleep(action->val / 64 + 10);
+                       msleep(action->idx);
                        break;
                }
                action++;
@@ -5830,7 +5830,7 @@ static void setmatrix(struct gspca_dev *gspca_dev)
                [SENSOR_GC0305] =       gc0305_matrix,
                [SENSOR_HDCS2020b] =    NULL,
                [SENSOR_HV7131B] =      NULL,
-               [SENSOR_HV7131R] =      NULL,
+               [SENSOR_HV7131R] =      po2030_matrix,
                [SENSOR_ICM105A] =      po2030_matrix,
                [SENSOR_MC501CB] =      NULL,
                [SENSOR_MT9V111_1] =    gc0305_matrix,
@@ -5936,6 +5936,7 @@ static void setquality(struct gspca_dev *gspca_dev)
        case SENSOR_ADCM2700:
        case SENSOR_GC0305:
        case SENSOR_HV7131B:
+       case SENSOR_HV7131R:
        case SENSOR_OV7620:
        case SENSOR_PAS202B:
        case SENSOR_PO2030:
@@ -6108,11 +6109,13 @@ static void send_unknown(struct gspca_dev *gspca_dev, int sensor)
                reg_w(gspca_dev, 0x02, 0x003b);
                reg_w(gspca_dev, 0x00, 0x0038);
                break;
+       case SENSOR_HV7131R:
        case SENSOR_PAS202B:
                reg_w(gspca_dev, 0x03, 0x003b);
                reg_w(gspca_dev, 0x0c, 0x003a);
                reg_w(gspca_dev, 0x0b, 0x0039);
-               reg_w(gspca_dev, 0x0b, 0x0038);
+               if (sensor == SENSOR_PAS202B)
+                       reg_w(gspca_dev, 0x0b, 0x0038);
                break;
        }
 }
@@ -6704,10 +6707,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
                reg_w(gspca_dev, 0x02, 0x003b);
                reg_w(gspca_dev, 0x00, 0x0038);
                break;
+       case SENSOR_HV7131R:
        case SENSOR_PAS202B:
                reg_w(gspca_dev, 0x03, 0x003b);
                reg_w(gspca_dev, 0x0c, 0x003a);
                reg_w(gspca_dev, 0x0b, 0x0039);
+               if (sd->sensor == SENSOR_HV7131R)
+                       reg_w(gspca_dev, 0x50, ZC3XX_R11D_GLOBALGAIN);
                break;
        }
 
@@ -6720,6 +6726,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                break;
        case SENSOR_PAS202B:
        case SENSOR_GC0305:
+       case SENSOR_HV7131R:
        case SENSOR_TAS5130C:
                reg_r(gspca_dev, 0x0008);
                /* fall thru */
@@ -6760,6 +6767,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
                                                /* ms-win + */
                reg_w(gspca_dev, 0x40, 0x0117);
                break;
+       case SENSOR_HV7131R:
+               i2c_write(gspca_dev, 0x25, 0x04, 0x00); /* exposure */
+               i2c_write(gspca_dev, 0x26, 0x93, 0x00);
+               i2c_write(gspca_dev, 0x27, 0xe0, 0x00);
+               reg_w(gspca_dev, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN);
+               break;
        case SENSOR_GC0305:
        case SENSOR_TAS5130C:
                reg_w(gspca_dev, 0x09, 0x01ad); /* (from win traces) */
@@ -6808,9 +6821,17 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       if (data[0] == 0xff && data[1] == 0xd8) {       /* start of frame */
+       /* check the JPEG end of frame */
+       if (len >= 3
+        && data[len - 3] == 0xff && data[len - 2] == 0xd9) {
+/*fixme: what does the last byte mean?*/
                gspca_frame_add(gspca_dev, LAST_PACKET,
-                                       NULL, 0);
+                                       data, len - 1);
+               return;
+       }
+
+       /* check the JPEG start of a frame */
+       if (data[0] == 0xff && data[1] == 0xd8) {
                /* put the JPEG header in the new frame */
                gspca_frame_add(gspca_dev, FIRST_PACKET,
                        sd->jpeg_hdr, JPEG_HDR_SZ);
index a6572e5..a27d93b 100644 (file)
@@ -283,6 +283,7 @@ static int hdpvr_probe(struct usb_interface *interface,
        struct hdpvr_device *dev;
        struct usb_host_interface *iface_desc;
        struct usb_endpoint_descriptor *endpoint;
+       struct i2c_client *client;
        size_t buffer_size;
        int i;
        int retval = -ENOMEM;
@@ -381,13 +382,21 @@ static int hdpvr_probe(struct usb_interface *interface,
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        retval = hdpvr_register_i2c_adapter(dev);
        if (retval < 0) {
-               v4l2_err(&dev->v4l2_dev, "registering i2c adapter failed\n");
+               v4l2_err(&dev->v4l2_dev, "i2c adapter register failed\n");
                goto error;
        }
 
-       retval = hdpvr_register_i2c_ir(dev);
-       if (retval < 0)
-               v4l2_err(&dev->v4l2_dev, "registering i2c IR devices failed\n");
+       client = hdpvr_register_ir_rx_i2c(dev);
+       if (!client) {
+               v4l2_err(&dev->v4l2_dev, "i2c IR RX device register failed\n");
+               goto reg_fail;
+       }
+
+       client = hdpvr_register_ir_tx_i2c(dev);
+       if (!client) {
+               v4l2_err(&dev->v4l2_dev, "i2c IR TX device register failed\n");
+               goto reg_fail;
+       }
 #endif
 
        /* let the user know what node this device is now attached to */
@@ -395,6 +404,10 @@ static int hdpvr_probe(struct usb_interface *interface,
                  video_device_node_name(dev->video_dev));
        return 0;
 
+reg_fail:
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_adapter(&dev->i2c_adapter);
+#endif
 error:
        if (dev) {
                /* Destroy single thread */
@@ -424,6 +437,9 @@ static void hdpvr_disconnect(struct usb_interface *interface)
        mutex_lock(&dev->io_mutex);
        hdpvr_cancel_queue(dev);
        mutex_unlock(&dev->io_mutex);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_adapter(&dev->i2c_adapter);
+#endif
        video_unregister_device(dev->video_dev);
        atomic_dec(&dev_nr);
 }
index 89b71fa..e53fa55 100644 (file)
 #define Z8F0811_IR_RX_I2C_ADDR 0x71
 
 
-static struct i2c_board_info hdpvr_i2c_board_info = {
-       I2C_BOARD_INFO("ir_tx_z8f0811_hdpvr", Z8F0811_IR_TX_I2C_ADDR),
-       I2C_BOARD_INFO("ir_rx_z8f0811_hdpvr", Z8F0811_IR_RX_I2C_ADDR),
-};
+struct i2c_client *hdpvr_register_ir_tx_i2c(struct hdpvr_device *dev)
+{
+       struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data;
+       struct i2c_board_info hdpvr_ir_tx_i2c_board_info = {
+               I2C_BOARD_INFO("ir_tx_z8f0811_hdpvr", Z8F0811_IR_TX_I2C_ADDR),
+       };
+
+       init_data->name = "HD-PVR";
+       hdpvr_ir_tx_i2c_board_info.platform_data = init_data;
 
-int hdpvr_register_i2c_ir(struct hdpvr_device *dev)
+       return i2c_new_device(&dev->i2c_adapter, &hdpvr_ir_tx_i2c_board_info);
+}
+
+struct i2c_client *hdpvr_register_ir_rx_i2c(struct hdpvr_device *dev)
 {
-       struct i2c_client *c;
        struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data;
+       struct i2c_board_info hdpvr_ir_rx_i2c_board_info = {
+               I2C_BOARD_INFO("ir_rx_z8f0811_hdpvr", Z8F0811_IR_RX_I2C_ADDR),
+       };
 
        /* Our default information for ir-kbd-i2c.c to use */
        init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW;
        init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
        init_data->type = RC_TYPE_RC5;
-       init_data->name = "HD PVR";
-       hdpvr_i2c_board_info.platform_data = init_data;
-
-       c = i2c_new_device(&dev->i2c_adapter, &hdpvr_i2c_board_info);
+       init_data->name = "HD-PVR";
+       hdpvr_ir_rx_i2c_board_info.platform_data = init_data;
 
-       return (c == NULL) ? -ENODEV : 0;
+       return i2c_new_device(&dev->i2c_adapter, &hdpvr_ir_rx_i2c_board_info);
 }
 
 static int hdpvr_i2c_read(struct hdpvr_device *dev, int bus,
index ee74e3b..072f23c 100644 (file)
@@ -313,7 +313,8 @@ int hdpvr_cancel_queue(struct hdpvr_device *dev);
 /* i2c adapter registration */
 int hdpvr_register_i2c_adapter(struct hdpvr_device *dev);
 
-int hdpvr_register_i2c_ir(struct hdpvr_device *dev);
+struct i2c_client *hdpvr_register_ir_rx_i2c(struct hdpvr_device *dev);
+struct i2c_client *hdpvr_register_ir_tx_i2c(struct hdpvr_device *dev);
 
 /*========================================================================*/
 /* buffer management */
index d2b20ad..a221ad6 100644 (file)
@@ -128,6 +128,19 @@ static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 
 static int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
+       int ret;
+       unsigned char buf[1] = { 0 };
+
+       /*
+        * This is the same apparent "are you ready?" poll command observed
+        * watching Windows driver traffic and implemented in lirc_zilog. With
+        * this added, we get far saner remote behavior with z8 chips on usb
+        * connected devices, even with the default polling interval of 100ms.
+        */
+       ret = i2c_master_send(ir->c, buf, 1);
+       if (ret != 1)
+               return (ret < 0) ? ret : -EINVAL;
+
        return get_key_haup_common (ir, ir_key, ir_raw, 6, 3);
 }
 
index 9b4faf0..9c29e96 100644 (file)
@@ -628,22 +628,66 @@ static void ivtv_irq_enc_pio_complete(struct ivtv *itv)
 static void ivtv_irq_dma_err(struct ivtv *itv)
 {
        u32 data[CX2341X_MBOX_MAX_DATA];
+       u32 status;
 
        del_timer(&itv->dma_timer);
+
        ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, 2, data);
+       status = read_reg(IVTV_REG_DMASTATUS);
        IVTV_DEBUG_WARN("DMA ERROR %08x %08x %08x %d\n", data[0], data[1],
-                               read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream);
-       write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
+                               status, itv->cur_dma_stream);
+       /*
+        * We do *not* write back to the IVTV_REG_DMASTATUS register to
+        * clear the error status, if either the encoder write (0x02) or
+        * decoder read (0x01) bus master DMA operation do not indicate
+        * completed.  We can race with the DMA engine, which may have
+        * transitioned to completed status *after* we read the register.
+        * Setting a IVTV_REG_DMASTATUS flag back to "busy" status, after the
+        * DMA engine has completed, will cause the DMA engine to stop working.
+        */
+       status &= 0x3;
+       if (status == 0x3)
+               write_reg(status, IVTV_REG_DMASTATUS);
+
        if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) &&
            itv->cur_dma_stream >= 0 && itv->cur_dma_stream < IVTV_MAX_STREAMS) {
                struct ivtv_stream *s = &itv->streams[itv->cur_dma_stream];
 
-               /* retry */
-               if (s->type >= IVTV_DEC_STREAM_TYPE_MPG)
+               if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) {
+                       /* retry */
+                       /*
+                        * FIXME - handle cases of DMA error similar to
+                        * encoder below, except conditioned on status & 0x1
+                        */
                        ivtv_dma_dec_start(s);
-               else
-                       ivtv_dma_enc_start(s);
-               return;
+                       return;
+               } else {
+                       if ((status & 0x2) == 0) {
+                               /*
+                                * CX2341x Bus Master DMA write is ongoing.
+                                * Reset the timer and let it complete.
+                                */
+                               itv->dma_timer.expires =
+                                               jiffies + msecs_to_jiffies(600);
+                               add_timer(&itv->dma_timer);
+                               return;
+                       }
+
+                       if (itv->dma_retries < 3) {
+                               /*
+                                * CX2341x Bus Master DMA write has ended.
+                                * Retry the write, starting with the first
+                                * xfer segment. Just retrying the current
+                                * segment is not sufficient.
+                                */
+                               s->sg_processed = 0;
+                               itv->dma_retries++;
+                               ivtv_dma_enc_start_xfer(s);
+                               return;
+                       }
+                       /* Too many retries, give up on this one */
+               }
+
        }
        if (test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
                ivtv_udma_start(itv);
index c179041..e7e7178 100644 (file)
@@ -1011,7 +1011,6 @@ static int m2mtest_remove(struct platform_device *pdev)
        v4l2_m2m_release(dev->m2m_dev);
        del_timer_sync(&dev->timer);
        video_unregister_device(dev->vfd);
-       video_device_release(dev->vfd);
        v4l2_device_unregister(&dev->v4l2_dev);
        kfree(dev);
 
index ccc8849..451ecd4 100644 (file)
@@ -597,7 +597,6 @@ static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw)
                init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
                init_data->type                  = RC_TYPE_RC5;
                init_data->name                  = hdw->hdw_desc->description;
-               init_data->polling_interval      = 260; /* ms From lirc_zilog */
                /* IR Receiver */
                info.addr          = 0x71;
                info.platform_data = init_data;
index b63f8ca..561909b 100644 (file)
@@ -57,7 +57,7 @@
 #include <linux/usb.h>
 
 #define S2255_MAJOR_VERSION    1
-#define S2255_MINOR_VERSION    20
+#define S2255_MINOR_VERSION    21
 #define S2255_RELEASE          0
 #define S2255_VERSION          KERNEL_VERSION(S2255_MAJOR_VERSION, \
                                               S2255_MINOR_VERSION, \
@@ -312,9 +312,9 @@ struct s2255_fh {
 };
 
 /* current cypress EEPROM firmware version */
-#define S2255_CUR_USB_FWVER    ((3 << 8) | 6)
+#define S2255_CUR_USB_FWVER    ((3 << 8) | 11)
 /* current DSP FW version */
-#define S2255_CUR_DSP_FWVER     8
+#define S2255_CUR_DSP_FWVER     10102
 /* Need DSP version 5+ for video status feature */
 #define S2255_MIN_DSP_STATUS      5
 #define S2255_MIN_DSP_COLORFILTER 8
@@ -492,9 +492,11 @@ static void planar422p_to_yuv_packed(const unsigned char *in,
 
 static void s2255_reset_dsppower(struct s2255_dev *dev)
 {
-       s2255_vendor_req(dev, 0x40, 0x0b0b, 0x0b0b, NULL, 0, 1);
+       s2255_vendor_req(dev, 0x40, 0x0b0b, 0x0b01, NULL, 0, 1);
        msleep(10);
        s2255_vendor_req(dev, 0x50, 0x0000, 0x0000, NULL, 0, 1);
+       msleep(600);
+       s2255_vendor_req(dev, 0x10, 0x0000, 0x0000, NULL, 0, 1);
        return;
 }
 
index f35459d..0db9092 100644 (file)
@@ -1565,7 +1565,7 @@ static int saa711x_probe(struct i2c_client *client,
        chip_id = name[5];
 
        /* Check whether this chip is part of the saa711x series */
-       if (memcmp(name, "1f711", 5)) {
+       if (memcmp(name + 1, "f711", 4)) {
                v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n",
                        client->addr << 1, name);
                return -ENODEV;
index e9a3eab..8c1d85e 100644 (file)
@@ -621,7 +621,7 @@ static int __init memstick_init(void)
 {
        int rc;
 
-       workqueue = create_freezeable_workqueue("kmemstick");
+       workqueue = create_freezable_workqueue("kmemstick");
        if (!workqueue)
                return -ENOMEM;
 
index f71f229..1735c84 100644 (file)
@@ -76,8 +76,8 @@
 #define COPYRIGHT      "Copyright (c) 1999-2008 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON       "3.04.17"
-#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-3.04.17"
+#define MPT_LINUX_VERSION_COMMON       "3.04.18"
+#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-3.04.18"
 #define WHAT_MAGIC_STRING              "@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
index a3856ed..e8deb8e 100644 (file)
@@ -596,6 +596,13 @@ mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
        return 1;
 }
 
+static int
+mptctl_release(struct inode *inode, struct file *filep)
+{
+       fasync_helper(-1, filep, 0, &async_queue);
+       return 0;
+}
+
 static int
 mptctl_fasync(int fd, struct file *filep, int mode)
 {
@@ -2815,6 +2822,7 @@ static const struct file_operations mptctl_fops = {
        .llseek =       no_llseek,
        .fasync =       mptctl_fasync,
        .unlocked_ioctl = mptctl_ioctl,
+       .release =      mptctl_release,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = compat_mpctl_ioctl,
 #endif
index 59b8f53..0d9b82a 100644 (file)
@@ -1873,8 +1873,9 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
        }
 
  out:
-       printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
-           ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), SCpnt);
+       printk(MYIOC_s_INFO_FMT "task abort: %s (rv=%04x) (sc=%p) (sn=%ld)\n",
+           ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), retval,
+           SCpnt, SCpnt->serial_number);
 
        return retval;
 }
@@ -1911,7 +1912,7 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
 
        vdevice = SCpnt->device->hostdata;
        if (!vdevice || !vdevice->vtarget) {
-               retval = SUCCESS;
+               retval = 0;
                goto out;
        }
 
index a0421ef..8a5b2d8 100644 (file)
@@ -84,7 +84,8 @@ int i2o_driver_register(struct i2o_driver *drv)
        osm_debug("Register driver %s\n", drv->name);
 
        if (drv->event) {
-               drv->event_queue = create_workqueue(drv->name);
+               drv->event_queue = alloc_workqueue(drv->name,
+                                                  WQ_MEM_RECLAIM, 1);
                if (!drv->event_queue) {
                        osm_err("Could not initialize event queue for driver "
                                "%s\n", drv->name);
index 6a1f940..c45e630 100644 (file)
@@ -143,9 +143,9 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc)
        unsigned long flags;
        struct asic3 *asic;
 
-       desc->chip->ack(irq);
+       desc->irq_data.chip->irq_ack(&desc->irq_data);
 
-       asic = desc->handler_data;
+       asic = get_irq_data(irq);
 
        for (iter = 0 ; iter < MAX_ASIC_ISR_LOOPS; iter++) {
                u32 status;
index 33c923d..fdd8a1b 100644 (file)
@@ -118,12 +118,12 @@ static int __init davinci_vc_probe(struct platform_device *pdev)
 
        /* Voice codec interface client */
        cell = &davinci_vc->cells[DAVINCI_VC_VCIF_CELL];
-       cell->name = "davinci_vcif";
+       cell->name = "davinci-vcif";
        cell->driver_data = davinci_vc;
 
        /* Voice codec CQ93VC client */
        cell = &davinci_vc->cells[DAVINCI_VC_CQ93VC_CELL];
-       cell->name = "cq93vc";
+       cell->name = "cq93vc-codec";
        cell->driver_data = davinci_vc;
 
        ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells,
index 627cf57..e9018d1 100644 (file)
@@ -150,12 +150,12 @@ static inline int __tps6586x_write(struct i2c_client *client,
 static inline int __tps6586x_writes(struct i2c_client *client, int reg,
                                  int len, uint8_t *val)
 {
-       int ret;
+       int ret, i;
 
-       ret = i2c_smbus_write_i2c_block_data(client, reg, len, val);
-       if (ret < 0) {
-               dev_err(&client->dev, "failed writings to 0x%02x\n", reg);
-               return ret;
+       for (i = 0; i < len; i++) {
+               ret = __tps6586x_write(client, reg + i, *(val + i));
+               if (ret < 0)
+                       return ret;
        }
 
        return 0;
index 000cb41..92b85e2 100644 (file)
@@ -385,12 +385,18 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
        idev->close      = ucb1x00_ts_close;
 
        __set_bit(EV_ABS, idev->evbit);
-       __set_bit(ABS_X, idev->absbit);
-       __set_bit(ABS_Y, idev->absbit);
-       __set_bit(ABS_PRESSURE, idev->absbit);
 
        input_set_drvdata(idev, ts);
 
+       ucb1x00_adc_enable(ts->ucb);
+       ts->x_res = ucb1x00_ts_read_xres(ts);
+       ts->y_res = ucb1x00_ts_read_yres(ts);
+       ucb1x00_adc_disable(ts->ucb);
+
+       input_set_abs_params(idev, ABS_X, 0, ts->x_res, 0, 0);
+       input_set_abs_params(idev, ABS_Y, 0, ts->y_res, 0, 0);
+       input_set_abs_params(idev, ABS_PRESSURE, 0, 0, 0, 0);
+
        err = input_register_device(idev);
        if (err)
                goto fail;
index 41233c7..f4016a0 100644 (file)
@@ -246,6 +246,16 @@ static int wm8994_suspend(struct device *dev)
        struct wm8994 *wm8994 = dev_get_drvdata(dev);
        int ret;
 
+       /* Don't actually go through with the suspend if the CODEC is
+        * still active (eg, for audio passthrough from CP. */
+       ret = wm8994_reg_read(wm8994, WM8994_POWER_MANAGEMENT_1);
+       if (ret < 0) {
+               dev_err(dev, "Failed to read power status: %d\n", ret);
+       } else if (ret & WM8994_VMID_SEL_MASK) {
+               dev_dbg(dev, "CODEC still active, ignoring suspend\n");
+               return 0;
+       }
+
        /* GPIO configuration state is saved here since we may be configuring
         * the GPIO alternate functions even if we're not using the gpiolib
         * driver for them.
@@ -261,6 +271,8 @@ static int wm8994_suspend(struct device *dev)
        if (ret < 0)
                dev_err(dev, "Failed to save LDO registers: %d\n", ret);
 
+       wm8994->suspended = true;
+
        ret = regulator_bulk_disable(wm8994->num_supplies,
                                     wm8994->supplies);
        if (ret != 0) {
@@ -276,6 +288,10 @@ static int wm8994_resume(struct device *dev)
        struct wm8994 *wm8994 = dev_get_drvdata(dev);
        int ret;
 
+       /* We may have lied to the PM core about suspending */
+       if (!wm8994->suspended)
+               return 0;
+
        ret = regulator_bulk_enable(wm8994->num_supplies,
                                    wm8994->supplies);
        if (ret != 0) {
@@ -298,6 +314,8 @@ static int wm8994_resume(struct device *dev)
        if (ret < 0)
                dev_err(dev, "Failed to restore GPIO registers: %d\n", ret);
 
+       wm8994->suspended = false;
+
        return 0;
 }
 #endif
index 63ee4c1..b6e1c9a 100644 (file)
@@ -449,6 +449,7 @@ static const struct i2c_device_id bmp085_id[] = {
        { "bmp085", 0 },
        { }
 };
+MODULE_DEVICE_TABLE(i2c, bmp085_id);
 
 static struct i2c_driver bmp085_driver = {
        .driver = {
index 740ff07..620973e 100644 (file)
@@ -183,9 +183,7 @@ struct iwmct_priv {
        u32 barker;
        struct iwmct_dbg dbg;
 
-       /* drivers work queue */
-       struct workqueue_struct *wq;
-       struct workqueue_struct *bus_rescan_wq;
+       /* drivers work items */
        struct work_struct bus_rescan_worker;
        struct work_struct isr_worker;
 
index c73cef2..727af07 100644 (file)
@@ -89,7 +89,7 @@ static void op_top_message(struct iwmct_priv *priv, struct top_msg *msg)
        switch (msg->hdr.opcode) {
        case OP_OPR_ALIVE:
                LOG_INFO(priv, FW_MSG, "Got ALIVE from device, wake rescan\n");
-               queue_work(priv->bus_rescan_wq, &priv->bus_rescan_worker);
+               schedule_work(&priv->bus_rescan_worker);
                break;
        default:
                LOG_INFO(priv, FW_MSG, "Received msg opcode 0x%X\n",
@@ -360,7 +360,7 @@ static void iwmct_irq(struct sdio_func *func)
        /* clear the function's interrupt request bit (write 1 to clear) */
        sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret);
 
-       queue_work(priv->wq, &priv->isr_worker);
+       schedule_work(&priv->isr_worker);
 
        LOG_TRACE(priv, IRQ, "exit iwmct_irq\n");
 
@@ -506,10 +506,6 @@ static int iwmct_probe(struct sdio_func *func,
        priv->func = func;
        sdio_set_drvdata(func, priv);
 
-
-       /* create drivers work queue */
-       priv->wq = create_workqueue(DRV_NAME "_wq");
-       priv->bus_rescan_wq = create_workqueue(DRV_NAME "_rescan_wq");
        INIT_WORK(&priv->bus_rescan_worker, iwmct_rescan_worker);
        INIT_WORK(&priv->isr_worker, iwmct_irq_read_worker);
 
@@ -604,9 +600,9 @@ static void iwmct_remove(struct sdio_func *func)
        sdio_release_irq(func);
        sdio_release_host(func);
 
-       /* Safely destroy osc workqueue */
-       destroy_workqueue(priv->bus_rescan_wq);
-       destroy_workqueue(priv->wq);
+       /* Make sure works are finished */
+       flush_work_sync(&priv->bus_rescan_worker);
+       flush_work_sync(&priv->isr_worker);
 
        sdio_claim_host(func);
        sdio_disable_func(func);
index 5f6852d..44d4475 100644 (file)
@@ -329,7 +329,7 @@ static int __init tifm_init(void)
 {
        int rc;
 
-       workqueue = create_freezeable_workqueue("tifm");
+       workqueue = create_freezable_workqueue("tifm");
        if (!workqueue)
                return -ENOMEM;
 
index 4d2ea8e..6df5a55 100644 (file)
@@ -785,7 +785,7 @@ static int __init vmballoon_init(void)
        if (x86_hyper != &x86_hyper_vmware)
                return -ENODEV;
 
-       vmballoon_wq = create_freezeable_workqueue("vmmemctl");
+       vmballoon_wq = create_freezable_workqueue("vmmemctl");
        if (!vmballoon_wq) {
                pr_err("failed to create workqueue\n");
                return -ENOMEM;
index 6625c05..150b5f3 100644 (file)
@@ -1529,7 +1529,7 @@ void mmc_rescan(struct work_struct *work)
         * still present
         */
        if (host->bus_ops && host->bus_ops->detect && !host->bus_dead
-           && mmc_card_is_removable(host))
+           && !(host->caps & MMC_CAP_NONREMOVABLE))
                host->bus_ops->detect(host);
 
        /*
index 5c4a54d..ebc62ad 100644 (file)
@@ -792,7 +792,6 @@ int mmc_attach_sdio(struct mmc_host *host)
         */
        mmc_release_host(host);
        err = mmc_add_card(host->card);
-       mmc_claim_host(host);
        if (err)
                goto remove_added;
 
@@ -805,12 +804,12 @@ int mmc_attach_sdio(struct mmc_host *host)
                        goto remove_added;
        }
 
+       mmc_claim_host(host);
        return 0;
 
 
 remove_added:
        /* Remove without lock if the device has been added. */
-       mmc_release_host(host);
        mmc_sdio_remove(host);
        mmc_claim_host(host);
 remove:
index bac7d62..0371bf5 100644 (file)
@@ -462,7 +462,7 @@ static int __devinit sdh_probe(struct platform_device *pdev)
                goto out;
        }
 
-       mmc = mmc_alloc_host(sizeof(*mmc), &pdev->dev);
+       mmc = mmc_alloc_host(sizeof(struct sdh_host), &pdev->dev);
        if (!mmc) {
                ret = -ENOMEM;
                goto out;
index b3a0ab0..74218ad 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <linux/mmc/host.h>
+#include <linux/err.h>
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
@@ -827,8 +828,8 @@ static int __devinit jz4740_mmc_probe(struct platform_device* pdev)
        }
 
        host->clk = clk_get(&pdev->dev, "mmc");
-       if (!host->clk) {
-               ret = -ENOENT;
+       if (IS_ERR(host->clk)) {
+               ret = PTR_ERR(host->clk);
                dev_err(&pdev->dev, "Failed to get mmc clock\n");
                goto err_free_host;
        }
index fd877f6..2f7fc0c 100644 (file)
@@ -1516,21 +1516,17 @@ static int __devexit mmc_spi_remove(struct spi_device *spi)
        return 0;
 }
 
-#if defined(CONFIG_OF)
 static struct of_device_id mmc_spi_of_match_table[] __devinitdata = {
        { .compatible = "mmc-spi-slot", },
        {},
 };
-#endif
 
 static struct spi_driver mmc_spi_driver = {
        .driver = {
                .name =         "mmc_spi",
                .bus =          &spi_bus_type,
                .owner =        THIS_MODULE,
-#if defined(CONFIG_OF)
                .of_match_table = mmc_spi_of_match_table,
-#endif
        },
        .probe =        mmc_spi_probe,
        .remove =       __devexit_p(mmc_spi_remove),
index 5630228..2d6de3e 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/ioport.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
+#include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/highmem.h>
@@ -46,10 +47,6 @@ static unsigned int fmax = 515633;
  *           is asserted (likewise for RX)
  * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
  *               is asserted (likewise for RX)
- * @broken_blockend: the MCI_DATABLOCKEND is broken on the hardware
- *             and will not work at all.
- * @broken_blockend_dma: the MCI_DATABLOCKEND is broken on the hardware when
- *             using DMA.
  * @sdio: variant supports SDIO
  * @st_clkdiv: true if using a ST-specific clock divider algorithm
  */
@@ -59,8 +56,6 @@ struct variant_data {
        unsigned int            datalength_bits;
        unsigned int            fifosize;
        unsigned int            fifohalfsize;
-       bool                    broken_blockend;
-       bool                    broken_blockend_dma;
        bool                    sdio;
        bool                    st_clkdiv;
 };
@@ -76,7 +71,6 @@ static struct variant_data variant_u300 = {
        .fifohalfsize           = 8 * 4,
        .clkreg_enable          = 1 << 13, /* HWFCEN */
        .datalength_bits        = 16,
-       .broken_blockend_dma    = true,
        .sdio                   = true,
 };
 
@@ -86,7 +80,6 @@ static struct variant_data variant_ux500 = {
        .clkreg                 = MCI_CLK_ENABLE,
        .clkreg_enable          = 1 << 14, /* HWFCEN */
        .datalength_bits        = 24,
-       .broken_blockend        = true,
        .sdio                   = true,
        .st_clkdiv              = true,
 };
@@ -210,8 +203,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
        host->data = data;
        host->size = data->blksz * data->blocks;
        host->data_xfered = 0;
-       host->blockend = false;
-       host->dataend = false;
 
        mmci_init_sg(host, data);
 
@@ -288,21 +279,26 @@ static void
 mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
              unsigned int status)
 {
-       struct variant_data *variant = host->variant;
-
        /* First check for errors */
        if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
+               u32 remain, success;
+
+               /* Calculate how far we are into the transfer */
+               remain = readl(host->base + MMCIDATACNT);
+               success = data->blksz * data->blocks - remain;
+
                dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status);
-               if (status & MCI_DATACRCFAIL)
+               if (status & MCI_DATACRCFAIL) {
+                       /* Last block was not successful */
+                       host->data_xfered = round_down(success - 1, data->blksz);
                        data->error = -EILSEQ;
-               else if (status & MCI_DATATIMEOUT)
+               } else if (status & MCI_DATATIMEOUT) {
+                       host->data_xfered = round_down(success, data->blksz);
                        data->error = -ETIMEDOUT;
-               else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN))
+               } else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
+                       host->data_xfered = round_down(success, data->blksz);
                        data->error = -EIO;
-
-               /* Force-complete the transaction */
-               host->blockend = true;
-               host->dataend = true;
+               }
 
                /*
                 * We hit an error condition.  Ensure that any data
@@ -321,61 +317,14 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
                }
        }
 
-       /*
-        * On ARM variants in PIO mode, MCI_DATABLOCKEND
-        * is always sent first, and we increase the
-        * transfered number of bytes for that IRQ. Then
-        * MCI_DATAEND follows and we conclude the transaction.
-        *
-        * On the Ux500 single-IRQ variant MCI_DATABLOCKEND
-        * doesn't seem to immediately clear from the status,
-        * so we can't use it keep count when only one irq is
-        * used because the irq will hit for other reasons, and
-        * then the flag is still up. So we use the MCI_DATAEND
-        * IRQ at the end of the entire transfer because
-        * MCI_DATABLOCKEND is broken.
-        *
-        * In the U300, the IRQs can arrive out-of-order,
-        * e.g. MCI_DATABLOCKEND sometimes arrives after MCI_DATAEND,
-        * so for this case we use the flags "blockend" and
-        * "dataend" to make sure both IRQs have arrived before
-        * concluding the transaction. (This does not apply
-        * to the Ux500 which doesn't fire MCI_DATABLOCKEND
-        * at all.) In DMA mode it suffers from the same problem
-        * as the Ux500.
-        */
-       if (status & MCI_DATABLOCKEND) {
-               /*
-                * Just being a little over-cautious, we do not
-                * use this progressive update if the hardware blockend
-                * flag is unreliable: since it can stay high between
-                * IRQs it will corrupt the transfer counter.
-                */
-               if (!variant->broken_blockend)
-                       host->data_xfered += data->blksz;
-               host->blockend = true;
-       }
-
-       if (status & MCI_DATAEND)
-               host->dataend = true;
+       if (status & MCI_DATABLOCKEND)
+               dev_err(mmc_dev(host->mmc), "stray MCI_DATABLOCKEND interrupt\n");
 
-       /*
-        * On variants with broken blockend we shall only wait for dataend,
-        * on others we must sync with the blockend signal since they can
-        * appear out-of-order.
-        */
-       if (host->dataend && (host->blockend || variant->broken_blockend)) {
+       if (status & MCI_DATAEND || data->error) {
                mmci_stop_data(host);
 
-               /* Reset these flags */
-               host->blockend = false;
-               host->dataend = false;
-
-               /*
-                * Variants with broken blockend flags need to handle the
-                * end of the entire transfer here.
-                */
-               if (variant->broken_blockend && !data->error)
+               if (!data->error)
+                       /* The error clause is handled above, success! */
                        host->data_xfered += data->blksz * data->blocks;
 
                if (!data->stop) {
@@ -394,15 +343,15 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
 
        host->cmd = NULL;
 
-       cmd->resp[0] = readl(base + MMCIRESPONSE0);
-       cmd->resp[1] = readl(base + MMCIRESPONSE1);
-       cmd->resp[2] = readl(base + MMCIRESPONSE2);
-       cmd->resp[3] = readl(base + MMCIRESPONSE3);
-
        if (status & MCI_CMDTIMEOUT) {
                cmd->error = -ETIMEDOUT;
        } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) {
                cmd->error = -EILSEQ;
+       } else {
+               cmd->resp[0] = readl(base + MMCIRESPONSE0);
+               cmd->resp[1] = readl(base + MMCIRESPONSE1);
+               cmd->resp[2] = readl(base + MMCIRESPONSE2);
+               cmd->resp[3] = readl(base + MMCIRESPONSE3);
        }
 
        if (!cmd->data || cmd->error) {
@@ -770,7 +719,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
        struct variant_data *variant = id->data;
        struct mmci_host *host;
        struct mmc_host *mmc;
-       unsigned int mask;
        int ret;
 
        /* must have platform data */
@@ -951,12 +899,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
                        goto irq0_free;
        }
 
-       mask = MCI_IRQENABLE;
-       /* Don't use the datablockend flag if it's broken */
-       if (variant->broken_blockend)
-               mask &= ~MCI_DATABLOCKEND;
-
-       writel(mask, host->base + MMCIMASK0);
+       writel(MCI_IRQENABLE, host->base + MMCIMASK0);
 
        amba_set_drvdata(dev, mmc);
 
index df06f01..c1df7b8 100644 (file)
 #define MCI_IRQENABLE  \
        (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK|     \
        MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK|       \
-       MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK)
+       MCI_CMDRESPENDMASK|MCI_CMDSENTMASK)
 
 /* These interrupts are directed to IRQ1 when two IRQ lines are available */
 #define MCI_IRQ1MASK \
@@ -177,9 +177,6 @@ struct mmci_host {
        struct timer_list       timer;
        unsigned int            oldstat;
 
-       bool                    blockend;
-       bool                    dataend;
-
        /* pio stuff */
        struct sg_mapping_iter  sg_miter;
        unsigned int            size;
index 1720358..5309ab9 100644 (file)
@@ -277,10 +277,43 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
        host->clock = clock;
 }
 
+/**
+ * sdhci_s3c_platform_8bit_width - support 8bit buswidth
+ * @host: The SDHCI host being queried
+ * @width: MMC_BUS_WIDTH_ macro for the bus width being requested
+ *
+ * We have 8-bit width support but is not a v3 controller.
+ * So we add platform_8bit_width() and support 8bit width.
+ */
+static int sdhci_s3c_platform_8bit_width(struct sdhci_host *host, int width)
+{
+       u8 ctrl;
+
+       ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+
+       switch (width) {
+       case MMC_BUS_WIDTH_8:
+               ctrl |= SDHCI_CTRL_8BITBUS;
+               ctrl &= ~SDHCI_CTRL_4BITBUS;
+               break;
+       case MMC_BUS_WIDTH_4:
+               ctrl |= SDHCI_CTRL_4BITBUS;
+               ctrl &= ~SDHCI_CTRL_8BITBUS;
+               break;
+       default:
+               break;
+       }
+
+       sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+
+       return 0;
+}
+
 static struct sdhci_ops sdhci_s3c_ops = {
        .get_max_clock          = sdhci_s3c_get_max_clk,
        .set_clock              = sdhci_s3c_set_clock,
        .get_min_clock          = sdhci_s3c_get_min_clock,
+       .platform_8bit_width    = sdhci_s3c_platform_8bit_width,
 };
 
 static void sdhci_s3c_notify_change(struct platform_device *dev, int state)
@@ -473,6 +506,9 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
        if (pdata->cd_type == S3C_SDHCI_CD_PERMANENT)
                host->mmc->caps = MMC_CAP_NONREMOVABLE;
 
+       if (pdata->host_caps)
+               host->mmc->caps |= pdata->host_caps;
+
        host->quirks |= (SDHCI_QUIRK_32BIT_DMA_ADDR |
                         SDHCI_QUIRK_32BIT_DMA_SIZE);
 
index f8f65df..f08f944 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/module.h>
 #include <linux/usb.h>
 #include <linux/kernel.h>
-#include <linux/usb.h>
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
 #include <linux/mmc/host.h>
index a8c3e1c..4aaa88f 100644 (file)
@@ -1230,10 +1230,32 @@ static int inval_cache_and_wait_for_operation(
        sleep_time = chip_op_time / 2;
 
        for (;;) {
+               if (chip->state != chip_state) {
+                       /* Someone's suspended the operation: sleep */
+                       DECLARE_WAITQUEUE(wait, current);
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       add_wait_queue(&chip->wq, &wait);
+                       mutex_unlock(&chip->mutex);
+                       schedule();
+                       remove_wait_queue(&chip->wq, &wait);
+                       mutex_lock(&chip->mutex);
+                       continue;
+               }
+
                status = map_read(map, cmd_adr);
                if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
 
+               if (chip->erase_suspended && chip_state == FL_ERASING)  {
+                       /* Erase suspend occured while sleep: reset timeout */
+                       timeo = reset_timeo;
+                       chip->erase_suspended = 0;
+               }
+               if (chip->write_suspended && chip_state == FL_WRITING)  {
+                       /* Write suspend occured while sleep: reset timeout */
+                       timeo = reset_timeo;
+                       chip->write_suspended = 0;
+               }
                if (!timeo) {
                        map_write(map, CMD(0x70), cmd_adr);
                        chip->state = FL_STATUS;
@@ -1257,27 +1279,6 @@ static int inval_cache_and_wait_for_operation(
                        timeo--;
                }
                mutex_lock(&chip->mutex);
-
-               while (chip->state != chip_state) {
-                       /* Someone's suspended the operation: sleep */
-                       DECLARE_WAITQUEUE(wait, current);
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       add_wait_queue(&chip->wq, &wait);
-                       mutex_unlock(&chip->mutex);
-                       schedule();
-                       remove_wait_queue(&chip->wq, &wait);
-                       mutex_lock(&chip->mutex);
-               }
-               if (chip->erase_suspended && chip_state == FL_ERASING)  {
-                       /* Erase suspend occured while sleep: reset timeout */
-                       timeo = reset_timeo;
-                       chip->erase_suspended = 0;
-               }
-               if (chip->write_suspended && chip_state == FL_WRITING)  {
-                       /* Write suspend occured while sleep: reset timeout */
-                       timeo = reset_timeo;
-                       chip->write_suspended = 0;
-               }
        }
 
        /* Done and happy. */
index d72a5fb..4e1be51 100644 (file)
@@ -1935,14 +1935,14 @@ static void jedec_reset(u32 base, struct map_info *map, struct cfi_private *cfi)
 }
 
 
-static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
+static int cfi_jedec_setup(struct map_info *map, struct cfi_private *cfi, int index)
 {
        int i,num_erase_regions;
        uint8_t uaddr;
 
-       if (! (jedec_table[index].devtypes & p_cfi->device_type)) {
+       if (!(jedec_table[index].devtypes & cfi->device_type)) {
                DEBUG(MTD_DEBUG_LEVEL1, "Rejecting potential %s with incompatible %d-bit device type\n",
-                     jedec_table[index].name, 4 * (1<<p_cfi->device_type));
+                     jedec_table[index].name, 4 * (1<<cfi->device_type));
                return 0;
        }
 
@@ -1950,27 +1950,28 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
 
        num_erase_regions = jedec_table[index].nr_regions;
 
-       p_cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL);
-       if (!p_cfi->cfiq) {
+       cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL);
+       if (!cfi->cfiq) {
                //xx printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name);
                return 0;
        }
 
-       memset(p_cfi->cfiq,0,sizeof(struct cfi_ident));
+       memset(cfi->cfiq, 0, sizeof(struct cfi_ident));
 
-       p_cfi->cfiq->P_ID = jedec_table[index].cmd_set;
-       p_cfi->cfiq->NumEraseRegions = jedec_table[index].nr_regions;
-       p_cfi->cfiq->DevSize = jedec_table[index].dev_size;
-       p_cfi->cfi_mode = CFI_MODE_JEDEC;
+       cfi->cfiq->P_ID = jedec_table[index].cmd_set;
+       cfi->cfiq->NumEraseRegions = jedec_table[index].nr_regions;
+       cfi->cfiq->DevSize = jedec_table[index].dev_size;
+       cfi->cfi_mode = CFI_MODE_JEDEC;
+       cfi->sector_erase_cmd = CMD(0x30);
 
        for (i=0; i<num_erase_regions; i++){
-               p_cfi->cfiq->EraseRegionInfo[i] = jedec_table[index].regions[i];
+               cfi->cfiq->EraseRegionInfo[i] = jedec_table[index].regions[i];
        }
-       p_cfi->cmdset_priv = NULL;
+       cfi->cmdset_priv = NULL;
 
        /* This may be redundant for some cases, but it doesn't hurt */
-       p_cfi->mfr = jedec_table[index].mfr_id;
-       p_cfi->id = jedec_table[index].dev_id;
+       cfi->mfr = jedec_table[index].mfr_id;
+       cfi->id = jedec_table[index].dev_id;
 
        uaddr = jedec_table[index].uaddr;
 
@@ -1978,8 +1979,8 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
           our brains explode when we see the datasheets talking about address
           lines numbered from A-1 to A18. The CFI table has unlock addresses
           in device-words according to the mode the device is connected in */
-       p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1 / p_cfi->device_type;
-       p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2 / p_cfi->device_type;
+       cfi->addr_unlock1 = unlock_addrs[uaddr].addr1 / cfi->device_type;
+       cfi->addr_unlock2 = unlock_addrs[uaddr].addr2 / cfi->device_type;
 
        return 1;       /* ok */
 }
@@ -2175,7 +2176,7 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
                                       "MTD %s(): matched device 0x%x,0x%x unlock_addrs: 0x%.4x 0x%.4x\n",
                                       __func__, cfi->mfr, cfi->id,
                                       cfi->addr_unlock1, cfi->addr_unlock2 );
-                               if (!cfi_jedec_setup(cfi, i))
+                               if (!cfi_jedec_setup(map, cfi, i))
                                        return 0;
                                goto ok_out;
                        }
index 77d64ce..92de7e3 100644 (file)
@@ -151,6 +151,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
                printk(KERN_ERR MOD_NAME
                       " %s(): Unable to register resource %pR - kernel bug?\n",
                       __func__, &window->rsrc);
+               return -EBUSY;
        }
 
 
index cb20c67..e0a2373 100644 (file)
@@ -413,7 +413,6 @@ error3:
 error2:
        list_del(&new->list);
 error1:
-       kfree(new);
        return ret;
 }
 
index 15682ec..28af71c 100644 (file)
@@ -968,6 +968,6 @@ static void __exit omap_nand_exit(void)
 module_init(omap_nand_init);
 module_exit(omap_nand_exit);
 
-MODULE_ALIAS(DRIVER_NAME);
+MODULE_ALIAS("platform:" DRIVER_NAME);
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Glue layer for NAND flash on TI OMAP boards");
index d9d7efb..6322d1f 100644 (file)
@@ -930,7 +930,7 @@ int  r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
 
        init_completion(&dev->dma_done);
 
-       dev->card_workqueue = create_freezeable_workqueue(DRV_NAME);
+       dev->card_workqueue = create_freezable_workqueue(DRV_NAME);
 
        if (!dev->card_workqueue)
                goto error9;
index e789149..ac08750 100644 (file)
@@ -131,7 +131,7 @@ static struct platform_driver generic_onenand_driver = {
        .remove         = __devexit_p(generic_onenand_remove),
 };
 
-MODULE_ALIAS(DRIVER_NAME);
+MODULE_ALIAS("platform:" DRIVER_NAME);
 
 static int __init generic_onenand_init(void)
 {
index ac31f46..c849cac 100644 (file)
@@ -860,7 +860,7 @@ static void __exit omap2_onenand_exit(void)
 module_init(omap2_onenand_init);
 module_exit(omap2_onenand_exit);
 
-MODULE_ALIAS(DRIVER_NAME);
+MODULE_ALIAS("platform:" DRIVER_NAME);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jarkko Lavinen <jarkko.lavinen@nokia.com>");
 MODULE_DESCRIPTION("Glue layer for OneNAND flash on OMAP2 / OMAP3");
index 67822cf..ac0d6a8 100644 (file)
@@ -1258,7 +1258,7 @@ static struct mtd_blktrans_ops sm_ftl_ops = {
 static __init int sm_module_init(void)
 {
        int error = 0;
-       cache_flush_workqueue = create_freezeable_workqueue("smflush");
+       cache_flush_workqueue = create_freezable_workqueue("smflush");
 
        if (IS_ERR(cache_flush_workqueue))
                return PTR_ERR(cache_flush_workqueue);
index f49e49d..5ebe280 100644 (file)
@@ -672,33 +672,7 @@ static int io_init(struct ubi_device *ubi)
                ubi->nor_flash = 1;
        }
 
-       /*
-        * Set UBI min. I/O size (@ubi->min_io_size). We use @mtd->writebufsize
-        * for these purposes, not @mtd->writesize. At the moment this does not
-        * matter for NAND, because currently @mtd->writebufsize is equivalent to
-        * @mtd->writesize for all NANDs. However, some CFI NOR flashes may
-        * have @mtd->writebufsize which is multiple of @mtd->writesize.
-        *
-        * The reason we use @mtd->writebufsize for @ubi->min_io_size is that
-        * UBI and UBIFS recovery algorithms rely on the fact that if there was
-        * an unclean power cut, then we can find offset of the last corrupted
-        * node, align the offset to @ubi->min_io_size, read the rest of the
-        * eraseblock starting from this offset, and check whether there are
-        * only 0xFF bytes. If yes, then we are probably dealing with a
-        * corruption caused by a power cut, if not, then this is probably some
-        * severe corruption.
-        *
-        * Thus, we have to use the maximum write unit size of the flash, which
-        * is @mtd->writebufsize, because @mtd->writesize is the minimum write
-        * size, not the maximum.
-        */
-       if (ubi->mtd->type == MTD_NANDFLASH)
-               ubi_assert(ubi->mtd->writebufsize == ubi->mtd->writesize);
-       else if (ubi->mtd->type == MTD_NORFLASH)
-               ubi_assert(ubi->mtd->writebufsize % ubi->mtd->writesize == 0);
-
-       ubi->min_io_size = ubi->mtd->writebufsize;
-
+       ubi->min_io_size = ubi->mtd->writesize;
        ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
 
        /*
index 39214e5..7ca0ede 100644 (file)
@@ -425,11 +425,6 @@ static irqreturn_t ariadne_interrupt(int irq, void *data)
     int csr0, boguscnt;
     int handled = 0;
 
-    if (dev == NULL) {
-       printk(KERN_WARNING "ariadne_interrupt(): irq for unknown device.\n");
-       return IRQ_NONE;
-    }
-
     lance->RAP = CSR0;                 /* PCnet-ISA Controller Status */
 
     if (!(lance->RDP & INTR))          /* Check if any interrupt has been */
index a699bbf..3824382 100644 (file)
@@ -48,6 +48,7 @@ static DEFINE_PCI_DEVICE_TABLE(atl1c_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L2C_B)},
        {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L2C_B2)},
        {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L1D)},
+       {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L1D_2_0)},
        /* required last entry */
        { 0 }
 };
index 0c7811f..a179cc6 100644 (file)
@@ -1786,6 +1786,10 @@ int be_cmd_get_seeprom_data(struct be_adapter *adapter,
        spin_lock_bh(&adapter->mcc_lock);
 
        wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+               status = -EBUSY;
+               goto err;
+       }
        req = nonemb_cmd->va;
        sge = nonembedded_sgl(wrb);
 
@@ -1801,6 +1805,7 @@ int be_cmd_get_seeprom_data(struct be_adapter *adapter,
 
        status = be_mcc_notify_wait(adapter);
 
+err:
        spin_unlock_bh(&adapter->mcc_lock);
        return status;
 }
index de40d3b..28a32a6 100644 (file)
@@ -312,11 +312,9 @@ void be_link_status_update(struct be_adapter *adapter, bool link_up)
        if (adapter->link_up != link_up) {
                adapter->link_speed = -1;
                if (link_up) {
-                       netif_start_queue(netdev);
                        netif_carrier_on(netdev);
                        printk(KERN_INFO "%s: Link up\n", netdev->name);
                } else {
-                       netif_stop_queue(netdev);
                        netif_carrier_off(netdev);
                        printk(KERN_INFO "%s: Link down\n", netdev->name);
                }
@@ -2628,8 +2626,6 @@ static void be_netdev_init(struct net_device *netdev)
 
        netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx_mcc,
                BE_NAPI_WEIGHT);
-
-       netif_stop_queue(netdev);
 }
 
 static void be_unmap_pci_bars(struct be_adapter *adapter)
index df99edf..0ba59d5 100644 (file)
@@ -7553,6 +7553,10 @@ bnx2_set_flags(struct net_device *dev, u32 data)
            !(data & ETH_FLAG_RXVLAN))
                return -EINVAL;
 
+       /* TSO with VLAN tag won't work with current firmware */
+       if (!(data & ETH_FLAG_TXVLAN))
+               return -EINVAL;
+
        rc = ethtool_op_set_flags(dev, data, ETH_FLAG_RXHASH | ETH_FLAG_RXVLAN |
                                  ETH_FLAG_TXVLAN);
        if (rc)
@@ -7962,11 +7966,8 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
 
                /* AER (Advanced Error Reporting) hooks */
                err = pci_enable_pcie_error_reporting(pdev);
-               if (err) {
-                       dev_err(&pdev->dev, "pci_enable_pcie_error_reporting "
-                                           "failed 0x%x\n", err);
-                       /* non-fatal, continue */
-               }
+               if (!err)
+                       bp->flags |= BNX2_FLAG_AER_ENABLED;
 
        } else {
                bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
@@ -8229,8 +8230,10 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        return 0;
 
 err_out_unmap:
-       if (bp->flags & BNX2_FLAG_PCIE)
+       if (bp->flags & BNX2_FLAG_AER_ENABLED) {
                pci_disable_pcie_error_reporting(pdev);
+               bp->flags &= ~BNX2_FLAG_AER_ENABLED;
+       }
 
        if (bp->regview) {
                iounmap(bp->regview);
@@ -8418,8 +8421,10 @@ bnx2_remove_one(struct pci_dev *pdev)
 
        kfree(bp->temp_stats_blk);
 
-       if (bp->flags & BNX2_FLAG_PCIE)
+       if (bp->flags & BNX2_FLAG_AER_ENABLED) {
                pci_disable_pcie_error_reporting(pdev);
+               bp->flags &= ~BNX2_FLAG_AER_ENABLED;
+       }
 
        free_netdev(dev);
 
@@ -8535,7 +8540,7 @@ static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
        }
        rtnl_unlock();
 
-       if (!(bp->flags & BNX2_FLAG_PCIE))
+       if (!(bp->flags & BNX2_FLAG_AER_ENABLED))
                return result;
 
        err = pci_cleanup_aer_uncorrect_error_status(pdev);
index 5488a2e..f459fb2 100644 (file)
@@ -6741,6 +6741,7 @@ struct bnx2 {
 #define BNX2_FLAG_JUMBO_BROKEN         0x00000800
 #define BNX2_FLAG_CAN_KEEP_VLAN                0x00001000
 #define BNX2_FLAG_BROKEN_STATS         0x00002000
+#define BNX2_FLAG_AER_ENABLED          0x00004000
 
        struct bnx2_napi        bnx2_napi[BNX2_MAX_MSIX_VEC];
 
index 8e41837..8849699 100644 (file)
@@ -22,8 +22,8 @@
  * (you will need to reboot afterwards) */
 /* #define BNX2X_STOP_ON_ERROR */
 
-#define DRV_MODULE_VERSION      "1.62.00-4"
-#define DRV_MODULE_RELDATE      "2011/01/18"
+#define DRV_MODULE_VERSION      "1.62.00-6"
+#define DRV_MODULE_RELDATE      "2011/01/30"
 #define BNX2X_BC_VER            0x040200
 
 #define BNX2X_MULTI_QUEUE
@@ -1211,6 +1211,7 @@ struct bnx2x {
        /* DCBX Negotation results */
        struct dcbx_features                    dcbx_local_feat;
        u32                                     dcbx_error;
+       u32                                     pending_max;
 };
 
 /**
@@ -1613,19 +1614,23 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
 #define BNX2X_BTR                      4
 #define MAX_SPQ_PENDING                        8
 
-
-/* CMNG constants
-   derived from lab experiments, and not from system spec calculations !!! */
-#define DEF_MIN_RATE                   100
-/* resolution of the rate shaping timer - 100 usec */
-#define RS_PERIODIC_TIMEOUT_USEC       100
-/* resolution of fairness algorithm in usecs -
-   coefficient for calculating the actual t fair */
-#define T_FAIR_COEF                    10000000
+/* CMNG constants, as derived from system spec calculations */
+/* default MIN rate in case VNIC min rate is configured to zero - 100Mbps */
+#define DEF_MIN_RATE                                   100
+/* resolution of the rate shaping timer - 400 usec */
+#define RS_PERIODIC_TIMEOUT_USEC                       400
 /* number of bytes in single QM arbitration cycle -
-   coefficient for calculating the fairness timer */
-#define QM_ARB_BYTES                   40000
-#define FAIR_MEM                       2
+ * coefficient for calculating the fairness timer */
+#define QM_ARB_BYTES                                   160000
+/* resolution of Min algorithm 1:100 */
+#define MIN_RES                                                100
+/* how many bytes above threshold for the minimal credit of Min algorithm*/
+#define MIN_ABOVE_THRESH                               32768
+/* Fairness algorithm integration time coefficient -
+ * for calculating the actual Tfair */
+#define T_FAIR_COEF    ((MIN_ABOVE_THRESH +  QM_ARB_BYTES) * 8 * MIN_RES)
+/* Memory of fairness algorithm . 2 cycles */
+#define FAIR_MEM                                       2
 
 
 #define ATTN_NIG_FOR_FUNC              (1L << 8)
index 710ce5d..a71b329 100644 (file)
@@ -259,10 +259,44 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
 #endif
 }
 
+/* Timestamp option length allowed for TPA aggregation:
+ *
+ *             nop nop kind length echo val
+ */
+#define TPA_TSTAMP_OPT_LEN     12
+/**
+ * Calculate the approximate value of the MSS for this
+ * aggregation using the first packet of it.
+ *
+ * @param bp
+ * @param parsing_flags Parsing flags from the START CQE
+ * @param len_on_bd Total length of the first packet for the
+ *                  aggregation.
+ */
+static inline u16 bnx2x_set_lro_mss(struct bnx2x *bp, u16 parsing_flags,
+                                   u16 len_on_bd)
+{
+       /* TPA arrgregation won't have an IP options and TCP options
+        * other than timestamp.
+        */
+       u16 hdrs_len = ETH_HLEN + sizeof(struct iphdr) + sizeof(struct tcphdr);
+
+
+       /* Check if there was a TCP timestamp, if there is it's will
+        * always be 12 bytes length: nop nop kind length echo val.
+        *
+        * Otherwise FW would close the aggregation.
+        */
+       if (parsing_flags & PARSING_FLAGS_TIME_STAMP_EXIST_FLAG)
+               hdrs_len += TPA_TSTAMP_OPT_LEN;
+
+       return len_on_bd - hdrs_len;
+}
+
 static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
                               struct sk_buff *skb,
                               struct eth_fast_path_rx_cqe *fp_cqe,
-                              u16 cqe_idx)
+                              u16 cqe_idx, u16 parsing_flags)
 {
        struct sw_rx_page *rx_pg, old_rx_pg;
        u16 len_on_bd = le16_to_cpu(fp_cqe->len_on_bd);
@@ -275,8 +309,8 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
 
        /* This is needed in order to enable forwarding support */
        if (frag_size)
-               skb_shinfo(skb)->gso_size = min((u32)SGE_PAGE_SIZE,
-                                              max(frag_size, (u32)len_on_bd));
+               skb_shinfo(skb)->gso_size = bnx2x_set_lro_mss(bp, parsing_flags,
+                                                             len_on_bd);
 
 #ifdef BNX2X_STOP_ON_ERROR
        if (pages > min_t(u32, 8, MAX_SKB_FRAGS)*SGE_PAGE_SIZE*PAGES_PER_SGE) {
@@ -344,6 +378,8 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
        if (likely(new_skb)) {
                /* fix ip xsum and give it to the stack */
                /* (no need to map the new skb) */
+               u16 parsing_flags =
+                       le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags);
 
                prefetch(skb);
                prefetch(((char *)(skb)) + L1_CACHE_BYTES);
@@ -373,9 +409,9 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
                }
 
                if (!bnx2x_fill_frag_skb(bp, fp, skb,
-                                        &cqe->fast_path_cqe, cqe_idx)) {
-                       if ((le16_to_cpu(cqe->fast_path_cqe.
-                           pars_flags.flags) & PARSING_FLAGS_VLAN))
+                                        &cqe->fast_path_cqe, cqe_idx,
+                                        parsing_flags)) {
+                       if (parsing_flags & PARSING_FLAGS_VLAN)
                                __vlan_hwaccel_put_tag(skb,
                                                 le16_to_cpu(cqe->fast_path_cqe.
                                                             vlan_tag));
@@ -703,19 +739,20 @@ u16 bnx2x_get_mf_speed(struct bnx2x *bp)
 {
        u16 line_speed = bp->link_vars.line_speed;
        if (IS_MF(bp)) {
-               u16 maxCfg = (bp->mf_config[BP_VN(bp)] &
-                                               FUNC_MF_CFG_MAX_BW_MASK) >>
-                                               FUNC_MF_CFG_MAX_BW_SHIFT;
-               /* Calculate the current MAX line speed limit for the DCC
-                * capable devices
+               u16 maxCfg = bnx2x_extract_max_cfg(bp,
+                                                  bp->mf_config[BP_VN(bp)]);
+
+               /* Calculate the current MAX line speed limit for the MF
+                * devices
                 */
-               if (IS_MF_SD(bp)) {
+               if (IS_MF_SI(bp))
+                       line_speed = (line_speed * maxCfg) / 100;
+               else { /* SD mode */
                        u16 vn_max_rate = maxCfg * 100;
 
                        if (vn_max_rate < line_speed)
                                line_speed = vn_max_rate;
-               } else /* IS_MF_SI(bp)) */
-                       line_speed = (line_speed * maxCfg) / 100;
+               }
        }
 
        return line_speed;
@@ -959,6 +996,23 @@ void bnx2x_free_skbs(struct bnx2x *bp)
        bnx2x_free_rx_skbs(bp);
 }
 
+void bnx2x_update_max_mf_config(struct bnx2x *bp, u32 value)
+{
+       /* load old values */
+       u32 mf_cfg = bp->mf_config[BP_VN(bp)];
+
+       if (value != bnx2x_extract_max_cfg(bp, mf_cfg)) {
+               /* leave all but MAX value */
+               mf_cfg &= ~FUNC_MF_CFG_MAX_BW_MASK;
+
+               /* set new MAX value */
+               mf_cfg |= (value << FUNC_MF_CFG_MAX_BW_SHIFT)
+                               & FUNC_MF_CFG_MAX_BW_MASK;
+
+               bnx2x_fw_command(bp, DRV_MSG_CODE_SET_MF_BW, mf_cfg);
+       }
+}
+
 static void bnx2x_free_msix_irqs(struct bnx2x *bp)
 {
        int i, offset = 1;
@@ -1427,6 +1481,11 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
 
        bnx2x_set_eth_mac(bp, 1);
 
+       if (bp->pending_max) {
+               bnx2x_update_max_mf_config(bp, bp->pending_max);
+               bp->pending_max = 0;
+       }
+
        if (bp->port.pmf)
                bnx2x_initial_phy_init(bp, load_mode);
 
index 03eb4d6..85ea7f2 100644 (file)
@@ -341,6 +341,15 @@ void bnx2x_dcbx_init(struct bnx2x *bp);
  */
 int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state);
 
+/**
+ * Updates MAX part of MF configuration in HW
+ * (if required)
+ *
+ * @param bp
+ * @param value
+ */
+void bnx2x_update_max_mf_config(struct bnx2x *bp, u32 value);
+
 /* dev_close main block */
 int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode);
 
@@ -1044,4 +1053,24 @@ static inline void storm_memset_cmng(struct bnx2x *bp,
 void bnx2x_acquire_phy_lock(struct bnx2x *bp);
 void bnx2x_release_phy_lock(struct bnx2x *bp);
 
+/**
+ * Extracts MAX BW part from MF configuration.
+ *
+ * @param bp
+ * @param mf_cfg
+ *
+ * @return u16
+ */
+static inline u16 bnx2x_extract_max_cfg(struct bnx2x *bp, u32 mf_cfg)
+{
+       u16 max_cfg = (mf_cfg & FUNC_MF_CFG_MAX_BW_MASK) >>
+                             FUNC_MF_CFG_MAX_BW_SHIFT;
+       if (!max_cfg) {
+               BNX2X_ERR("Illegal configuration detected for Max BW - "
+                         "using 100 instead\n");
+               max_cfg = 100;
+       }
+       return max_cfg;
+}
+
 #endif /* BNX2X_CMN_H */
index 5b44a8b..7e92f9d 100644 (file)
@@ -238,7 +238,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        speed |= (cmd->speed_hi << 16);
 
        if (IS_MF_SI(bp)) {
-               u32 param = 0;
+               u32 part;
                u32 line_speed = bp->link_vars.line_speed;
 
                /* use 10G if no link detected */
@@ -251,23 +251,22 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                                       REQ_BC_VER_4_SET_MF_BW);
                        return -EINVAL;
                }
-               if (line_speed < speed) {
-                       BNX2X_DEV_INFO("New speed should be less or equal "
-                                      "to actual line speed\n");
+
+               part = (speed * 100) / line_speed;
+
+               if (line_speed < speed || !part) {
+                       BNX2X_DEV_INFO("Speed setting should be in a range "
+                                      "from 1%% to 100%% "
+                                      "of actual line speed\n");
                        return -EINVAL;
                }
-               /* load old values */
-               param = bp->mf_config[BP_VN(bp)];
-
-               /* leave only MIN value */
-               param &= FUNC_MF_CFG_MIN_BW_MASK;
 
-               /* set new MAX value */
-               param |= (((speed * 100) / line_speed)
-                                << FUNC_MF_CFG_MAX_BW_SHIFT)
-                                 & FUNC_MF_CFG_MAX_BW_MASK;
+               if (bp->state != BNX2X_STATE_OPEN)
+                       /* store value for following "load" */
+                       bp->pending_max = part;
+               else
+                       bnx2x_update_max_mf_config(bp, part);
 
-               bnx2x_fw_command(bp, DRV_MSG_CODE_SET_MF_BW, param);
                return 0;
        }
 
@@ -1781,9 +1780,7 @@ static int bnx2x_test_nvram(struct bnx2x *bp)
                { 0x100, 0x350 }, /* manuf_info */
                { 0x450,  0xf0 }, /* feature_info */
                { 0x640,  0x64 }, /* upgrade_key_info */
-               { 0x6a4,  0x64 },
                { 0x708,  0x70 }, /* manuf_key_info */
-               { 0x778,  0x70 },
                {     0,     0 }
        };
        __be32 buf[0x350 / 4];
@@ -1933,11 +1930,11 @@ static void bnx2x_self_test(struct net_device *dev,
                buf[4] = 1;
                etest->flags |= ETH_TEST_FL_FAILED;
        }
-       if (bp->port.pmf)
-               if (bnx2x_link_test(bp, is_serdes) != 0) {
-                       buf[5] = 1;
-                       etest->flags |= ETH_TEST_FL_FAILED;
-               }
+
+       if (bnx2x_link_test(bp, is_serdes) != 0) {
+               buf[5] = 1;
+               etest->flags |= ETH_TEST_FL_FAILED;
+       }
 
 #ifdef BNX2X_EXTRA_DEBUG
        bnx2x_panic_dump(bp);
index 5a268e9..fa6dbe3 100644 (file)
@@ -241,7 +241,7 @@ static const struct {
        /* Block IGU, MISC, PXP and PXP2 parity errors as long as we don't
         * want to handle "system kill" flow at the moment.
         */
-       BLOCK_PRTY_INFO(PXP, 0x3ffffff, 0x3ffffff, 0x3ffffff, 0x3ffffff),
+       BLOCK_PRTY_INFO(PXP, 0x7ffffff, 0x3ffffff, 0x3ffffff, 0x7ffffff),
        BLOCK_PRTY_INFO_0(PXP2, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff),
        BLOCK_PRTY_INFO_1(PXP2, 0x7ff, 0x7f, 0x7f, 0x7ff),
        BLOCK_PRTY_INFO(HC, 0x7, 0x7, 0x7, 0),
index 7160ec5..dd1210f 100644 (file)
@@ -3948,48 +3948,6 @@ static u8 bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
        return rc;
 }
 
-static void bnx2x_8073_set_xaui_low_power_mode(struct bnx2x *bp,
-                                              struct bnx2x_phy *phy)
-{
-       u16 val;
-       bnx2x_cl45_read(bp, phy,
-                       MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV, &val);
-
-       if (val == 0) {
-               /* Mustn't set low power mode in 8073 A0 */
-               return;
-       }
-
-       /* Disable PLL sequencer (use read-modify-write to clear bit 13) */
-       bnx2x_cl45_read(bp, phy,
-                       MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, &val);
-       val &= ~(1<<13);
-       bnx2x_cl45_write(bp, phy,
-                      MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
-
-       /* PLL controls */
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805E, 0x1077);
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805D, 0x0000);
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805C, 0x030B);
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805B, 0x1240);
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x805A, 0x2490);
-
-       /* Tx Controls */
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A7, 0x0C74);
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A6, 0x9041);
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80A5, 0x4640);
-
-       /* Rx Controls */
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FE, 0x01C4);
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FD, 0x9249);
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, 0x80FC, 0x2015);
-
-       /* Enable PLL sequencer  (use read-modify-write to set bit 13) */
-       bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, &val);
-       val |= (1<<13);
-       bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, MDIO_XS_PLL_SEQUENCER, val);
-}
-
 /******************************************************************/
 /*                     BCM8073 PHY SECTION                       */
 /******************************************************************/
@@ -4148,8 +4106,6 @@ static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy,
 
        bnx2x_8073_set_pause_cl37(params, phy, vars);
 
-       bnx2x_8073_set_xaui_low_power_mode(bp, phy);
-
        bnx2x_cl45_read(bp, phy,
                        MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1);
 
@@ -6519,6 +6475,18 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
                                         MDIO_PMA_DEVAD,
                                         MDIO_PMA_REG_8481_LED1_MASK,
                                         0x80);
+
+                       /* Tell LED3 to blink on source */
+                       bnx2x_cl45_read(bp, phy,
+                                       MDIO_PMA_DEVAD,
+                                       MDIO_PMA_REG_8481_LINK_SIGNAL,
+                                       &val);
+                       val &= ~(7<<6);
+                       val |= (1<<6); /* A83B[8:6]= 1 */
+                       bnx2x_cl45_write(bp, phy,
+                                        MDIO_PMA_DEVAD,
+                                        MDIO_PMA_REG_8481_LINK_SIGNAL,
+                                        val);
                }
                break;
        }
@@ -7720,10 +7688,13 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
        struct bnx2x_phy phy[PORT_MAX];
        struct bnx2x_phy *phy_blk[PORT_MAX];
        u16 val;
-       s8 port;
+       s8 port = 0;
        s8 port_of_path = 0;
-
-       bnx2x_ext_phy_hw_reset(bp, 0);
+       u32 swap_val, swap_override;
+       swap_val = REG_RD(bp,  NIG_REG_PORT_SWAP);
+       swap_override = REG_RD(bp,  NIG_REG_STRAP_OVERRIDE);
+       port ^= (swap_val && swap_override);
+       bnx2x_ext_phy_hw_reset(bp, port);
        /* PART1 - Reset both phys */
        for (port = PORT_MAX - 1; port >= PORT_0; port--) {
                u32 shmem_base, shmem2_base;
index 8cdcf5b..aa03233 100644 (file)
@@ -1974,13 +1974,22 @@ static void bnx2x_init_vn_minmax(struct bnx2x *bp, int vn)
                vn_max_rate = 0;
 
        } else {
+               u32 maxCfg = bnx2x_extract_max_cfg(bp, vn_cfg);
+
                vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >>
                                FUNC_MF_CFG_MIN_BW_SHIFT) * 100;
-               /* If min rate is zero - set it to 1 */
+               /* If fairness is enabled (not all min rates are zeroes) and
+                  if current min rate is zero - set it to 1.
+                  This is a requirement of the algorithm. */
                if (bp->vn_weight_sum && (vn_min_rate == 0))
                        vn_min_rate = DEF_MIN_RATE;
-               vn_max_rate = ((vn_cfg & FUNC_MF_CFG_MAX_BW_MASK) >>
-                               FUNC_MF_CFG_MAX_BW_SHIFT) * 100;
+
+               if (IS_MF_SI(bp))
+                       /* maxCfg in percents of linkspeed */
+                       vn_max_rate = (bp->link_vars.line_speed * maxCfg) / 100;
+               else
+                       /* maxCfg is absolute in 100Mb units */
+                       vn_max_rate = maxCfg * 100;
        }
 
        DP(NETIF_MSG_IFUP,
@@ -2006,7 +2015,8 @@ static void bnx2x_init_vn_minmax(struct bnx2x *bp, int vn)
                m_fair_vn.vn_credit_delta =
                        max_t(u32, (vn_min_rate * (T_FAIR_COEF /
                                                   (8 * bp->vn_weight_sum))),
-                             (bp->cmng.fair_vars.fair_threshold * 2));
+                             (bp->cmng.fair_vars.fair_threshold +
+                                                       MIN_ABOVE_THRESH));
                DP(NETIF_MSG_IFUP, "m_fair_vn.vn_credit_delta %d\n",
                   m_fair_vn.vn_credit_delta);
        }
@@ -2082,8 +2092,9 @@ static void bnx2x_cmng_fns_init(struct bnx2x *bp, u8 read_cfg, u8 cmng_type)
                bnx2x_calc_vn_weight_sum(bp);
 
                /* calculate and set min-max rate for each vn */
-               for (vn = VN_0; vn < E1HVN_MAX; vn++)
-                       bnx2x_init_vn_minmax(bp, vn);
+               if (bp->port.pmf)
+                       for (vn = VN_0; vn < E1HVN_MAX; vn++)
+                               bnx2x_init_vn_minmax(bp, vn);
 
                /* always enable rate shaping and fairness */
                bp->cmng.flags.cmng_enables |=
@@ -2152,13 +2163,6 @@ static void bnx2x_link_attn(struct bnx2x *bp)
                        bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
        }
 
-       /* indicate link status only if link status actually changed */
-       if (prev_link_status != bp->link_vars.link_status)
-               bnx2x_link_report(bp);
-
-       if (IS_MF(bp))
-               bnx2x_link_sync_notify(bp);
-
        if (bp->link_vars.link_up && bp->link_vars.line_speed) {
                int cmng_fns = bnx2x_get_cmng_fns_mode(bp);
 
@@ -2170,6 +2174,13 @@ static void bnx2x_link_attn(struct bnx2x *bp)
                        DP(NETIF_MSG_IFUP,
                           "single function mode without fairness\n");
        }
+
+       if (IS_MF(bp))
+               bnx2x_link_sync_notify(bp);
+
+       /* indicate link status only if link status actually changed */
+       if (prev_link_status != bp->link_vars.link_status)
+               bnx2x_link_report(bp);
 }
 
 void bnx2x__link_status_update(struct bnx2x *bp)
@@ -2301,15 +2312,10 @@ static void bnx2x_rxq_set_mac_filters(struct bnx2x *bp, u16 cl_id, u32 filters)
                /* accept matched ucast */
                drop_all_ucast = 0;
        }
-       if (filters & BNX2X_ACCEPT_MULTICAST) {
+       if (filters & BNX2X_ACCEPT_MULTICAST)
                /* accept matched mcast */
                drop_all_mcast = 0;
-               if (IS_MF_SI(bp))
-                       /* since mcast addresses won't arrive with ovlan,
-                        * fw needs to accept all of them in
-                        * switch-independent mode */
-                       accp_all_mcast = 1;
-       }
+
        if (filters & BNX2X_ACCEPT_ALL_UNICAST) {
                /* accept all mcast */
                drop_all_ucast = 0;
@@ -4281,9 +4287,12 @@ void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
                def_q_filters |= BNX2X_ACCEPT_UNICAST | BNX2X_ACCEPT_BROADCAST |
                                BNX2X_ACCEPT_MULTICAST;
 #ifdef BCM_CNIC
-               cl_id = bnx2x_fcoe(bp, cl_id);
-               bnx2x_rxq_set_mac_filters(bp, cl_id, BNX2X_ACCEPT_UNICAST |
-                                         BNX2X_ACCEPT_MULTICAST);
+               if (!NO_FCOE(bp)) {
+                       cl_id = bnx2x_fcoe(bp, cl_id);
+                       bnx2x_rxq_set_mac_filters(bp, cl_id,
+                                                 BNX2X_ACCEPT_UNICAST |
+                                                 BNX2X_ACCEPT_MULTICAST);
+               }
 #endif
                break;
 
@@ -4291,18 +4300,29 @@ void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
                def_q_filters |= BNX2X_ACCEPT_UNICAST | BNX2X_ACCEPT_BROADCAST |
                                BNX2X_ACCEPT_ALL_MULTICAST;
 #ifdef BCM_CNIC
-               cl_id = bnx2x_fcoe(bp, cl_id);
-               bnx2x_rxq_set_mac_filters(bp, cl_id, BNX2X_ACCEPT_UNICAST |
-                                         BNX2X_ACCEPT_MULTICAST);
+               /*
+                *  Prevent duplication of multicast packets by configuring FCoE
+                *  L2 Client to receive only matched unicast frames.
+                */
+               if (!NO_FCOE(bp)) {
+                       cl_id = bnx2x_fcoe(bp, cl_id);
+                       bnx2x_rxq_set_mac_filters(bp, cl_id,
+                                                 BNX2X_ACCEPT_UNICAST);
+               }
 #endif
                break;
 
        case BNX2X_RX_MODE_PROMISC:
                def_q_filters |= BNX2X_PROMISCUOUS_MODE;
 #ifdef BCM_CNIC
-               cl_id = bnx2x_fcoe(bp, cl_id);
-               bnx2x_rxq_set_mac_filters(bp, cl_id, BNX2X_ACCEPT_UNICAST |
-                                         BNX2X_ACCEPT_MULTICAST);
+               /*
+                *  Prevent packets duplication by configuring DROP_ALL for FCoE
+                *  L2 Client.
+                */
+               if (!NO_FCOE(bp)) {
+                       cl_id = bnx2x_fcoe(bp, cl_id);
+                       bnx2x_rxq_set_mac_filters(bp, cl_id, BNX2X_ACCEPT_NONE);
+               }
 #endif
                /* pass management unicast packets as well */
                llh_mask |= NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_UNCST;
@@ -5296,10 +5316,6 @@ static int bnx2x_init_hw_common(struct bnx2x *bp, u32 load_code)
                }
        }
 
-       bp->port.need_hw_lock = bnx2x_hw_lock_required(bp,
-                                                      bp->common.shmem_base,
-                                                      bp->common.shmem2_base);
-
        bnx2x_setup_fan_failure_detection(bp);
 
        /* clear PXP2 attentions */
@@ -5503,9 +5519,6 @@ static int bnx2x_init_hw_port(struct bnx2x *bp)
 
        bnx2x_init_block(bp, MCP_BLOCK, init_stage);
        bnx2x_init_block(bp, DMAE_BLOCK, init_stage);
-       bp->port.need_hw_lock = bnx2x_hw_lock_required(bp,
-                                                      bp->common.shmem_base,
-                                                      bp->common.shmem2_base);
        if (bnx2x_fan_failure_det_req(bp, bp->common.shmem_base,
                                      bp->common.shmem2_base, port)) {
                u32 reg_addr = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
@@ -8379,6 +8392,17 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
                 (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN))
                bp->mdio.prtad =
                        XGXS_EXT_PHY_ADDR(ext_phy_config);
+
+       /*
+        * Check if hw lock is required to access MDC/MDIO bus to the PHY(s)
+        * In MF mode, it is set to cover self test cases
+        */
+       if (IS_MF(bp))
+               bp->port.need_hw_lock = 1;
+       else
+               bp->port.need_hw_lock = bnx2x_hw_lock_required(bp,
+                                                       bp->common.shmem_base,
+                                                       bp->common.shmem2_base);
 }
 
 static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp)
index bda60d5..3445ded 100644 (file)
@@ -1239,14 +1239,14 @@ void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event)
        if (unlikely(bp->panic))
                return;
 
+       bnx2x_stats_stm[bp->stats_state][event].action(bp);
+
        /* Protect a state change flow */
        spin_lock_bh(&bp->stats_lock);
        state = bp->stats_state;
        bp->stats_state = bnx2x_stats_stm[state][event].next_state;
        spin_unlock_bh(&bp->stats_lock);
 
-       bnx2x_stats_stm[state][event].action(bp);
-
        if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp))
                DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n",
                   state, event, bp->stats_state);
index 171782e..a5d5d0b 100644 (file)
@@ -281,23 +281,23 @@ static inline int __check_agg_selection_timer(struct port *port)
 }
 
 /**
- * __get_rx_machine_lock - lock the port's RX machine
+ * __get_state_machine_lock - lock the port's state machines
  * @port: the port we're looking at
  *
  */
-static inline void __get_rx_machine_lock(struct port *port)
+static inline void __get_state_machine_lock(struct port *port)
 {
-       spin_lock_bh(&(SLAVE_AD_INFO(port->slave).rx_machine_lock));
+       spin_lock_bh(&(SLAVE_AD_INFO(port->slave).state_machine_lock));
 }
 
 /**
- * __release_rx_machine_lock - unlock the port's RX machine
+ * __release_state_machine_lock - unlock the port's state machines
  * @port: the port we're looking at
  *
  */
-static inline void __release_rx_machine_lock(struct port *port)
+static inline void __release_state_machine_lock(struct port *port)
 {
-       spin_unlock_bh(&(SLAVE_AD_INFO(port->slave).rx_machine_lock));
+       spin_unlock_bh(&(SLAVE_AD_INFO(port->slave).state_machine_lock));
 }
 
 /**
@@ -388,14 +388,14 @@ static u8 __get_duplex(struct port *port)
 }
 
 /**
- * __initialize_port_locks - initialize a port's RX machine spinlock
+ * __initialize_port_locks - initialize a port's STATE machine spinlock
  * @port: the port we're looking at
  *
  */
 static inline void __initialize_port_locks(struct port *port)
 {
        // make sure it isn't called twice
-       spin_lock_init(&(SLAVE_AD_INFO(port->slave).rx_machine_lock));
+       spin_lock_init(&(SLAVE_AD_INFO(port->slave).state_machine_lock));
 }
 
 //conversions
@@ -1025,9 +1025,6 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
 {
        rx_states_t last_state;
 
-       // Lock to prevent 2 instances of this function to run simultaneously(rx interrupt and periodic machine callback)
-       __get_rx_machine_lock(port);
-
        // keep current State Machine state to compare later if it was changed
        last_state = port->sm_rx_state;
 
@@ -1133,7 +1130,6 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
                                pr_err("%s: An illegal loopback occurred on adapter (%s).\n"
                                       "Check the configuration to verify that all adapters are connected to 802.3ad compliant switch ports\n",
                                       port->slave->dev->master->name, port->slave->dev->name);
-                               __release_rx_machine_lock(port);
                                return;
                        }
                        __update_selected(lacpdu, port);
@@ -1153,7 +1149,6 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
                        break;
                }
        }
-       __release_rx_machine_lock(port);
 }
 
 /**
@@ -2155,6 +2150,12 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
                        goto re_arm;
                }
 
+               /* Lock around state machines to protect data accessed
+                * by all (e.g., port->sm_vars).  ad_rx_machine may run
+                * concurrently due to incoming LACPDU.
+                */
+               __get_state_machine_lock(port);
+
                ad_rx_machine(NULL, port);
                ad_periodic_machine(port);
                ad_port_selection_logic(port);
@@ -2164,6 +2165,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
                // turn off the BEGIN bit, since we already handled it
                if (port->sm_vars & AD_PORT_BEGIN)
                        port->sm_vars &= ~AD_PORT_BEGIN;
+
+               __release_state_machine_lock(port);
        }
 
 re_arm:
@@ -2200,7 +2203,10 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u
                case AD_TYPE_LACPDU:
                        pr_debug("Received LACPDU on port %d\n",
                                 port->actor_port_number);
+                       /* Protect against concurrent state machines */
+                       __get_state_machine_lock(port);
                        ad_rx_machine(lacpdu, port);
+                       __release_state_machine_lock(port);
                        break;
 
                case AD_TYPE_MARKER:
@@ -2470,6 +2476,10 @@ int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct pac
        if (!(dev->flags & IFF_MASTER))
                goto out;
 
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (!skb)
+               goto out;
+
        if (!pskb_may_pull(skb, sizeof(struct lacpdu)))
                goto out;
 
index 2c46a15..b28baff 100644 (file)
@@ -264,7 +264,8 @@ struct ad_bond_info {
 struct ad_slave_info {
        struct aggregator aggregator;       // 802.3ad aggregator structure
        struct port port;                   // 802.3ad port structure
-       spinlock_t rx_machine_lock; // To avoid race condition between callback and receive interrupt
+       spinlock_t state_machine_lock; /* mutex state machines vs.
+                                         incoming LACPDU */
        u16 id;
 };
 
index f4e638c..5c6fba8 100644 (file)
@@ -326,6 +326,10 @@ static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct
                goto out;
        }
 
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (!skb)
+               goto out;
+
        if (!pskb_may_pull(skb, arp_hdr_len(bond_dev)))
                goto out;
 
index b1025b8..163e0b0 100644 (file)
@@ -2733,6 +2733,10 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack
        if (!slave || !slave_do_arp_validate(bond, slave))
                goto out_unlock;
 
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (!skb)
+               goto out_unlock;
+
        if (!pskb_may_pull(skb, arp_hdr_len(dev)))
                goto out_unlock;
 
index d5a9db6..5dec456 100644 (file)
@@ -23,7 +23,7 @@ config CAN_SLCAN
 
          As only the sending and receiving of CAN frames is implemented, this
          driver should work with the (serial/USB) CAN hardware from:
-         www.canusb.com / www.can232.com / www.mictronic.com / www.canhack.de
+         www.canusb.com / www.can232.com / www.mictronics.de / www.canhack.de
 
          Userspace tools to attach the SLCAN line discipline (slcan_attach,
          slcand) can be found in the can-utils at the SocketCAN SVN, see
@@ -117,6 +117,8 @@ source "drivers/net/can/sja1000/Kconfig"
 
 source "drivers/net/can/usb/Kconfig"
 
+source "drivers/net/can/softing/Kconfig"
+
 config CAN_DEBUG_DEVICES
        bool "CAN devices debugging messages"
        depends on CAN
index 07ca159..53c82a7 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_CAN_DEV)           += can-dev.o
 can-dev-y                      := dev.o
 
 obj-y                          += usb/
+obj-y                          += softing/
 
 obj-$(CONFIG_CAN_SJA1000)      += sja1000/
 obj-$(CONFIG_CAN_MSCAN)                += mscan/
index 7ef83d0..57d2ffb 100644 (file)
@@ -2,7 +2,7 @@
  * at91_can.c - CAN network driver for AT91 SoC CAN controller
  *
  * (C) 2007 by Hans J. Koch <hjk@hansjkoch.de>
- * (C) 2008, 2009, 2010 by Marc Kleine-Budde <kernel@pengutronix.de>
+ * (C) 2008, 2009, 2010, 2011 by Marc Kleine-Budde <kernel@pengutronix.de>
  *
  * This software may be distributed under the terms of the GNU General
  * Public License ("GPL") version 2 as distributed in the 'COPYING'
@@ -30,6 +30,7 @@
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/platform_device.h>
+#include <linux/rtnetlink.h>
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
 
 #include <mach/board.h>
 
-#define AT91_NAPI_WEIGHT       12
+#define AT91_NAPI_WEIGHT       11
 
 /*
  * RX/TX Mailbox split
  * don't dare to touch
  */
-#define AT91_MB_RX_NUM         12
+#define AT91_MB_RX_NUM         11
 #define AT91_MB_TX_SHIFT       2
 
-#define AT91_MB_RX_FIRST       0
+#define AT91_MB_RX_FIRST       1
 #define AT91_MB_RX_LAST                (AT91_MB_RX_FIRST + AT91_MB_RX_NUM - 1)
 
 #define AT91_MB_RX_MASK(i)     ((1 << (i)) - 1)
 #define AT91_MB_RX_SPLIT       8
 #define AT91_MB_RX_LOW_LAST    (AT91_MB_RX_SPLIT - 1)
-#define AT91_MB_RX_LOW_MASK    (AT91_MB_RX_MASK(AT91_MB_RX_SPLIT))
+#define AT91_MB_RX_LOW_MASK    (AT91_MB_RX_MASK(AT91_MB_RX_SPLIT) & \
+                                ~AT91_MB_RX_MASK(AT91_MB_RX_FIRST))
 
 #define AT91_MB_TX_NUM         (1 << AT91_MB_TX_SHIFT)
 #define AT91_MB_TX_FIRST       (AT91_MB_RX_LAST + 1)
@@ -168,6 +170,8 @@ struct at91_priv {
 
        struct clk              *clk;
        struct at91_can_data    *pdata;
+
+       canid_t                 mb0_id;
 };
 
 static struct can_bittiming_const at91_bittiming_const = {
@@ -220,6 +224,18 @@ static inline void set_mb_mode(const struct at91_priv *priv, unsigned int mb,
        set_mb_mode_prio(priv, mb, mode, 0);
 }
 
+static inline u32 at91_can_id_to_reg_mid(canid_t can_id)
+{
+       u32 reg_mid;
+
+       if (can_id & CAN_EFF_FLAG)
+               reg_mid = (can_id & CAN_EFF_MASK) | AT91_MID_MIDE;
+       else
+               reg_mid = (can_id & CAN_SFF_MASK) << 18;
+
+       return reg_mid;
+}
+
 /*
  * Swtich transceiver on or off
  */
@@ -233,12 +249,22 @@ static void at91_setup_mailboxes(struct net_device *dev)
 {
        struct at91_priv *priv = netdev_priv(dev);
        unsigned int i;
+       u32 reg_mid;
 
        /*
-        * The first 12 mailboxes are used as a reception FIFO. The
-        * last mailbox is configured with overwrite option. The
-        * overwrite flag indicates a FIFO overflow.
+        * Due to a chip bug (errata 50.2.6.3 & 50.3.5.3) the first
+        * mailbox is disabled. The next 11 mailboxes are used as a
+        * reception FIFO. The last mailbox is configured with
+        * overwrite option. The overwrite flag indicates a FIFO
+        * overflow.
         */
+       reg_mid = at91_can_id_to_reg_mid(priv->mb0_id);
+       for (i = 0; i < AT91_MB_RX_FIRST; i++) {
+               set_mb_mode(priv, i, AT91_MB_MODE_DISABLED);
+               at91_write(priv, AT91_MID(i), reg_mid);
+               at91_write(priv, AT91_MCR(i), 0x0);     /* clear dlc */
+       }
+
        for (i = AT91_MB_RX_FIRST; i < AT91_MB_RX_LAST; i++)
                set_mb_mode(priv, i, AT91_MB_MODE_RX);
        set_mb_mode(priv, AT91_MB_RX_LAST, AT91_MB_MODE_RX_OVRWR);
@@ -254,7 +280,8 @@ static void at91_setup_mailboxes(struct net_device *dev)
                set_mb_mode_prio(priv, i, AT91_MB_MODE_TX, 0);
 
        /* Reset tx and rx helper pointers */
-       priv->tx_next = priv->tx_echo = priv->rx_next = 0;
+       priv->tx_next = priv->tx_echo = 0;
+       priv->rx_next = AT91_MB_RX_FIRST;
 }
 
 static int at91_set_bittiming(struct net_device *dev)
@@ -372,12 +399,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
                netdev_err(dev, "BUG! TX buffer full when queue awake!\n");
                return NETDEV_TX_BUSY;
        }
-
-       if (cf->can_id & CAN_EFF_FLAG)
-               reg_mid = (cf->can_id & CAN_EFF_MASK) | AT91_MID_MIDE;
-       else
-               reg_mid = (cf->can_id & CAN_SFF_MASK) << 18;
-
+       reg_mid = at91_can_id_to_reg_mid(cf->can_id);
        reg_mcr = ((cf->can_id & CAN_RTR_FLAG) ? AT91_MCR_MRTR : 0) |
                (cf->can_dlc << 16) | AT91_MCR_MTCR;
 
@@ -539,27 +561,31 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb)
  *
  * Theory of Operation:
  *
- * 12 of the 16 mailboxes on the chip are reserved for RX. we split
- * them into 2 groups. The lower group holds 8 and upper 4 mailboxes.
+ * 11 of the 16 mailboxes on the chip are reserved for RX. we split
+ * them into 2 groups. The lower group holds 7 and upper 4 mailboxes.
  *
  * Like it or not, but the chip always saves a received CAN message
  * into the first free mailbox it finds (starting with the
  * lowest). This makes it very difficult to read the messages in the
  * right order from the chip. This is how we work around that problem:
  *
- * The first message goes into mb nr. 0 and issues an interrupt. All
+ * The first message goes into mb nr. 1 and issues an interrupt. All
  * rx ints are disabled in the interrupt handler and a napi poll is
  * scheduled. We read the mailbox, but do _not_ reenable the mb (to
  * receive another message).
  *
  *    lower mbxs      upper
- *   ______^______    __^__
- *  /             \  /     \
+ *     ____^______    __^__
+ *    /           \  /     \
  * +-+-+-+-+-+-+-+-++-+-+-+-+
- * |x|x|x|x|x|x|x|x|| | | | |
+ * | |x|x|x|x|x|x|x|| | | | |
  * +-+-+-+-+-+-+-+-++-+-+-+-+
  *  0 0 0 0 0 0  0 0 0 0 1 1  \ mail
  *  0 1 2 3 4 5  6 7 8 9 0 1  / box
+ *  ^
+ *  |
+ *   \
+ *     unused, due to chip bug
  *
  * The variable priv->rx_next points to the next mailbox to read a
  * message from. As long we're in the lower mailboxes we just read the
@@ -590,10 +616,10 @@ static int at91_poll_rx(struct net_device *dev, int quota)
                        "order of incoming frames cannot be guaranteed\n");
 
  again:
-       for (mb = find_next_bit(addr, AT91_MB_RX_NUM, priv->rx_next);
-            mb < AT91_MB_RX_NUM && quota > 0;
+       for (mb = find_next_bit(addr, AT91_MB_RX_LAST + 1, priv->rx_next);
+            mb < AT91_MB_RX_LAST + 1 && quota > 0;
             reg_sr = at91_read(priv, AT91_SR),
-            mb = find_next_bit(addr, AT91_MB_RX_NUM, ++priv->rx_next)) {
+            mb = find_next_bit(addr, AT91_MB_RX_LAST + 1, ++priv->rx_next)) {
                at91_read_msg(dev, mb);
 
                /* reactivate mailboxes */
@@ -610,8 +636,8 @@ static int at91_poll_rx(struct net_device *dev, int quota)
 
        /* upper group completed, look again in lower */
        if (priv->rx_next > AT91_MB_RX_LOW_LAST &&
-           quota > 0 && mb >= AT91_MB_RX_NUM) {
-               priv->rx_next = 0;
+           quota > 0 && mb > AT91_MB_RX_LAST) {
+               priv->rx_next = AT91_MB_RX_FIRST;
                goto again;
        }
 
@@ -1037,6 +1063,64 @@ static const struct net_device_ops at91_netdev_ops = {
        .ndo_start_xmit = at91_start_xmit,
 };
 
+static ssize_t at91_sysfs_show_mb0_id(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct at91_priv *priv = netdev_priv(to_net_dev(dev));
+
+       if (priv->mb0_id & CAN_EFF_FLAG)
+               return snprintf(buf, PAGE_SIZE, "0x%08x\n", priv->mb0_id);
+       else
+               return snprintf(buf, PAGE_SIZE, "0x%03x\n", priv->mb0_id);
+}
+
+static ssize_t at91_sysfs_set_mb0_id(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct net_device *ndev = to_net_dev(dev);
+       struct at91_priv *priv = netdev_priv(ndev);
+       unsigned long can_id;
+       ssize_t ret;
+       int err;
+
+       rtnl_lock();
+
+       if (ndev->flags & IFF_UP) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       err = strict_strtoul(buf, 0, &can_id);
+       if (err) {
+               ret = err;
+               goto out;
+       }
+
+       if (can_id & CAN_EFF_FLAG)
+               can_id &= CAN_EFF_MASK | CAN_EFF_FLAG;
+       else
+               can_id &= CAN_SFF_MASK;
+
+       priv->mb0_id = can_id;
+       ret = count;
+
+ out:
+       rtnl_unlock();
+       return ret;
+}
+
+static DEVICE_ATTR(mb0_id, S_IWUSR | S_IRUGO,
+       at91_sysfs_show_mb0_id, at91_sysfs_set_mb0_id);
+
+static struct attribute *at91_sysfs_attrs[] = {
+       &dev_attr_mb0_id.attr,
+       NULL,
+};
+
+static struct attribute_group at91_sysfs_attr_group = {
+       .attrs = at91_sysfs_attrs,
+};
+
 static int __devinit at91_can_probe(struct platform_device *pdev)
 {
        struct net_device *dev;
@@ -1082,6 +1166,7 @@ static int __devinit at91_can_probe(struct platform_device *pdev)
        dev->netdev_ops = &at91_netdev_ops;
        dev->irq = irq;
        dev->flags |= IFF_ECHO;
+       dev->sysfs_groups[0] = &at91_sysfs_attr_group;
 
        priv = netdev_priv(dev);
        priv->can.clock.freq = clk_get_rate(clk);
@@ -1093,6 +1178,7 @@ static int __devinit at91_can_probe(struct platform_device *pdev)
        priv->dev = dev;
        priv->clk = clk;
        priv->pdata = pdev->dev.platform_data;
+       priv->mb0_id = 0x7ff;
 
        netif_napi_add(dev, &priv->napi, at91_poll, AT91_NAPI_WEIGHT);
 
index b9a6d7a..366f5cc 100644 (file)
@@ -1618,7 +1618,7 @@ static ssize_t ican3_sysfs_set_term(struct device *dev,
        return count;
 }
 
-static DEVICE_ATTR(termination, S_IWUGO | S_IRUGO, ican3_sysfs_show_term,
+static DEVICE_ATTR(termination, S_IWUSR | S_IRUGO, ican3_sysfs_show_term,
                                                   ican3_sysfs_set_term);
 
 static struct attribute *ican3_sysfs_attrs[] = {
index 7ab534a..7513c45 100644 (file)
@@ -940,7 +940,7 @@ static int mcp251x_open(struct net_device *net)
                goto open_unlock;
        }
 
-       priv->wq = create_freezeable_workqueue("mcp251x_wq");
+       priv->wq = create_freezable_workqueue("mcp251x_wq");
        INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler);
        INIT_WORK(&priv->restart_work, mcp251x_restart_work_handler);
 
index 27d1d39..d387069 100644 (file)
@@ -1,5 +1,5 @@
 config CAN_MSCAN
-       depends on CAN_DEV && (PPC || M68K || M68KNOMMU)
+       depends on CAN_DEV && (PPC || M68K)
        tristate "Support for Freescale MSCAN based chips"
        ---help---
          The Motorola Scalable Controller Area Network (MSCAN) definition
index c42e972..e54712b 100644 (file)
@@ -185,7 +185,7 @@ struct pch_can_priv {
 
 static struct can_bittiming_const pch_can_bittiming_const = {
        .name = KBUILD_MODNAME,
-       .tseg1_min = 1,
+       .tseg1_min = 2,
        .tseg1_max = 16,
        .tseg2_min = 1,
        .tseg2_max = 8,
@@ -959,13 +959,13 @@ static void __devexit pch_can_remove(struct pci_dev *pdev)
        struct pch_can_priv *priv = netdev_priv(ndev);
 
        unregister_candev(priv->ndev);
-       pci_iounmap(pdev, priv->regs);
        if (priv->use_msi)
                pci_disable_msi(priv->dev);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
        pch_can_reset(priv);
+       pci_iounmap(pdev, priv->regs);
        free_candev(priv->ndev);
 }
 
@@ -1238,6 +1238,7 @@ static int __devinit pch_can_probe(struct pci_dev *pdev,
                priv->use_msi = 0;
        } else {
                netdev_err(ndev, "PCH CAN opened with MSI\n");
+               pci_set_master(pdev);
                priv->use_msi = 1;
        }
 
diff --git a/drivers/net/can/softing/Kconfig b/drivers/net/can/softing/Kconfig
new file mode 100644 (file)
index 0000000..5de46a9
--- /dev/null
@@ -0,0 +1,30 @@
+config CAN_SOFTING
+       tristate "Softing Gmbh CAN generic support"
+       depends on CAN_DEV && HAS_IOMEM
+       ---help---
+         Support for CAN cards from Softing Gmbh & some cards
+         from Vector Gmbh.
+         Softing Gmbh CAN cards come with 1 or 2 physical busses.
+         Those cards typically use Dual Port RAM to communicate
+         with the host CPU. The interface is then identical for PCI
+         and PCMCIA cards. This driver operates on a platform device,
+         which has been created by softing_cs or softing_pci driver.
+         Warning:
+         The API of the card does not allow fine control per bus, but
+         controls the 2 busses on the card together.
+         As such, some actions (start/stop/busoff recovery) on 1 bus
+         must bring down the other bus too temporarily.
+
+config CAN_SOFTING_CS
+       tristate "Softing Gmbh CAN pcmcia cards"
+       depends on PCMCIA
+       depends on CAN_SOFTING
+       ---help---
+         Support for PCMCIA cards from Softing Gmbh & some cards
+         from Vector Gmbh.
+         You need firmware for these, which you can get at
+         http://developer.berlios.de/projects/socketcan/
+         This version of the driver is written against
+         firmware version 4.6 (softing-fw-4.6-binaries.tar.gz)
+         In order to use the card as CAN device, you need the Softing generic
+         support too.
diff --git a/drivers/net/can/softing/Makefile b/drivers/net/can/softing/Makefile
new file mode 100644 (file)
index 0000000..c5e5016
--- /dev/null
@@ -0,0 +1,6 @@
+
+softing-y := softing_main.o softing_fw.o
+obj-$(CONFIG_CAN_SOFTING) += softing.o
+obj-$(CONFIG_CAN_SOFTING_CS) += softing_cs.o
+
+ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/softing/softing.h b/drivers/net/can/softing/softing.h
new file mode 100644 (file)
index 0000000..7ec9f4d
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * softing common interfaces
+ *
+ * by Kurt Van Dijck, 2008-2010
+ */
+
+#include <linux/atomic.h>
+#include <linux/netdevice.h>
+#include <linux/ktime.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+
+#include "softing_platform.h"
+
+struct softing;
+
+struct softing_priv {
+       struct can_priv can; /* must be the first member! */
+       struct net_device *netdev;
+       struct softing *card;
+       struct {
+               int pending;
+               /* variables wich hold the circular buffer */
+               int echo_put;
+               int echo_get;
+       } tx;
+       struct can_bittiming_const btr_const;
+       int index;
+       uint8_t output;
+       uint16_t chip;
+};
+#define netdev2softing(netdev) ((struct softing_priv *)netdev_priv(netdev))
+
+struct softing {
+       const struct softing_platform_data *pdat;
+       struct platform_device *pdev;
+       struct net_device *net[2];
+       spinlock_t spin; /* protect this structure & DPRAM access */
+       ktime_t ts_ref;
+       ktime_t ts_overflow; /* timestamp overflow value, in ktime */
+
+       struct {
+               /* indication of firmware status */
+               int up;
+               /* protection of the 'up' variable */
+               struct mutex lock;
+       } fw;
+       struct {
+               int nr;
+               int requested;
+               int svc_count;
+               unsigned int dpram_position;
+       } irq;
+       struct {
+               int pending;
+               int last_bus;
+               /*
+                * keep the bus that last tx'd a message,
+                * in order to let every netdev queue resume
+                */
+       } tx;
+       __iomem uint8_t *dpram;
+       unsigned long dpram_phys;
+       unsigned long dpram_size;
+       struct {
+               uint16_t fw_version, hw_version, license, serial;
+               uint16_t chip[2];
+               unsigned int freq; /* remote cpu's operating frequency */
+       } id;
+};
+
+extern int softing_default_output(struct net_device *netdev);
+
+extern ktime_t softing_raw2ktime(struct softing *card, u32 raw);
+
+extern int softing_chip_poweron(struct softing *card);
+
+extern int softing_bootloader_command(struct softing *card, int16_t cmd,
+               const char *msg);
+
+/* Load firmware after reset */
+extern int softing_load_fw(const char *file, struct softing *card,
+                       __iomem uint8_t *virt, unsigned int size, int offset);
+
+/* Load final application firmware after bootloader */
+extern int softing_load_app_fw(const char *file, struct softing *card);
+
+/*
+ * enable or disable irq
+ * only called with fw.lock locked
+ */
+extern int softing_enable_irq(struct softing *card, int enable);
+
+/* start/stop 1 bus on card */
+extern int softing_startstop(struct net_device *netdev, int up);
+
+/* netif_rx() */
+extern int softing_netdev_rx(struct net_device *netdev,
+               const struct can_frame *msg, ktime_t ktime);
+
+/* SOFTING DPRAM mappings */
+#define DPRAM_RX               0x0000
+       #define DPRAM_RX_SIZE   32
+       #define DPRAM_RX_CNT    16
+#define DPRAM_RX_RD            0x0201  /* uint8_t */
+#define DPRAM_RX_WR            0x0205  /* uint8_t */
+#define DPRAM_RX_LOST          0x0207  /* uint8_t */
+
+#define DPRAM_FCT_PARAM                0x0300  /* int16_t [20] */
+#define DPRAM_FCT_RESULT       0x0328  /* int16_t */
+#define DPRAM_FCT_HOST         0x032b  /* uint16_t */
+
+#define DPRAM_INFO_BUSSTATE    0x0331  /* uint16_t */
+#define DPRAM_INFO_BUSSTATE2   0x0335  /* uint16_t */
+#define DPRAM_INFO_ERRSTATE    0x0339  /* uint16_t */
+#define DPRAM_INFO_ERRSTATE2   0x033d  /* uint16_t */
+#define DPRAM_RESET            0x0341  /* uint16_t */
+#define DPRAM_CLR_RECV_FIFO    0x0345  /* uint16_t */
+#define DPRAM_RESET_TIME       0x034d  /* uint16_t */
+#define DPRAM_TIME             0x0350  /* uint64_t */
+#define DPRAM_WR_START         0x0358  /* uint8_t */
+#define DPRAM_WR_END           0x0359  /* uint8_t */
+#define DPRAM_RESET_RX_FIFO    0x0361  /* uint16_t */
+#define DPRAM_RESET_TX_FIFO    0x0364  /* uint8_t */
+#define DPRAM_READ_FIFO_LEVEL  0x0365  /* uint8_t */
+#define DPRAM_RX_FIFO_LEVEL    0x0366  /* uint16_t */
+#define DPRAM_TX_FIFO_LEVEL    0x0366  /* uint16_t */
+
+#define DPRAM_TX               0x0400  /* uint16_t */
+       #define DPRAM_TX_SIZE   16
+       #define DPRAM_TX_CNT    32
+#define DPRAM_TX_RD            0x0601  /* uint8_t */
+#define DPRAM_TX_WR            0x0605  /* uint8_t */
+
+#define DPRAM_COMMAND          0x07e0  /* uint16_t */
+#define DPRAM_RECEIPT          0x07f0  /* uint16_t */
+#define DPRAM_IRQ_TOHOST       0x07fe  /* uint8_t */
+#define DPRAM_IRQ_TOCARD       0x07ff  /* uint8_t */
+
+#define DPRAM_V2_RESET         0x0e00  /* uint8_t */
+#define DPRAM_V2_IRQ_TOHOST    0x0e02  /* uint8_t */
+
+#define TXMAX  (DPRAM_TX_CNT - 1)
+
+/* DPRAM return codes */
+#define RES_NONE       0
+#define RES_OK         1
+#define RES_NOK                2
+#define RES_UNKNOWN    3
+/* DPRAM flags */
+#define CMD_TX         0x01
+#define CMD_ACK                0x02
+#define CMD_XTD                0x04
+#define CMD_RTR                0x08
+#define CMD_ERR                0x10
+#define CMD_BUS2       0x80
+
+/* returned fifo entry bus state masks */
+#define SF_MASK_BUSOFF         0x80
+#define SF_MASK_EPASSIVE       0x60
+
+/* bus states */
+#define STATE_BUSOFF   2
+#define STATE_EPASSIVE 1
+#define STATE_EACTIVE  0
diff --git a/drivers/net/can/softing/softing_cs.c b/drivers/net/can/softing/softing_cs.c
new file mode 100644 (file)
index 0000000..c11bb4d
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2008-2010
+ *
+ * - Kurt Van Dijck, EIA Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#include "softing_platform.h"
+
+static int softingcs_index;
+static spinlock_t softingcs_index_lock;
+
+static int softingcs_reset(struct platform_device *pdev, int v);
+static int softingcs_enable_irq(struct platform_device *pdev, int v);
+
+/*
+ * platform_data descriptions
+ */
+#define MHZ (1000*1000)
+static const struct softing_platform_data softingcs_platform_data[] = {
+{
+       .name = "CANcard",
+       .manf = 0x0168, .prod = 0x001,
+       .generation = 1,
+       .nbus = 2,
+       .freq = 16 * MHZ, .max_brp = 32, .max_sjw = 4,
+       .dpram_size = 0x0800,
+       .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
+       .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
+       .app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
+       .reset = softingcs_reset,
+       .enable_irq = softingcs_enable_irq,
+}, {
+       .name = "CANcard-NEC",
+       .manf = 0x0168, .prod = 0x002,
+       .generation = 1,
+       .nbus = 2,
+       .freq = 16 * MHZ, .max_brp = 32, .max_sjw = 4,
+       .dpram_size = 0x0800,
+       .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
+       .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
+       .app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
+       .reset = softingcs_reset,
+       .enable_irq = softingcs_enable_irq,
+}, {
+       .name = "CANcard-SJA",
+       .manf = 0x0168, .prod = 0x004,
+       .generation = 1,
+       .nbus = 2,
+       .freq = 20 * MHZ, .max_brp = 32, .max_sjw = 4,
+       .dpram_size = 0x0800,
+       .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
+       .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
+       .app = {0x0010, 0x0d0000, fw_dir "cansja.bin",},
+       .reset = softingcs_reset,
+       .enable_irq = softingcs_enable_irq,
+}, {
+       .name = "CANcard-2",
+       .manf = 0x0168, .prod = 0x005,
+       .generation = 2,
+       .nbus = 2,
+       .freq = 24 * MHZ, .max_brp = 64, .max_sjw = 4,
+       .dpram_size = 0x1000,
+       .boot = {0x0000, 0x000000, fw_dir "bcard2.bin",},
+       .load = {0x0120, 0x00f600, fw_dir "ldcard2.bin",},
+       .app = {0x0010, 0x0d0000, fw_dir "cancrd2.bin",},
+       .reset = softingcs_reset,
+       .enable_irq = NULL,
+}, {
+       .name = "Vector-CANcard",
+       .manf = 0x0168, .prod = 0x081,
+       .generation = 1,
+       .nbus = 2,
+       .freq = 16 * MHZ, .max_brp = 64, .max_sjw = 4,
+       .dpram_size = 0x0800,
+       .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
+       .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
+       .app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
+       .reset = softingcs_reset,
+       .enable_irq = softingcs_enable_irq,
+}, {
+       .name = "Vector-CANcard-SJA",
+       .manf = 0x0168, .prod = 0x084,
+       .generation = 1,
+       .nbus = 2,
+       .freq = 20 * MHZ, .max_brp = 32, .max_sjw = 4,
+       .dpram_size = 0x0800,
+       .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
+       .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
+       .app = {0x0010, 0x0d0000, fw_dir "cansja.bin",},
+       .reset = softingcs_reset,
+       .enable_irq = softingcs_enable_irq,
+}, {
+       .name = "Vector-CANcard-2",
+       .manf = 0x0168, .prod = 0x085,
+       .generation = 2,
+       .nbus = 2,
+       .freq = 24 * MHZ, .max_brp = 64, .max_sjw = 4,
+       .dpram_size = 0x1000,
+       .boot = {0x0000, 0x000000, fw_dir "bcard2.bin",},
+       .load = {0x0120, 0x00f600, fw_dir "ldcard2.bin",},
+       .app = {0x0010, 0x0d0000, fw_dir "cancrd2.bin",},
+       .reset = softingcs_reset,
+       .enable_irq = NULL,
+}, {
+       .name = "EDICcard-NEC",
+       .manf = 0x0168, .prod = 0x102,
+       .generation = 1,
+       .nbus = 2,
+       .freq = 16 * MHZ, .max_brp = 64, .max_sjw = 4,
+       .dpram_size = 0x0800,
+       .boot = {0x0000, 0x000000, fw_dir "bcard.bin",},
+       .load = {0x0120, 0x00f600, fw_dir "ldcard.bin",},
+       .app = {0x0010, 0x0d0000, fw_dir "cancard.bin",},
+       .reset = softingcs_reset,
+       .enable_irq = softingcs_enable_irq,
+}, {
+       .name = "EDICcard-2",
+       .manf = 0x0168, .prod = 0x105,
+       .generation = 2,
+       .nbus = 2,
+       .freq = 24 * MHZ, .max_brp = 64, .max_sjw = 4,
+       .dpram_size = 0x1000,
+       .boot = {0x0000, 0x000000, fw_dir "bcard2.bin",},
+       .load = {0x0120, 0x00f600, fw_dir "ldcard2.bin",},
+       .app = {0x0010, 0x0d0000, fw_dir "cancrd2.bin",},
+       .reset = softingcs_reset,
+       .enable_irq = NULL,
+}, {
+       0, 0,
+},
+};
+
+MODULE_FIRMWARE(fw_dir "bcard.bin");
+MODULE_FIRMWARE(fw_dir "ldcard.bin");
+MODULE_FIRMWARE(fw_dir "cancard.bin");
+MODULE_FIRMWARE(fw_dir "cansja.bin");
+
+MODULE_FIRMWARE(fw_dir "bcard2.bin");
+MODULE_FIRMWARE(fw_dir "ldcard2.bin");
+MODULE_FIRMWARE(fw_dir "cancrd2.bin");
+
+static __devinit const struct softing_platform_data
+*softingcs_find_platform_data(unsigned int manf, unsigned int prod)
+{
+       const struct softing_platform_data *lp;
+
+       for (lp = softingcs_platform_data; lp->manf; ++lp) {
+               if ((lp->manf == manf) && (lp->prod == prod))
+                       return lp;
+       }
+       return NULL;
+}
+
+/*
+ * platformdata callbacks
+ */
+static int softingcs_reset(struct platform_device *pdev, int v)
+{
+       struct pcmcia_device *pcmcia = to_pcmcia_dev(pdev->dev.parent);
+
+       dev_dbg(&pdev->dev, "pcmcia config [2] %02x\n", v ? 0 : 0x20);
+       return pcmcia_write_config_byte(pcmcia, 2, v ? 0 : 0x20);
+}
+
+static int softingcs_enable_irq(struct platform_device *pdev, int v)
+{
+       struct pcmcia_device *pcmcia = to_pcmcia_dev(pdev->dev.parent);
+
+       dev_dbg(&pdev->dev, "pcmcia config [0] %02x\n", v ? 0x60 : 0);
+       return pcmcia_write_config_byte(pcmcia, 0, v ? 0x60 : 0);
+}
+
+/*
+ * pcmcia check
+ */
+static __devinit int softingcs_probe_config(struct pcmcia_device *pcmcia,
+               void *priv_data)
+{
+       struct softing_platform_data *pdat = priv_data;
+       struct resource *pres;
+       int memspeed = 0;
+
+       WARN_ON(!pdat);
+       pres = pcmcia->resource[PCMCIA_IOMEM_0];
+       if (resource_size(pres) < 0x1000)
+               return -ERANGE;
+
+       pres->flags |= WIN_MEMORY_TYPE_CM | WIN_ENABLE;
+       if (pdat->generation < 2) {
+               pres->flags |= WIN_USE_WAIT | WIN_DATA_WIDTH_8;
+               memspeed = 3;
+       } else {
+               pres->flags |= WIN_DATA_WIDTH_16;
+       }
+       return pcmcia_request_window(pcmcia, pres, memspeed);
+}
+
+static __devexit void softingcs_remove(struct pcmcia_device *pcmcia)
+{
+       struct platform_device *pdev = pcmcia->priv;
+
+       /* free bits */
+       platform_device_unregister(pdev);
+       /* release pcmcia stuff */
+       pcmcia_disable_device(pcmcia);
+}
+
+/*
+ * platform_device wrapper
+ * pdev->resource has 2 entries: io & irq
+ */
+static void softingcs_pdev_release(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       kfree(pdev);
+}
+
+static __devinit int softingcs_probe(struct pcmcia_device *pcmcia)
+{
+       int ret;
+       struct platform_device *pdev;
+       const struct softing_platform_data *pdat;
+       struct resource *pres;
+       struct dev {
+               struct platform_device pdev;
+               struct resource res[2];
+       } *dev;
+
+       /* find matching platform_data */
+       pdat = softingcs_find_platform_data(pcmcia->manf_id, pcmcia->card_id);
+       if (!pdat)
+               return -ENOTTY;
+
+       /* setup pcmcia device */
+       pcmcia->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IOMEM |
+               CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC;
+       ret = pcmcia_loop_config(pcmcia, softingcs_probe_config, (void *)pdat);
+       if (ret)
+               goto pcmcia_failed;
+
+       ret = pcmcia_enable_device(pcmcia);
+       if (ret < 0)
+               goto pcmcia_failed;
+
+       pres = pcmcia->resource[PCMCIA_IOMEM_0];
+       if (!pres) {
+               ret = -EBADF;
+               goto pcmcia_bad;
+       }
+
+       /* create softing platform device */
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               ret = -ENOMEM;
+               goto mem_failed;
+       }
+       dev->pdev.resource = dev->res;
+       dev->pdev.num_resources = ARRAY_SIZE(dev->res);
+       dev->pdev.dev.release = softingcs_pdev_release;
+
+       pdev = &dev->pdev;
+       pdev->dev.platform_data = (void *)pdat;
+       pdev->dev.parent = &pcmcia->dev;
+       pcmcia->priv = pdev;
+
+       /* platform device resources */
+       pdev->resource[0].flags = IORESOURCE_MEM;
+       pdev->resource[0].start = pres->start;
+       pdev->resource[0].end = pres->end;
+
+       pdev->resource[1].flags = IORESOURCE_IRQ;
+       pdev->resource[1].start = pcmcia->irq;
+       pdev->resource[1].end = pdev->resource[1].start;
+
+       /* platform device setup */
+       spin_lock(&softingcs_index_lock);
+       pdev->id = softingcs_index++;
+       spin_unlock(&softingcs_index_lock);
+       pdev->name = "softing";
+       dev_set_name(&pdev->dev, "softingcs.%i", pdev->id);
+       ret = platform_device_register(pdev);
+       if (ret < 0)
+               goto platform_failed;
+
+       dev_info(&pcmcia->dev, "created %s\n", dev_name(&pdev->dev));
+       return 0;
+
+platform_failed:
+       kfree(dev);
+mem_failed:
+pcmcia_bad:
+pcmcia_failed:
+       pcmcia_disable_device(pcmcia);
+       pcmcia->priv = NULL;
+       return ret ?: -ENODEV;
+}
+
+static /*const*/ struct pcmcia_device_id softingcs_ids[] = {
+       /* softing */
+       PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0001),
+       PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0002),
+       PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0004),
+       PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0005),
+       /* vector, manufacturer? */
+       PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0081),
+       PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0084),
+       PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0085),
+       /* EDIC */
+       PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0102),
+       PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0105),
+       PCMCIA_DEVICE_NULL,
+};
+
+MODULE_DEVICE_TABLE(pcmcia, softingcs_ids);
+
+static struct pcmcia_driver softingcs_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "softingcs",
+       .id_table       = softingcs_ids,
+       .probe          = softingcs_probe,
+       .remove         = __devexit_p(softingcs_remove),
+};
+
+static int __init softingcs_start(void)
+{
+       spin_lock_init(&softingcs_index_lock);
+       return pcmcia_register_driver(&softingcs_driver);
+}
+
+static void __exit softingcs_stop(void)
+{
+       pcmcia_unregister_driver(&softingcs_driver);
+}
+
+module_init(softingcs_start);
+module_exit(softingcs_stop);
+
+MODULE_DESCRIPTION("softing CANcard driver"
+               ", links PCMCIA card to softing driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/can/softing/softing_fw.c b/drivers/net/can/softing/softing_fw.c
new file mode 100644 (file)
index 0000000..b520784
--- /dev/null
@@ -0,0 +1,691 @@
+/*
+ * Copyright (C) 2008-2010
+ *
+ * - Kurt Van Dijck, EIA Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/firmware.h>
+#include <linux/sched.h>
+#include <asm/div64.h>
+
+#include "softing.h"
+
+/*
+ * low level DPRAM command.
+ * Make sure that card->dpram[DPRAM_FCT_HOST] is preset
+ */
+static int _softing_fct_cmd(struct softing *card, int16_t cmd, uint16_t vector,
+               const char *msg)
+{
+       int ret;
+       unsigned long stamp;
+
+       iowrite16(cmd, &card->dpram[DPRAM_FCT_PARAM]);
+       iowrite8(vector >> 8, &card->dpram[DPRAM_FCT_HOST + 1]);
+       iowrite8(vector, &card->dpram[DPRAM_FCT_HOST]);
+       /* be sure to flush this to the card */
+       wmb();
+       stamp = jiffies + 1 * HZ;
+       /* wait for card */
+       do {
+               /* DPRAM_FCT_HOST is _not_ aligned */
+               ret = ioread8(&card->dpram[DPRAM_FCT_HOST]) +
+                       (ioread8(&card->dpram[DPRAM_FCT_HOST + 1]) << 8);
+               /* don't have any cached variables */
+               rmb();
+               if (ret == RES_OK)
+                       /* read return-value now */
+                       return ioread16(&card->dpram[DPRAM_FCT_RESULT]);
+
+               if ((ret != vector) || time_after(jiffies, stamp))
+                       break;
+               /* process context => relax */
+               usleep_range(500, 10000);
+       } while (1);
+
+       ret = (ret == RES_NONE) ? -ETIMEDOUT : -ECANCELED;
+       dev_alert(&card->pdev->dev, "firmware %s failed (%i)\n", msg, ret);
+       return ret;
+}
+
+static int softing_fct_cmd(struct softing *card, int16_t cmd, const char *msg)
+{
+       int ret;
+
+       ret = _softing_fct_cmd(card, cmd, 0, msg);
+       if (ret > 0) {
+               dev_alert(&card->pdev->dev, "%s returned %u\n", msg, ret);
+               ret = -EIO;
+       }
+       return ret;
+}
+
+int softing_bootloader_command(struct softing *card, int16_t cmd,
+               const char *msg)
+{
+       int ret;
+       unsigned long stamp;
+
+       iowrite16(RES_NONE, &card->dpram[DPRAM_RECEIPT]);
+       iowrite16(cmd, &card->dpram[DPRAM_COMMAND]);
+       /* be sure to flush this to the card */
+       wmb();
+       stamp = jiffies + 3 * HZ;
+       /* wait for card */
+       do {
+               ret = ioread16(&card->dpram[DPRAM_RECEIPT]);
+               /* don't have any cached variables */
+               rmb();
+               if (ret == RES_OK)
+                       return 0;
+               if (time_after(jiffies, stamp))
+                       break;
+               /* process context => relax */
+               usleep_range(500, 10000);
+       } while (!signal_pending(current));
+
+       ret = (ret == RES_NONE) ? -ETIMEDOUT : -ECANCELED;
+       dev_alert(&card->pdev->dev, "bootloader %s failed (%i)\n", msg, ret);
+       return ret;
+}
+
+static int fw_parse(const uint8_t **pmem, uint16_t *ptype, uint32_t *paddr,
+               uint16_t *plen, const uint8_t **pdat)
+{
+       uint16_t checksum[2];
+       const uint8_t *mem;
+       const uint8_t *end;
+
+       /*
+        * firmware records are a binary, unaligned stream composed of:
+        * uint16_t type;
+        * uint32_t addr;
+        * uint16_t len;
+        * uint8_t dat[len];
+        * uint16_t checksum;
+        * all values in little endian.
+        * We could define a struct for this, with __attribute__((packed)),
+        * but would that solve the alignment in _all_ cases (cfr. the
+        * struct itself may be an odd address)?
+        *
+        * I chose to use leXX_to_cpup() since this solves both
+        * endianness & alignment.
+        */
+       mem = *pmem;
+       *ptype = le16_to_cpup((void *)&mem[0]);
+       *paddr = le32_to_cpup((void *)&mem[2]);
+       *plen = le16_to_cpup((void *)&mem[6]);
+       *pdat = &mem[8];
+       /* verify checksum */
+       end = &mem[8 + *plen];
+       checksum[0] = le16_to_cpup((void *)end);
+       for (checksum[1] = 0; mem < end; ++mem)
+               checksum[1] += *mem;
+       if (checksum[0] != checksum[1])
+               return -EINVAL;
+       /* increment */
+       *pmem += 10 + *plen;
+       return 0;
+}
+
+int softing_load_fw(const char *file, struct softing *card,
+               __iomem uint8_t *dpram, unsigned int size, int offset)
+{
+       const struct firmware *fw;
+       int ret;
+       const uint8_t *mem, *end, *dat;
+       uint16_t type, len;
+       uint32_t addr;
+       uint8_t *buf = NULL;
+       int buflen = 0;
+       int8_t type_end = 0;
+
+       ret = request_firmware(&fw, file, &card->pdev->dev);
+       if (ret < 0)
+               return ret;
+       dev_dbg(&card->pdev->dev, "%s, firmware(%s) got %u bytes"
+               ", offset %c0x%04x\n",
+               card->pdat->name, file, (unsigned int)fw->size,
+               (offset >= 0) ? '+' : '-', (unsigned int)abs(offset));
+       /* parse the firmware */
+       mem = fw->data;
+       end = &mem[fw->size];
+       /* look for header record */
+       ret = fw_parse(&mem, &type, &addr, &len, &dat);
+       if (ret < 0)
+               goto failed;
+       if (type != 0xffff)
+               goto failed;
+       if (strncmp("Structured Binary Format, Softing GmbH" , dat, len)) {
+               ret = -EINVAL;
+               goto failed;
+       }
+       /* ok, we had a header */
+       while (mem < end) {
+               ret = fw_parse(&mem, &type, &addr, &len, &dat);
+               if (ret < 0)
+                       goto failed;
+               if (type == 3) {
+                       /* start address, not used here */
+                       continue;
+               } else if (type == 1) {
+                       /* eof */
+                       type_end = 1;
+                       break;
+               } else if (type != 0) {
+                       ret = -EINVAL;
+                       goto failed;
+               }
+
+               if ((addr + len + offset) > size)
+                       goto failed;
+               memcpy_toio(&dpram[addr + offset], dat, len);
+               /* be sure to flush caches from IO space */
+               mb();
+               if (len > buflen) {
+                       /* align buflen */
+                       buflen = (len + (1024-1)) & ~(1024-1);
+                       buf = krealloc(buf, buflen, GFP_KERNEL);
+                       if (!buf) {
+                               ret = -ENOMEM;
+                               goto failed;
+                       }
+               }
+               /* verify record data */
+               memcpy_fromio(buf, &dpram[addr + offset], len);
+               if (memcmp(buf, dat, len)) {
+                       /* is not ok */
+                       dev_alert(&card->pdev->dev, "DPRAM readback failed\n");
+                       ret = -EIO;
+                       goto failed;
+               }
+       }
+       if (!type_end)
+               /* no end record seen */
+               goto failed;
+       ret = 0;
+failed:
+       kfree(buf);
+       release_firmware(fw);
+       if (ret < 0)
+               dev_info(&card->pdev->dev, "firmware %s failed\n", file);
+       return ret;
+}
+
+int softing_load_app_fw(const char *file, struct softing *card)
+{
+       const struct firmware *fw;
+       const uint8_t *mem, *end, *dat;
+       int ret, j;
+       uint16_t type, len;
+       uint32_t addr, start_addr = 0;
+       unsigned int sum, rx_sum;
+       int8_t type_end = 0, type_entrypoint = 0;
+
+       ret = request_firmware(&fw, file, &card->pdev->dev);
+       if (ret) {
+               dev_alert(&card->pdev->dev, "request_firmware(%s) got %i\n",
+                       file, ret);
+               return ret;
+       }
+       dev_dbg(&card->pdev->dev, "firmware(%s) got %lu bytes\n",
+               file, (unsigned long)fw->size);
+       /* parse the firmware */
+       mem = fw->data;
+       end = &mem[fw->size];
+       /* look for header record */
+       ret = fw_parse(&mem, &type, &addr, &len, &dat);
+       if (ret)
+               goto failed;
+       ret = -EINVAL;
+       if (type != 0xffff) {
+               dev_alert(&card->pdev->dev, "firmware starts with type 0x%x\n",
+                       type);
+               goto failed;
+       }
+       if (strncmp("Structured Binary Format, Softing GmbH", dat, len)) {
+               dev_alert(&card->pdev->dev, "firmware string '%.*s' fault\n",
+                               len, dat);
+               goto failed;
+       }
+       /* ok, we had a header */
+       while (mem < end) {
+               ret = fw_parse(&mem, &type, &addr, &len, &dat);
+               if (ret)
+                       goto failed;
+
+               if (type == 3) {
+                       /* start address */
+                       start_addr = addr;
+                       type_entrypoint = 1;
+                       continue;
+               } else if (type == 1) {
+                       /* eof */
+                       type_end = 1;
+                       break;
+               } else if (type != 0) {
+                       dev_alert(&card->pdev->dev,
+                                       "unknown record type 0x%04x\n", type);
+                       ret = -EINVAL;
+                       goto failed;
+               }
+
+               /* regualar data */
+               for (sum = 0, j = 0; j < len; ++j)
+                       sum += dat[j];
+               /* work in 16bit (target) */
+               sum &= 0xffff;
+
+               memcpy_toio(&card->dpram[card->pdat->app.offs], dat, len);
+               iowrite32(card->pdat->app.offs + card->pdat->app.addr,
+                               &card->dpram[DPRAM_COMMAND + 2]);
+               iowrite32(addr, &card->dpram[DPRAM_COMMAND + 6]);
+               iowrite16(len, &card->dpram[DPRAM_COMMAND + 10]);
+               iowrite8(1, &card->dpram[DPRAM_COMMAND + 12]);
+               ret = softing_bootloader_command(card, 1, "loading app.");
+               if (ret < 0)
+                       goto failed;
+               /* verify checksum */
+               rx_sum = ioread16(&card->dpram[DPRAM_RECEIPT + 2]);
+               if (rx_sum != sum) {
+                       dev_alert(&card->pdev->dev, "SRAM seems to be damaged"
+                               ", wanted 0x%04x, got 0x%04x\n", sum, rx_sum);
+                       ret = -EIO;
+                       goto failed;
+               }
+       }
+       if (!type_end || !type_entrypoint)
+               goto failed;
+       /* start application in card */
+       iowrite32(start_addr, &card->dpram[DPRAM_COMMAND + 2]);
+       iowrite8(1, &card->dpram[DPRAM_COMMAND + 6]);
+       ret = softing_bootloader_command(card, 3, "start app.");
+       if (ret < 0)
+               goto failed;
+       ret = 0;
+failed:
+       release_firmware(fw);
+       if (ret < 0)
+               dev_info(&card->pdev->dev, "firmware %s failed\n", file);
+       return ret;
+}
+
+static int softing_reset_chip(struct softing *card)
+{
+       int ret;
+
+       do {
+               /* reset chip */
+               iowrite8(0, &card->dpram[DPRAM_RESET_RX_FIFO]);
+               iowrite8(0, &card->dpram[DPRAM_RESET_RX_FIFO+1]);
+               iowrite8(1, &card->dpram[DPRAM_RESET]);
+               iowrite8(0, &card->dpram[DPRAM_RESET+1]);
+
+               ret = softing_fct_cmd(card, 0, "reset_can");
+               if (!ret)
+                       break;
+               if (signal_pending(current))
+                       /* don't wait any longer */
+                       break;
+       } while (1);
+       card->tx.pending = 0;
+       return ret;
+}
+
+int softing_chip_poweron(struct softing *card)
+{
+       int ret;
+       /* sync */
+       ret = _softing_fct_cmd(card, 99, 0x55, "sync-a");
+       if (ret < 0)
+               goto failed;
+
+       ret = _softing_fct_cmd(card, 99, 0xaa, "sync-b");
+       if (ret < 0)
+               goto failed;
+
+       ret = softing_reset_chip(card);
+       if (ret < 0)
+               goto failed;
+       /* get_serial */
+       ret = softing_fct_cmd(card, 43, "get_serial_number");
+       if (ret < 0)
+               goto failed;
+       card->id.serial = ioread32(&card->dpram[DPRAM_FCT_PARAM]);
+       /* get_version */
+       ret = softing_fct_cmd(card, 12, "get_version");
+       if (ret < 0)
+               goto failed;
+       card->id.fw_version = ioread16(&card->dpram[DPRAM_FCT_PARAM + 2]);
+       card->id.hw_version = ioread16(&card->dpram[DPRAM_FCT_PARAM + 4]);
+       card->id.license = ioread16(&card->dpram[DPRAM_FCT_PARAM + 6]);
+       card->id.chip[0] = ioread16(&card->dpram[DPRAM_FCT_PARAM + 8]);
+       card->id.chip[1] = ioread16(&card->dpram[DPRAM_FCT_PARAM + 10]);
+       return 0;
+failed:
+       return ret;
+}
+
+static void softing_initialize_timestamp(struct softing *card)
+{
+       uint64_t ovf;
+
+       card->ts_ref = ktime_get();
+
+       /* 16MHz is the reference */
+       ovf = 0x100000000ULL * 16;
+       do_div(ovf, card->pdat->freq ?: 16);
+
+       card->ts_overflow = ktime_add_us(ktime_set(0, 0), ovf);
+}
+
+ktime_t softing_raw2ktime(struct softing *card, u32 raw)
+{
+       uint64_t rawl;
+       ktime_t now, real_offset;
+       ktime_t target;
+       ktime_t tmp;
+
+       now = ktime_get();
+       real_offset = ktime_sub(ktime_get_real(), now);
+
+       /* find nsec from card */
+       rawl = raw * 16;
+       do_div(rawl, card->pdat->freq ?: 16);
+       target = ktime_add_us(card->ts_ref, rawl);
+       /* test for overflows */
+       tmp = ktime_add(target, card->ts_overflow);
+       while (unlikely(ktime_to_ns(tmp) > ktime_to_ns(now))) {
+               card->ts_ref = ktime_add(card->ts_ref, card->ts_overflow);
+               target = tmp;
+               tmp = ktime_add(target, card->ts_overflow);
+       }
+       return ktime_add(target, real_offset);
+}
+
+static inline int softing_error_reporting(struct net_device *netdev)
+{
+       struct softing_priv *priv = netdev_priv(netdev);
+
+       return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
+               ? 1 : 0;
+}
+
+int softing_startstop(struct net_device *dev, int up)
+{
+       int ret;
+       struct softing *card;
+       struct softing_priv *priv;
+       struct net_device *netdev;
+       int bus_bitmask_start;
+       int j, error_reporting;
+       struct can_frame msg;
+       const struct can_bittiming *bt;
+
+       priv = netdev_priv(dev);
+       card = priv->card;
+
+       if (!card->fw.up)
+               return -EIO;
+
+       ret = mutex_lock_interruptible(&card->fw.lock);
+       if (ret)
+               return ret;
+
+       bus_bitmask_start = 0;
+       if (dev && up)
+               /* prepare to start this bus as well */
+               bus_bitmask_start |= (1 << priv->index);
+       /* bring netdevs down */
+       for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
+               netdev = card->net[j];
+               if (!netdev)
+                       continue;
+               priv = netdev_priv(netdev);
+
+               if (dev != netdev)
+                       netif_stop_queue(netdev);
+
+               if (netif_running(netdev)) {
+                       if (dev != netdev)
+                               bus_bitmask_start |= (1 << j);
+                       priv->tx.pending = 0;
+                       priv->tx.echo_put = 0;
+                       priv->tx.echo_get = 0;
+                       /*
+                        * this bus' may just have called open_candev()
+                        * which is rather stupid to call close_candev()
+                        * already
+                        * but we may come here from busoff recovery too
+                        * in which case the echo_skb _needs_ flushing too.
+                        * just be sure to call open_candev() again
+                        */
+                       close_candev(netdev);
+               }
+               priv->can.state = CAN_STATE_STOPPED;
+       }
+       card->tx.pending = 0;
+
+       softing_enable_irq(card, 0);
+       ret = softing_reset_chip(card);
+       if (ret)
+               goto failed;
+       if (!bus_bitmask_start)
+               /* no busses to be brought up */
+               goto card_done;
+
+       if ((bus_bitmask_start & 1) && (bus_bitmask_start & 2)
+                       && (softing_error_reporting(card->net[0])
+                               != softing_error_reporting(card->net[1]))) {
+               dev_alert(&card->pdev->dev,
+                               "err_reporting flag differs for busses\n");
+               goto invalid;
+       }
+       error_reporting = 0;
+       if (bus_bitmask_start & 1) {
+               netdev = card->net[0];
+               priv = netdev_priv(netdev);
+               error_reporting += softing_error_reporting(netdev);
+               /* init chip 1 */
+               bt = &priv->can.bittiming;
+               iowrite16(bt->brp, &card->dpram[DPRAM_FCT_PARAM + 2]);
+               iowrite16(bt->sjw, &card->dpram[DPRAM_FCT_PARAM + 4]);
+               iowrite16(bt->phase_seg1 + bt->prop_seg,
+                               &card->dpram[DPRAM_FCT_PARAM + 6]);
+               iowrite16(bt->phase_seg2, &card->dpram[DPRAM_FCT_PARAM + 8]);
+               iowrite16((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) ? 1 : 0,
+                               &card->dpram[DPRAM_FCT_PARAM + 10]);
+               ret = softing_fct_cmd(card, 1, "initialize_chip[0]");
+               if (ret < 0)
+                       goto failed;
+               /* set mode */
+               iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 2]);
+               iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 4]);
+               ret = softing_fct_cmd(card, 3, "set_mode[0]");
+               if (ret < 0)
+                       goto failed;
+               /* set filter */
+               /* 11bit id & mask */
+               iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 2]);
+               iowrite16(0x07ff, &card->dpram[DPRAM_FCT_PARAM + 4]);
+               /* 29bit id.lo & mask.lo & id.hi & mask.hi */
+               iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 6]);
+               iowrite16(0xffff, &card->dpram[DPRAM_FCT_PARAM + 8]);
+               iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 10]);
+               iowrite16(0x1fff, &card->dpram[DPRAM_FCT_PARAM + 12]);
+               ret = softing_fct_cmd(card, 7, "set_filter[0]");
+               if (ret < 0)
+                       goto failed;
+               /* set output control */
+               iowrite16(priv->output, &card->dpram[DPRAM_FCT_PARAM + 2]);
+               ret = softing_fct_cmd(card, 5, "set_output[0]");
+               if (ret < 0)
+                       goto failed;
+       }
+       if (bus_bitmask_start & 2) {
+               netdev = card->net[1];
+               priv = netdev_priv(netdev);
+               error_reporting += softing_error_reporting(netdev);
+               /* init chip2 */
+               bt = &priv->can.bittiming;
+               iowrite16(bt->brp, &card->dpram[DPRAM_FCT_PARAM + 2]);
+               iowrite16(bt->sjw, &card->dpram[DPRAM_FCT_PARAM + 4]);
+               iowrite16(bt->phase_seg1 + bt->prop_seg,
+                               &card->dpram[DPRAM_FCT_PARAM + 6]);
+               iowrite16(bt->phase_seg2, &card->dpram[DPRAM_FCT_PARAM + 8]);
+               iowrite16((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) ? 1 : 0,
+                               &card->dpram[DPRAM_FCT_PARAM + 10]);
+               ret = softing_fct_cmd(card, 2, "initialize_chip[1]");
+               if (ret < 0)
+                       goto failed;
+               /* set mode2 */
+               iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 2]);
+               iowrite16(0, &card->dpram[DPRAM_FCT_PARAM + 4]);
+               ret = softing_fct_cmd(card, 4, "set_mode[1]");
+               if (ret < 0)
+                       goto failed;
+               /* set filter2 */
+               /* 11bit id & mask */
+               iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 2]);
+               iowrite16(0x07ff, &card->dpram[DPRAM_FCT_PARAM + 4]);
+               /* 29bit id.lo & mask.lo & id.hi & mask.hi */
+               iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 6]);
+               iowrite16(0xffff, &card->dpram[DPRAM_FCT_PARAM + 8]);
+               iowrite16(0x0000, &card->dpram[DPRAM_FCT_PARAM + 10]);
+               iowrite16(0x1fff, &card->dpram[DPRAM_FCT_PARAM + 12]);
+               ret = softing_fct_cmd(card, 8, "set_filter[1]");
+               if (ret < 0)
+                       goto failed;
+               /* set output control2 */
+               iowrite16(priv->output, &card->dpram[DPRAM_FCT_PARAM + 2]);
+               ret = softing_fct_cmd(card, 6, "set_output[1]");
+               if (ret < 0)
+                       goto failed;
+       }
+       /* enable_error_frame */
+       /*
+        * Error reporting is switched off at the moment since
+        * the receiving of them is not yet 100% verified
+        * This should be enabled sooner or later
+        *
+       if (error_reporting) {
+               ret = softing_fct_cmd(card, 51, "enable_error_frame");
+               if (ret < 0)
+                       goto failed;
+       }
+       */
+       /* initialize interface */
+       iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 2]);
+       iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 4]);
+       iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 6]);
+       iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 8]);
+       iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 10]);
+       iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 12]);
+       iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 14]);
+       iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 16]);
+       iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 18]);
+       iowrite16(1, &card->dpram[DPRAM_FCT_PARAM + 20]);
+       ret = softing_fct_cmd(card, 17, "initialize_interface");
+       if (ret < 0)
+               goto failed;
+       /* enable_fifo */
+       ret = softing_fct_cmd(card, 36, "enable_fifo");
+       if (ret < 0)
+               goto failed;
+       /* enable fifo tx ack */
+       ret = softing_fct_cmd(card, 13, "fifo_tx_ack[0]");
+       if (ret < 0)
+               goto failed;
+       /* enable fifo tx ack2 */
+       ret = softing_fct_cmd(card, 14, "fifo_tx_ack[1]");
+       if (ret < 0)
+               goto failed;
+       /* start_chip */
+       ret = softing_fct_cmd(card, 11, "start_chip");
+       if (ret < 0)
+               goto failed;
+       iowrite8(0, &card->dpram[DPRAM_INFO_BUSSTATE]);
+       iowrite8(0, &card->dpram[DPRAM_INFO_BUSSTATE2]);
+       if (card->pdat->generation < 2) {
+               iowrite8(0, &card->dpram[DPRAM_V2_IRQ_TOHOST]);
+               /* flush the DPRAM caches */
+               wmb();
+       }
+
+       softing_initialize_timestamp(card);
+
+       /*
+        * do socketcan notifications/status changes
+        * from here, no errors should occur, or the failed: part
+        * must be reviewed
+        */
+       memset(&msg, 0, sizeof(msg));
+       msg.can_id = CAN_ERR_FLAG | CAN_ERR_RESTARTED;
+       msg.can_dlc = CAN_ERR_DLC;
+       for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
+               if (!(bus_bitmask_start & (1 << j)))
+                       continue;
+               netdev = card->net[j];
+               if (!netdev)
+                       continue;
+               priv = netdev_priv(netdev);
+               priv->can.state = CAN_STATE_ERROR_ACTIVE;
+               open_candev(netdev);
+               if (dev != netdev) {
+                       /* notify other busses on the restart */
+                       softing_netdev_rx(netdev, &msg, ktime_set(0, 0));
+                       ++priv->can.can_stats.restarts;
+               }
+               netif_wake_queue(netdev);
+       }
+
+       /* enable interrupts */
+       ret = softing_enable_irq(card, 1);
+       if (ret)
+               goto failed;
+card_done:
+       mutex_unlock(&card->fw.lock);
+       return 0;
+invalid:
+       ret = -EINVAL;
+failed:
+       softing_enable_irq(card, 0);
+       softing_reset_chip(card);
+       mutex_unlock(&card->fw.lock);
+       /* bring all other interfaces down */
+       for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
+               netdev = card->net[j];
+               if (!netdev)
+                       continue;
+               dev_close(netdev);
+       }
+       return ret;
+}
+
+int softing_default_output(struct net_device *netdev)
+{
+       struct softing_priv *priv = netdev_priv(netdev);
+       struct softing *card = priv->card;
+
+       switch (priv->chip) {
+       case 1000:
+               return (card->pdat->generation < 2) ? 0xfb : 0xfa;
+       case 5:
+               return 0x60;
+       default:
+               return 0x40;
+       }
+}
diff --git a/drivers/net/can/softing/softing_main.c b/drivers/net/can/softing/softing_main.c
new file mode 100644 (file)
index 0000000..aeea9f9
--- /dev/null
@@ -0,0 +1,894 @@
+/*
+ * Copyright (C) 2008-2010
+ *
+ * - Kurt Van Dijck, EIA Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include "softing.h"
+
+#define TX_ECHO_SKB_MAX (((TXMAX+1)/2)-1)
+
+/*
+ * test is a specific CAN netdev
+ * is online (ie. up 'n running, not sleeping, not busoff
+ */
+static inline int canif_is_active(struct net_device *netdev)
+{
+       struct can_priv *can = netdev_priv(netdev);
+
+       if (!netif_running(netdev))
+               return 0;
+       return (can->state <= CAN_STATE_ERROR_PASSIVE);
+}
+
+/* reset DPRAM */
+static inline void softing_set_reset_dpram(struct softing *card)
+{
+       if (card->pdat->generation >= 2) {
+               spin_lock_bh(&card->spin);
+               iowrite8(ioread8(&card->dpram[DPRAM_V2_RESET]) & ~1,
+                               &card->dpram[DPRAM_V2_RESET]);
+               spin_unlock_bh(&card->spin);
+       }
+}
+
+static inline void softing_clr_reset_dpram(struct softing *card)
+{
+       if (card->pdat->generation >= 2) {
+               spin_lock_bh(&card->spin);
+               iowrite8(ioread8(&card->dpram[DPRAM_V2_RESET]) | 1,
+                               &card->dpram[DPRAM_V2_RESET]);
+               spin_unlock_bh(&card->spin);
+       }
+}
+
+/* trigger the tx queue-ing */
+static netdev_tx_t softing_netdev_start_xmit(struct sk_buff *skb,
+               struct net_device *dev)
+{
+       struct softing_priv *priv = netdev_priv(dev);
+       struct softing *card = priv->card;
+       int ret;
+       uint8_t *ptr;
+       uint8_t fifo_wr, fifo_rd;
+       struct can_frame *cf = (struct can_frame *)skb->data;
+       uint8_t buf[DPRAM_TX_SIZE];
+
+       if (can_dropped_invalid_skb(dev, skb))
+               return NETDEV_TX_OK;
+
+       spin_lock(&card->spin);
+
+       ret = NETDEV_TX_BUSY;
+       if (!card->fw.up ||
+                       (card->tx.pending >= TXMAX) ||
+                       (priv->tx.pending >= TX_ECHO_SKB_MAX))
+               goto xmit_done;
+       fifo_wr = ioread8(&card->dpram[DPRAM_TX_WR]);
+       fifo_rd = ioread8(&card->dpram[DPRAM_TX_RD]);
+       if (fifo_wr == fifo_rd)
+               /* fifo full */
+               goto xmit_done;
+       memset(buf, 0, sizeof(buf));
+       ptr = buf;
+       *ptr = CMD_TX;
+       if (cf->can_id & CAN_RTR_FLAG)
+               *ptr |= CMD_RTR;
+       if (cf->can_id & CAN_EFF_FLAG)
+               *ptr |= CMD_XTD;
+       if (priv->index)
+               *ptr |= CMD_BUS2;
+       ++ptr;
+       *ptr++ = cf->can_dlc;
+       *ptr++ = (cf->can_id >> 0);
+       *ptr++ = (cf->can_id >> 8);
+       if (cf->can_id & CAN_EFF_FLAG) {
+               *ptr++ = (cf->can_id >> 16);
+               *ptr++ = (cf->can_id >> 24);
+       } else {
+               /* increment 1, not 2 as you might think */
+               ptr += 1;
+       }
+       if (!(cf->can_id & CAN_RTR_FLAG))
+               memcpy(ptr, &cf->data[0], cf->can_dlc);
+       memcpy_toio(&card->dpram[DPRAM_TX + DPRAM_TX_SIZE * fifo_wr],
+                       buf, DPRAM_TX_SIZE);
+       if (++fifo_wr >= DPRAM_TX_CNT)
+               fifo_wr = 0;
+       iowrite8(fifo_wr, &card->dpram[DPRAM_TX_WR]);
+       card->tx.last_bus = priv->index;
+       ++card->tx.pending;
+       ++priv->tx.pending;
+       can_put_echo_skb(skb, dev, priv->tx.echo_put);
+       ++priv->tx.echo_put;
+       if (priv->tx.echo_put >= TX_ECHO_SKB_MAX)
+               priv->tx.echo_put = 0;
+       /* can_put_echo_skb() saves the skb, safe to return TX_OK */
+       ret = NETDEV_TX_OK;
+xmit_done:
+       spin_unlock(&card->spin);
+       if (card->tx.pending >= TXMAX) {
+               int j;
+               for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
+                       if (card->net[j])
+                               netif_stop_queue(card->net[j]);
+               }
+       }
+       if (ret != NETDEV_TX_OK)
+               netif_stop_queue(dev);
+
+       return ret;
+}
+
+/*
+ * shortcut for skb delivery
+ */
+int softing_netdev_rx(struct net_device *netdev, const struct can_frame *msg,
+               ktime_t ktime)
+{
+       struct sk_buff *skb;
+       struct can_frame *cf;
+
+       skb = alloc_can_skb(netdev, &cf);
+       if (!skb)
+               return -ENOMEM;
+       memcpy(cf, msg, sizeof(*msg));
+       skb->tstamp = ktime;
+       return netif_rx(skb);
+}
+
+/*
+ * softing_handle_1
+ * pop 1 entry from the DPRAM queue, and process
+ */
+static int softing_handle_1(struct softing *card)
+{
+       struct net_device *netdev;
+       struct softing_priv *priv;
+       ktime_t ktime;
+       struct can_frame msg;
+       int cnt = 0, lost_msg;
+       uint8_t fifo_rd, fifo_wr, cmd;
+       uint8_t *ptr;
+       uint32_t tmp_u32;
+       uint8_t buf[DPRAM_RX_SIZE];
+
+       memset(&msg, 0, sizeof(msg));
+       /* test for lost msgs */
+       lost_msg = ioread8(&card->dpram[DPRAM_RX_LOST]);
+       if (lost_msg) {
+               int j;
+               /* reset condition */
+               iowrite8(0, &card->dpram[DPRAM_RX_LOST]);
+               /* prepare msg */
+               msg.can_id = CAN_ERR_FLAG | CAN_ERR_CRTL;
+               msg.can_dlc = CAN_ERR_DLC;
+               msg.data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+               /*
+                * service to all busses, we don't know which it was applicable
+                * but only service busses that are online
+                */
+               for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
+                       netdev = card->net[j];
+                       if (!netdev)
+                               continue;
+                       if (!canif_is_active(netdev))
+                               /* a dead bus has no overflows */
+                               continue;
+                       ++netdev->stats.rx_over_errors;
+                       softing_netdev_rx(netdev, &msg, ktime_set(0, 0));
+               }
+               /* prepare for other use */
+               memset(&msg, 0, sizeof(msg));
+               ++cnt;
+       }
+
+       fifo_rd = ioread8(&card->dpram[DPRAM_RX_RD]);
+       fifo_wr = ioread8(&card->dpram[DPRAM_RX_WR]);
+
+       if (++fifo_rd >= DPRAM_RX_CNT)
+               fifo_rd = 0;
+       if (fifo_wr == fifo_rd)
+               return cnt;
+
+       memcpy_fromio(buf, &card->dpram[DPRAM_RX + DPRAM_RX_SIZE*fifo_rd],
+                       DPRAM_RX_SIZE);
+       mb();
+       /* trigger dual port RAM */
+       iowrite8(fifo_rd, &card->dpram[DPRAM_RX_RD]);
+
+       ptr = buf;
+       cmd = *ptr++;
+       if (cmd == 0xff)
+               /* not quite usefull, probably the card has got out */
+               return 0;
+       netdev = card->net[0];
+       if (cmd & CMD_BUS2)
+               netdev = card->net[1];
+       priv = netdev_priv(netdev);
+
+       if (cmd & CMD_ERR) {
+               uint8_t can_state, state;
+
+               state = *ptr++;
+
+               msg.can_id = CAN_ERR_FLAG;
+               msg.can_dlc = CAN_ERR_DLC;
+
+               if (state & SF_MASK_BUSOFF) {
+                       can_state = CAN_STATE_BUS_OFF;
+                       msg.can_id |= CAN_ERR_BUSOFF;
+                       state = STATE_BUSOFF;
+               } else if (state & SF_MASK_EPASSIVE) {
+                       can_state = CAN_STATE_ERROR_PASSIVE;
+                       msg.can_id |= CAN_ERR_CRTL;
+                       msg.data[1] = CAN_ERR_CRTL_TX_PASSIVE;
+                       state = STATE_EPASSIVE;
+               } else {
+                       can_state = CAN_STATE_ERROR_ACTIVE;
+                       msg.can_id |= CAN_ERR_CRTL;
+                       state = STATE_EACTIVE;
+               }
+               /* update DPRAM */
+               iowrite8(state, &card->dpram[priv->index ?
+                               DPRAM_INFO_BUSSTATE2 : DPRAM_INFO_BUSSTATE]);
+               /* timestamp */
+               tmp_u32 = le32_to_cpup((void *)ptr);
+               ptr += 4;
+               ktime = softing_raw2ktime(card, tmp_u32);
+
+               ++netdev->stats.rx_errors;
+               /* update internal status */
+               if (can_state != priv->can.state) {
+                       priv->can.state = can_state;
+                       if (can_state == CAN_STATE_ERROR_PASSIVE)
+                               ++priv->can.can_stats.error_passive;
+                       else if (can_state == CAN_STATE_BUS_OFF) {
+                               /* this calls can_close_cleanup() */
+                               can_bus_off(netdev);
+                               netif_stop_queue(netdev);
+                       }
+                       /* trigger socketcan */
+                       softing_netdev_rx(netdev, &msg, ktime);
+               }
+
+       } else {
+               if (cmd & CMD_RTR)
+                       msg.can_id |= CAN_RTR_FLAG;
+               msg.can_dlc = get_can_dlc(*ptr++);
+               if (cmd & CMD_XTD) {
+                       msg.can_id |= CAN_EFF_FLAG;
+                       msg.can_id |= le32_to_cpup((void *)ptr);
+                       ptr += 4;
+               } else {
+                       msg.can_id |= le16_to_cpup((void *)ptr);
+                       ptr += 2;
+               }
+               /* timestamp */
+               tmp_u32 = le32_to_cpup((void *)ptr);
+               ptr += 4;
+               ktime = softing_raw2ktime(card, tmp_u32);
+               if (!(msg.can_id & CAN_RTR_FLAG))
+                       memcpy(&msg.data[0], ptr, 8);
+               ptr += 8;
+               /* update socket */
+               if (cmd & CMD_ACK) {
+                       /* acknowledge, was tx msg */
+                       struct sk_buff *skb;
+                       skb = priv->can.echo_skb[priv->tx.echo_get];
+                       if (skb)
+                               skb->tstamp = ktime;
+                       can_get_echo_skb(netdev, priv->tx.echo_get);
+                       ++priv->tx.echo_get;
+                       if (priv->tx.echo_get >= TX_ECHO_SKB_MAX)
+                               priv->tx.echo_get = 0;
+                       if (priv->tx.pending)
+                               --priv->tx.pending;
+                       if (card->tx.pending)
+                               --card->tx.pending;
+                       ++netdev->stats.tx_packets;
+                       if (!(msg.can_id & CAN_RTR_FLAG))
+                               netdev->stats.tx_bytes += msg.can_dlc;
+               } else {
+                       int ret;
+
+                       ret = softing_netdev_rx(netdev, &msg, ktime);
+                       if (ret == NET_RX_SUCCESS) {
+                               ++netdev->stats.rx_packets;
+                               if (!(msg.can_id & CAN_RTR_FLAG))
+                                       netdev->stats.rx_bytes += msg.can_dlc;
+                       } else {
+                               ++netdev->stats.rx_dropped;
+                       }
+               }
+       }
+       ++cnt;
+       return cnt;
+}
+
+/*
+ * real interrupt handler
+ */
+static irqreturn_t softing_irq_thread(int irq, void *dev_id)
+{
+       struct softing *card = (struct softing *)dev_id;
+       struct net_device *netdev;
+       struct softing_priv *priv;
+       int j, offset, work_done;
+
+       work_done = 0;
+       spin_lock_bh(&card->spin);
+       while (softing_handle_1(card) > 0) {
+               ++card->irq.svc_count;
+               ++work_done;
+       }
+       spin_unlock_bh(&card->spin);
+       /* resume tx queue's */
+       offset = card->tx.last_bus;
+       for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
+               if (card->tx.pending >= TXMAX)
+                       break;
+               netdev = card->net[(j + offset + 1) % card->pdat->nbus];
+               if (!netdev)
+                       continue;
+               priv = netdev_priv(netdev);
+               if (!canif_is_active(netdev))
+                       /* it makes no sense to wake dead busses */
+                       continue;
+               if (priv->tx.pending >= TX_ECHO_SKB_MAX)
+                       continue;
+               ++work_done;
+               netif_wake_queue(netdev);
+       }
+       return work_done ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/*
+ * interrupt routines:
+ * schedule the 'real interrupt handler'
+ */
+static irqreturn_t softing_irq_v2(int irq, void *dev_id)
+{
+       struct softing *card = (struct softing *)dev_id;
+       uint8_t ir;
+
+       ir = ioread8(&card->dpram[DPRAM_V2_IRQ_TOHOST]);
+       iowrite8(0, &card->dpram[DPRAM_V2_IRQ_TOHOST]);
+       return (1 == ir) ? IRQ_WAKE_THREAD : IRQ_NONE;
+}
+
+static irqreturn_t softing_irq_v1(int irq, void *dev_id)
+{
+       struct softing *card = (struct softing *)dev_id;
+       uint8_t ir;
+
+       ir = ioread8(&card->dpram[DPRAM_IRQ_TOHOST]);
+       iowrite8(0, &card->dpram[DPRAM_IRQ_TOHOST]);
+       return ir ? IRQ_WAKE_THREAD : IRQ_NONE;
+}
+
+/*
+ * netdev/candev inter-operability
+ */
+static int softing_netdev_open(struct net_device *ndev)
+{
+       int ret;
+
+       /* check or determine and set bittime */
+       ret = open_candev(ndev);
+       if (!ret)
+               ret = softing_startstop(ndev, 1);
+       return ret;
+}
+
+static int softing_netdev_stop(struct net_device *ndev)
+{
+       int ret;
+
+       netif_stop_queue(ndev);
+
+       /* softing cycle does close_candev() */
+       ret = softing_startstop(ndev, 0);
+       return ret;
+}
+
+static int softing_candev_set_mode(struct net_device *ndev, enum can_mode mode)
+{
+       int ret;
+
+       switch (mode) {
+       case CAN_MODE_START:
+               /* softing_startstop does close_candev() */
+               ret = softing_startstop(ndev, 1);
+               return ret;
+       case CAN_MODE_STOP:
+       case CAN_MODE_SLEEP:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+/*
+ * Softing device management helpers
+ */
+int softing_enable_irq(struct softing *card, int enable)
+{
+       int ret;
+
+       if (!card->irq.nr) {
+               return 0;
+       } else if (card->irq.requested && !enable) {
+               free_irq(card->irq.nr, card);
+               card->irq.requested = 0;
+       } else if (!card->irq.requested && enable) {
+               ret = request_threaded_irq(card->irq.nr,
+                               (card->pdat->generation >= 2) ?
+                                       softing_irq_v2 : softing_irq_v1,
+                               softing_irq_thread, IRQF_SHARED,
+                               dev_name(&card->pdev->dev), card);
+               if (ret) {
+                       dev_alert(&card->pdev->dev,
+                                       "request_threaded_irq(%u) failed\n",
+                                       card->irq.nr);
+                       return ret;
+               }
+               card->irq.requested = 1;
+       }
+       return 0;
+}
+
+static void softing_card_shutdown(struct softing *card)
+{
+       int fw_up = 0;
+
+       if (mutex_lock_interruptible(&card->fw.lock))
+               /* return -ERESTARTSYS */;
+       fw_up = card->fw.up;
+       card->fw.up = 0;
+
+       if (card->irq.requested && card->irq.nr) {
+               free_irq(card->irq.nr, card);
+               card->irq.requested = 0;
+       }
+       if (fw_up) {
+               if (card->pdat->enable_irq)
+                       card->pdat->enable_irq(card->pdev, 0);
+               softing_set_reset_dpram(card);
+               if (card->pdat->reset)
+                       card->pdat->reset(card->pdev, 1);
+       }
+       mutex_unlock(&card->fw.lock);
+}
+
+static __devinit int softing_card_boot(struct softing *card)
+{
+       int ret, j;
+       static const uint8_t stream[] = {
+               0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, };
+       unsigned char back[sizeof(stream)];
+
+       if (mutex_lock_interruptible(&card->fw.lock))
+               return -ERESTARTSYS;
+       if (card->fw.up) {
+               mutex_unlock(&card->fw.lock);
+               return 0;
+       }
+       /* reset board */
+       if (card->pdat->enable_irq)
+               card->pdat->enable_irq(card->pdev, 1);
+       /* boot card */
+       softing_set_reset_dpram(card);
+       if (card->pdat->reset)
+               card->pdat->reset(card->pdev, 1);
+       for (j = 0; (j + sizeof(stream)) < card->dpram_size;
+                       j += sizeof(stream)) {
+
+               memcpy_toio(&card->dpram[j], stream, sizeof(stream));
+               /* flush IO cache */
+               mb();
+               memcpy_fromio(back, &card->dpram[j], sizeof(stream));
+
+               if (!memcmp(back, stream, sizeof(stream)))
+                       continue;
+               /* memory is not equal */
+               dev_alert(&card->pdev->dev, "dpram failed at 0x%04x\n", j);
+               ret = -EIO;
+               goto failed;
+       }
+       wmb();
+       /* load boot firmware */
+       ret = softing_load_fw(card->pdat->boot.fw, card, card->dpram,
+                               card->dpram_size,
+                               card->pdat->boot.offs - card->pdat->boot.addr);
+       if (ret < 0)
+               goto failed;
+       /* load loader firmware */
+       ret = softing_load_fw(card->pdat->load.fw, card, card->dpram,
+                               card->dpram_size,
+                               card->pdat->load.offs - card->pdat->load.addr);
+       if (ret < 0)
+               goto failed;
+
+       if (card->pdat->reset)
+               card->pdat->reset(card->pdev, 0);
+       softing_clr_reset_dpram(card);
+       ret = softing_bootloader_command(card, 0, "card boot");
+       if (ret < 0)
+               goto failed;
+       ret = softing_load_app_fw(card->pdat->app.fw, card);
+       if (ret < 0)
+               goto failed;
+
+       ret = softing_chip_poweron(card);
+       if (ret < 0)
+               goto failed;
+
+       card->fw.up = 1;
+       mutex_unlock(&card->fw.lock);
+       return 0;
+failed:
+       card->fw.up = 0;
+       if (card->pdat->enable_irq)
+               card->pdat->enable_irq(card->pdev, 0);
+       softing_set_reset_dpram(card);
+       if (card->pdat->reset)
+               card->pdat->reset(card->pdev, 1);
+       mutex_unlock(&card->fw.lock);
+       return ret;
+}
+
+/*
+ * netdev sysfs
+ */
+static ssize_t show_channel(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct net_device *ndev = to_net_dev(dev);
+       struct softing_priv *priv = netdev2softing(ndev);
+
+       return sprintf(buf, "%i\n", priv->index);
+}
+
+static ssize_t show_chip(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct net_device *ndev = to_net_dev(dev);
+       struct softing_priv *priv = netdev2softing(ndev);
+
+       return sprintf(buf, "%i\n", priv->chip);
+}
+
+static ssize_t show_output(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct net_device *ndev = to_net_dev(dev);
+       struct softing_priv *priv = netdev2softing(ndev);
+
+       return sprintf(buf, "0x%02x\n", priv->output);
+}
+
+static ssize_t store_output(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct net_device *ndev = to_net_dev(dev);
+       struct softing_priv *priv = netdev2softing(ndev);
+       struct softing *card = priv->card;
+       unsigned long val;
+       int ret;
+
+       ret = strict_strtoul(buf, 0, &val);
+       if (ret < 0)
+               return ret;
+       val &= 0xFF;
+
+       ret = mutex_lock_interruptible(&card->fw.lock);
+       if (ret)
+               return -ERESTARTSYS;
+       if (netif_running(ndev)) {
+               mutex_unlock(&card->fw.lock);
+               return -EBUSY;
+       }
+       priv->output = val;
+       mutex_unlock(&card->fw.lock);
+       return count;
+}
+
+static const DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL);
+static const DEVICE_ATTR(chip, S_IRUGO, show_chip, NULL);
+static const DEVICE_ATTR(output, S_IRUGO | S_IWUSR, show_output, store_output);
+
+static const struct attribute *const netdev_sysfs_attrs[] = {
+       &dev_attr_channel.attr,
+       &dev_attr_chip.attr,
+       &dev_attr_output.attr,
+       NULL,
+};
+static const struct attribute_group netdev_sysfs_group = {
+       .name = NULL,
+       .attrs = (struct attribute **)netdev_sysfs_attrs,
+};
+
+static const struct net_device_ops softing_netdev_ops = {
+       .ndo_open = softing_netdev_open,
+       .ndo_stop = softing_netdev_stop,
+       .ndo_start_xmit = softing_netdev_start_xmit,
+};
+
+static const struct can_bittiming_const softing_btr_const = {
+       .name = "softing",
+       .tseg1_min = 1,
+       .tseg1_max = 16,
+       .tseg2_min = 1,
+       .tseg2_max = 8,
+       .sjw_max = 4, /* overruled */
+       .brp_min = 1,
+       .brp_max = 32, /* overruled */
+       .brp_inc = 1,
+};
+
+
+static __devinit struct net_device *softing_netdev_create(struct softing *card,
+               uint16_t chip_id)
+{
+       struct net_device *netdev;
+       struct softing_priv *priv;
+
+       netdev = alloc_candev(sizeof(*priv), TX_ECHO_SKB_MAX);
+       if (!netdev) {
+               dev_alert(&card->pdev->dev, "alloc_candev failed\n");
+               return NULL;
+       }
+       priv = netdev_priv(netdev);
+       priv->netdev = netdev;
+       priv->card = card;
+       memcpy(&priv->btr_const, &softing_btr_const, sizeof(priv->btr_const));
+       priv->btr_const.brp_max = card->pdat->max_brp;
+       priv->btr_const.sjw_max = card->pdat->max_sjw;
+       priv->can.bittiming_const = &priv->btr_const;
+       priv->can.clock.freq = 8000000;
+       priv->chip = chip_id;
+       priv->output = softing_default_output(netdev);
+       SET_NETDEV_DEV(netdev, &card->pdev->dev);
+
+       netdev->flags |= IFF_ECHO;
+       netdev->netdev_ops = &softing_netdev_ops;
+       priv->can.do_set_mode = softing_candev_set_mode;
+       priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
+
+       return netdev;
+}
+
+static __devinit int softing_netdev_register(struct net_device *netdev)
+{
+       int ret;
+
+       netdev->sysfs_groups[0] = &netdev_sysfs_group;
+       ret = register_candev(netdev);
+       if (ret) {
+               dev_alert(&netdev->dev, "register failed\n");
+               return ret;
+       }
+       return 0;
+}
+
+static void softing_netdev_cleanup(struct net_device *netdev)
+{
+       unregister_candev(netdev);
+       free_candev(netdev);
+}
+
+/*
+ * sysfs for Platform device
+ */
+#define DEV_ATTR_RO(name, member) \
+static ssize_t show_##name(struct device *dev, \
+               struct device_attribute *attr, char *buf) \
+{ \
+       struct softing *card = platform_get_drvdata(to_platform_device(dev)); \
+       return sprintf(buf, "%u\n", card->member); \
+} \
+static DEVICE_ATTR(name, 0444, show_##name, NULL)
+
+#define DEV_ATTR_RO_STR(name, member) \
+static ssize_t show_##name(struct device *dev, \
+               struct device_attribute *attr, char *buf) \
+{ \
+       struct softing *card = platform_get_drvdata(to_platform_device(dev)); \
+       return sprintf(buf, "%s\n", card->member); \
+} \
+static DEVICE_ATTR(name, 0444, show_##name, NULL)
+
+DEV_ATTR_RO(serial, id.serial);
+DEV_ATTR_RO_STR(firmware, pdat->app.fw);
+DEV_ATTR_RO(firmware_version, id.fw_version);
+DEV_ATTR_RO_STR(hardware, pdat->name);
+DEV_ATTR_RO(hardware_version, id.hw_version);
+DEV_ATTR_RO(license, id.license);
+DEV_ATTR_RO(frequency, id.freq);
+DEV_ATTR_RO(txpending, tx.pending);
+
+static struct attribute *softing_pdev_attrs[] = {
+       &dev_attr_serial.attr,
+       &dev_attr_firmware.attr,
+       &dev_attr_firmware_version.attr,
+       &dev_attr_hardware.attr,
+       &dev_attr_hardware_version.attr,
+       &dev_attr_license.attr,
+       &dev_attr_frequency.attr,
+       &dev_attr_txpending.attr,
+       NULL,
+};
+
+static const struct attribute_group softing_pdev_group = {
+       .name = NULL,
+       .attrs = softing_pdev_attrs,
+};
+
+/*
+ * platform driver
+ */
+static __devexit int softing_pdev_remove(struct platform_device *pdev)
+{
+       struct softing *card = platform_get_drvdata(pdev);
+       int j;
+
+       /* first, disable card*/
+       softing_card_shutdown(card);
+
+       for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
+               if (!card->net[j])
+                       continue;
+               softing_netdev_cleanup(card->net[j]);
+               card->net[j] = NULL;
+       }
+       sysfs_remove_group(&pdev->dev.kobj, &softing_pdev_group);
+
+       iounmap(card->dpram);
+       kfree(card);
+       return 0;
+}
+
+static __devinit int softing_pdev_probe(struct platform_device *pdev)
+{
+       const struct softing_platform_data *pdat = pdev->dev.platform_data;
+       struct softing *card;
+       struct net_device *netdev;
+       struct softing_priv *priv;
+       struct resource *pres;
+       int ret;
+       int j;
+
+       if (!pdat) {
+               dev_warn(&pdev->dev, "no platform data\n");
+               return -EINVAL;
+       }
+       if (pdat->nbus > ARRAY_SIZE(card->net)) {
+               dev_warn(&pdev->dev, "%u nets??\n", pdat->nbus);
+               return -EINVAL;
+       }
+
+       card = kzalloc(sizeof(*card), GFP_KERNEL);
+       if (!card)
+               return -ENOMEM;
+       card->pdat = pdat;
+       card->pdev = pdev;
+       platform_set_drvdata(pdev, card);
+       mutex_init(&card->fw.lock);
+       spin_lock_init(&card->spin);
+
+       ret = -EINVAL;
+       pres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!pres)
+               goto platform_resource_failed;;
+       card->dpram_phys = pres->start;
+       card->dpram_size = pres->end - pres->start + 1;
+       card->dpram = ioremap_nocache(card->dpram_phys, card->dpram_size);
+       if (!card->dpram) {
+               dev_alert(&card->pdev->dev, "dpram ioremap failed\n");
+               goto ioremap_failed;
+       }
+
+       pres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (pres)
+               card->irq.nr = pres->start;
+
+       /* reset card */
+       ret = softing_card_boot(card);
+       if (ret < 0) {
+               dev_alert(&pdev->dev, "failed to boot\n");
+               goto boot_failed;
+       }
+
+       /* only now, the chip's are known */
+       card->id.freq = card->pdat->freq;
+
+       ret = sysfs_create_group(&pdev->dev.kobj, &softing_pdev_group);
+       if (ret < 0) {
+               dev_alert(&card->pdev->dev, "sysfs failed\n");
+               goto sysfs_failed;
+       }
+
+       ret = -ENOMEM;
+       for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
+               card->net[j] = netdev =
+                       softing_netdev_create(card, card->id.chip[j]);
+               if (!netdev) {
+                       dev_alert(&pdev->dev, "failed to make can[%i]", j);
+                       goto netdev_failed;
+               }
+               priv = netdev_priv(card->net[j]);
+               priv->index = j;
+               ret = softing_netdev_register(netdev);
+               if (ret) {
+                       free_candev(netdev);
+                       card->net[j] = NULL;
+                       dev_alert(&card->pdev->dev,
+                                       "failed to register can[%i]\n", j);
+                       goto netdev_failed;
+               }
+       }
+       dev_info(&card->pdev->dev, "%s ready.\n", card->pdat->name);
+       return 0;
+
+netdev_failed:
+       for (j = 0; j < ARRAY_SIZE(card->net); ++j) {
+               if (!card->net[j])
+                       continue;
+               softing_netdev_cleanup(card->net[j]);
+       }
+       sysfs_remove_group(&pdev->dev.kobj, &softing_pdev_group);
+sysfs_failed:
+       softing_card_shutdown(card);
+boot_failed:
+       iounmap(card->dpram);
+ioremap_failed:
+platform_resource_failed:
+       kfree(card);
+       return ret;
+}
+
+static struct platform_driver softing_driver = {
+       .driver = {
+               .name = "softing",
+               .owner = THIS_MODULE,
+       },
+       .probe = softing_pdev_probe,
+       .remove = __devexit_p(softing_pdev_remove),
+};
+
+MODULE_ALIAS("platform:softing");
+
+static int __init softing_start(void)
+{
+       return platform_driver_register(&softing_driver);
+}
+
+static void __exit softing_stop(void)
+{
+       platform_driver_unregister(&softing_driver);
+}
+
+module_init(softing_start);
+module_exit(softing_stop);
+
+MODULE_DESCRIPTION("Softing DPRAM CAN driver");
+MODULE_AUTHOR("Kurt Van Dijck <kurt.van.dijck@eia.be>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/can/softing/softing_platform.h b/drivers/net/can/softing/softing_platform.h
new file mode 100644 (file)
index 0000000..ebbf698
--- /dev/null
@@ -0,0 +1,40 @@
+
+#include <linux/platform_device.h>
+
+#ifndef _SOFTING_DEVICE_H_
+#define _SOFTING_DEVICE_H_
+
+/* softing firmware directory prefix */
+#define fw_dir "softing-4.6/"
+
+struct softing_platform_data {
+       unsigned int manf;
+       unsigned int prod;
+       /*
+        * generation
+        * 1st with NEC or SJA1000
+        * 8bit, exclusive interrupt, ...
+        * 2nd only SJA1000
+        * 16bit, shared interrupt
+        */
+       int generation;
+       int nbus; /* # busses on device */
+       unsigned int freq; /* operating frequency in Hz */
+       unsigned int max_brp;
+       unsigned int max_sjw;
+       unsigned long dpram_size;
+       const char *name;
+       struct {
+               unsigned long offs;
+               unsigned long addr;
+               const char *fw;
+       } boot, load, app;
+       /*
+        * reset() function
+        * bring pdev in or out of reset, depending on value
+        */
+       int (*reset)(struct platform_device *pdev, int value);
+       int (*enable_irq)(struct platform_device *pdev, int value);
+};
+
+#endif
index 263a294..302be4a 100644 (file)
@@ -699,13 +699,13 @@ static void cnic_free_dma(struct cnic_dev *dev, struct cnic_dma *dma)
 static void cnic_setup_page_tbl(struct cnic_dev *dev, struct cnic_dma *dma)
 {
        int i;
-       u32 *page_table = dma->pgtbl;
+       __le32 *page_table = (__le32 *) dma->pgtbl;
 
        for (i = 0; i < dma->num_pages; i++) {
                /* Each entry needs to be in big endian format. */
-               *page_table = (u32) ((u64) dma->pg_map_arr[i] >> 32);
+               *page_table = cpu_to_le32((u64) dma->pg_map_arr[i] >> 32);
                page_table++;
-               *page_table = (u32) dma->pg_map_arr[i];
+               *page_table = cpu_to_le32(dma->pg_map_arr[i] & 0xffffffff);
                page_table++;
        }
 }
@@ -713,13 +713,13 @@ static void cnic_setup_page_tbl(struct cnic_dev *dev, struct cnic_dma *dma)
 static void cnic_setup_page_tbl_le(struct cnic_dev *dev, struct cnic_dma *dma)
 {
        int i;
-       u32 *page_table = dma->pgtbl;
+       __le32 *page_table = (__le32 *) dma->pgtbl;
 
        for (i = 0; i < dma->num_pages; i++) {
                /* Each entry needs to be in little endian format. */
-               *page_table = dma->pg_map_arr[i] & 0xffffffff;
+               *page_table = cpu_to_le32(dma->pg_map_arr[i] & 0xffffffff);
                page_table++;
-               *page_table = (u32) ((u64) dma->pg_map_arr[i] >> 32);
+               *page_table = cpu_to_le32((u64) dma->pg_map_arr[i] >> 32);
                page_table++;
        }
 }
@@ -2760,6 +2760,8 @@ static u32 cnic_service_bnx2_queues(struct cnic_dev *dev)
        u32 status_idx = (u16) *cp->kcq1.status_idx_ptr;
        int kcqe_cnt;
 
+       /* status block index must be read before reading other fields */
+       rmb();
        cp->kwq_con_idx = *cp->kwq_con_idx_ptr;
 
        while ((kcqe_cnt = cnic_get_kcqes(dev, &cp->kcq1))) {
@@ -2770,6 +2772,8 @@ static u32 cnic_service_bnx2_queues(struct cnic_dev *dev)
                barrier();
                if (status_idx != *cp->kcq1.status_idx_ptr) {
                        status_idx = (u16) *cp->kcq1.status_idx_ptr;
+                       /* status block index must be read first */
+                       rmb();
                        cp->kwq_con_idx = *cp->kwq_con_idx_ptr;
                } else
                        break;
@@ -2888,6 +2892,8 @@ static u32 cnic_service_bnx2x_kcq(struct cnic_dev *dev, struct kcq_info *info)
        u32 last_status = *info->status_idx_ptr;
        int kcqe_cnt;
 
+       /* status block index must be read before reading the KCQ */
+       rmb();
        while ((kcqe_cnt = cnic_get_kcqes(dev, info))) {
 
                service_kcqes(dev, kcqe_cnt);
@@ -2898,6 +2904,8 @@ static u32 cnic_service_bnx2x_kcq(struct cnic_dev *dev, struct kcq_info *info)
                        break;
 
                last_status = *info->status_idx_ptr;
+               /* status block index must be read before reading the KCQ */
+               rmb();
        }
        return last_status;
 }
@@ -2906,26 +2914,35 @@ static void cnic_service_bnx2x_bh(unsigned long data)
 {
        struct cnic_dev *dev = (struct cnic_dev *) data;
        struct cnic_local *cp = dev->cnic_priv;
-       u32 status_idx;
+       u32 status_idx, new_status_idx;
 
        if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags)))
                return;
 
-       status_idx = cnic_service_bnx2x_kcq(dev, &cp->kcq1);
+       while (1) {
+               status_idx = cnic_service_bnx2x_kcq(dev, &cp->kcq1);
 
-       CNIC_WR16(dev, cp->kcq1.io_addr, cp->kcq1.sw_prod_idx + MAX_KCQ_IDX);
+               CNIC_WR16(dev, cp->kcq1.io_addr,
+                         cp->kcq1.sw_prod_idx + MAX_KCQ_IDX);
 
-       if (BNX2X_CHIP_IS_E2(cp->chip_id)) {
-               status_idx = cnic_service_bnx2x_kcq(dev, &cp->kcq2);
+               if (!BNX2X_CHIP_IS_E2(cp->chip_id)) {
+                       cnic_ack_bnx2x_int(dev, cp->bnx2x_igu_sb_id, USTORM_ID,
+                                          status_idx, IGU_INT_ENABLE, 1);
+                       break;
+               }
+
+               new_status_idx = cnic_service_bnx2x_kcq(dev, &cp->kcq2);
+
+               if (new_status_idx != status_idx)
+                       continue;
 
                CNIC_WR16(dev, cp->kcq2.io_addr, cp->kcq2.sw_prod_idx +
                          MAX_KCQ_IDX);
 
                cnic_ack_igu_sb(dev, cp->bnx2x_igu_sb_id, IGU_SEG_ACCESS_DEF,
                                status_idx, IGU_INT_ENABLE, 1);
-       } else {
-               cnic_ack_bnx2x_int(dev, cp->bnx2x_igu_sb_id, USTORM_ID,
-                                  status_idx, IGU_INT_ENABLE, 1);
+
+               break;
        }
 }
 
index 059c1ee..ec35d45 100644 (file)
@@ -2710,6 +2710,8 @@ static int cxgb_open(struct net_device *dev)
        struct port_info *pi = netdev_priv(dev);
        struct adapter *adapter = pi->adapter;
 
+       netif_carrier_off(dev);
+
        if (!(adapter->flags & FULL_INIT_DONE)) {
                err = cxgb_up(adapter);
                if (err < 0)
@@ -3661,7 +3663,6 @@ static int __devinit init_one(struct pci_dev *pdev,
                pi->xact_addr_filt = -1;
                pi->rx_offload = RX_CSO;
                pi->port_id = i;
-               netif_carrier_off(netdev);
                netdev->irq = pdev->irq;
 
                netdev->features |= NETIF_F_SG | TSO_FLAGS;
index 56166ae..6aad64d 100644 (file)
@@ -2040,7 +2040,7 @@ static int __devinit setup_debugfs(struct adapter *adapter)
 {
        int i;
 
-       BUG_ON(adapter->debugfs_root == NULL);
+       BUG_ON(IS_ERR_OR_NULL(adapter->debugfs_root));
 
        /*
         * Debugfs support is best effort.
@@ -2061,7 +2061,7 @@ static int __devinit setup_debugfs(struct adapter *adapter)
  */
 static void cleanup_debugfs(struct adapter *adapter)
 {
-       BUG_ON(adapter->debugfs_root == NULL);
+       BUG_ON(IS_ERR_OR_NULL(adapter->debugfs_root));
 
        /*
         * Unlike our sister routine cleanup_proc(), we don't need to remove
@@ -2488,17 +2488,6 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
        struct port_info *pi;
        struct net_device *netdev;
 
-       /*
-        * Vet our module parameters.
-        */
-       if (msi != MSI_MSIX && msi != MSI_MSI) {
-               dev_err(&pdev->dev, "bad module parameter msi=%d; must be %d"
-                       " (MSI-X or MSI) or %d (MSI)\n", msi, MSI_MSIX,
-                       MSI_MSI);
-               err = -EINVAL;
-               goto err_out;
-       }
-
        /*
         * Print our driver banner the first time we're called to initialize a
         * device.
@@ -2711,11 +2700,11 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
        /*
         * Set up our debugfs entries.
         */
-       if (cxgb4vf_debugfs_root) {
+       if (!IS_ERR_OR_NULL(cxgb4vf_debugfs_root)) {
                adapter->debugfs_root =
                        debugfs_create_dir(pci_name(pdev),
                                           cxgb4vf_debugfs_root);
-               if (adapter->debugfs_root == NULL)
+               if (IS_ERR_OR_NULL(adapter->debugfs_root))
                        dev_warn(&pdev->dev, "could not create debugfs"
                                 " directory");
                else
@@ -2770,7 +2759,7 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
         */
 
 err_free_debugfs:
-       if (adapter->debugfs_root) {
+       if (!IS_ERR_OR_NULL(adapter->debugfs_root)) {
                cleanup_debugfs(adapter);
                debugfs_remove_recursive(adapter->debugfs_root);
        }
@@ -2802,7 +2791,6 @@ err_release_regions:
 err_disable_device:
        pci_disable_device(pdev);
 
-err_out:
        return err;
 }
 
@@ -2840,7 +2828,7 @@ static void __devexit cxgb4vf_pci_remove(struct pci_dev *pdev)
                /*
                 * Tear down our debugfs entries.
                 */
-               if (adapter->debugfs_root) {
+               if (!IS_ERR_OR_NULL(adapter->debugfs_root)) {
                        cleanup_debugfs(adapter);
                        debugfs_remove_recursive(adapter->debugfs_root);
                }
@@ -2873,6 +2861,46 @@ static void __devexit cxgb4vf_pci_remove(struct pci_dev *pdev)
        pci_release_regions(pdev);
 }
 
+/*
+ * "Shutdown" quiesce the device, stopping Ingress Packet and Interrupt
+ * delivery.
+ */
+static void __devexit cxgb4vf_pci_shutdown(struct pci_dev *pdev)
+{
+       struct adapter *adapter;
+       int pidx;
+
+       adapter = pci_get_drvdata(pdev);
+       if (!adapter)
+               return;
+
+       /*
+        * Disable all Virtual Interfaces.  This will shut down the
+        * delivery of all ingress packets into the chip for these
+        * Virtual Interfaces.
+        */
+       for_each_port(adapter, pidx) {
+               struct net_device *netdev;
+               struct port_info *pi;
+
+               if (!test_bit(pidx, &adapter->registered_device_map))
+                       continue;
+
+               netdev = adapter->port[pidx];
+               if (!netdev)
+                       continue;
+
+               pi = netdev_priv(netdev);
+               t4vf_enable_vi(adapter, pi->viid, false, false);
+       }
+
+       /*
+        * Free up all Queues which will prevent further DMA and
+        * Interrupts allowing various internal pathways to drain.
+        */
+       t4vf_free_sge_resources(adapter);
+}
+
 /*
  * PCI Device registration data structures.
  */
@@ -2906,6 +2934,7 @@ static struct pci_driver cxgb4vf_driver = {
        .id_table       = cxgb4vf_pci_tbl,
        .probe          = cxgb4vf_pci_probe,
        .remove         = __devexit_p(cxgb4vf_pci_remove),
+       .shutdown       = __devexit_p(cxgb4vf_pci_shutdown),
 };
 
 /*
@@ -2915,14 +2944,25 @@ static int __init cxgb4vf_module_init(void)
 {
        int ret;
 
+       /*
+        * Vet our module parameters.
+        */
+       if (msi != MSI_MSIX && msi != MSI_MSI) {
+               printk(KERN_WARNING KBUILD_MODNAME
+                      ": bad module parameter msi=%d; must be %d"
+                      " (MSI-X or MSI) or %d (MSI)\n",
+                      msi, MSI_MSIX, MSI_MSI);
+               return -EINVAL;
+       }
+
        /* Debugfs support is optional, just warn if this fails */
        cxgb4vf_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
-       if (!cxgb4vf_debugfs_root)
+       if (IS_ERR_OR_NULL(cxgb4vf_debugfs_root))
                printk(KERN_WARNING KBUILD_MODNAME ": could not create"
                       " debugfs entry, continuing\n");
 
        ret = pci_register_driver(&cxgb4vf_driver);
-       if (ret < 0)
+       if (ret < 0 && !IS_ERR_OR_NULL(cxgb4vf_debugfs_root))
                debugfs_remove(cxgb4vf_debugfs_root);
        return ret;
 }
index 0f51c80..192db22 100644 (file)
@@ -171,7 +171,7 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size,
        delay_idx = 0;
        ms = delay[0];
 
-       for (i = 0; i < 500; i += ms) {
+       for (i = 0; i < FW_CMD_MAX_TIMEOUT; i += ms) {
                if (sleep_ok) {
                        ms = delay[delay_idx];
                        if (delay_idx < ARRAY_SIZE(delay) - 1)
index 2a628d1..7018bfe 100644 (file)
@@ -1008,7 +1008,7 @@ static void emac_rx_handler(void *token, int len, int status)
        int                     ret;
 
        /* free and bail if we are shutting down */
-       if (unlikely(!netif_running(ndev))) {
+       if (unlikely(!netif_running(ndev) || !netif_carrier_ok(ndev))) {
                dev_kfree_skb_any(skb);
                return;
        }
index 1b48b68..8b0084d 100644 (file)
@@ -1094,7 +1094,7 @@ static int depca_rx(struct net_device *dev)
                                }
                        }
                        /* Change buffer ownership for this last frame, back to the adapter */
-                       for (; lp->rx_old != entry; lp->rx_old = (++lp->rx_old) & lp->rxRingMask) {
+                       for (; lp->rx_old != entry; lp->rx_old = (lp->rx_old + 1) & lp->rxRingMask) {
                                writel(readl(&lp->rx_ring[lp->rx_old].base) | R_OWN, &lp->rx_ring[lp->rx_old].base);
                        }
                        writel(readl(&lp->rx_ring[entry].base) | R_OWN, &lp->rx_ring[entry].base);
@@ -1103,7 +1103,7 @@ static int depca_rx(struct net_device *dev)
                /*
                   ** Update entry information
                 */
-               lp->rx_new = (++lp->rx_new) & lp->rxRingMask;
+               lp->rx_new = (lp->rx_new + 1) & lp->rxRingMask;
        }
 
        return 0;
@@ -1148,7 +1148,7 @@ static int depca_tx(struct net_device *dev)
                }
 
                /* Update all the pointers */
-               lp->tx_old = (++lp->tx_old) & lp->txRingMask;
+               lp->tx_old = (lp->tx_old + 1) & lp->txRingMask;
        }
 
        return 0;
index e1a8216..c05db60 100644 (file)
@@ -1753,8 +1753,6 @@ rio_close (struct net_device *dev)
 
        /* Free all the skbuffs in the queue. */
        for (i = 0; i < RX_RING_SIZE; i++) {
-               np->rx_ring[i].status = 0;
-               np->rx_ring[i].fraginfo = 0;
                skb = np->rx_skbuff[i];
                if (skb) {
                        pci_unmap_single(np->pdev,
@@ -1763,6 +1761,8 @@ rio_close (struct net_device *dev)
                        dev_kfree_skb (skb);
                        np->rx_skbuff[i] = NULL;
                }
+               np->rx_ring[i].status = 0;
+               np->rx_ring[i].fraginfo = 0;
        }
        for (i = 0; i < TX_RING_SIZE; i++) {
                skb = np->tx_skbuff[i];
index 2d4c4fc..461dd6f 100644 (file)
@@ -802,10 +802,7 @@ dm9000_init_dm9000(struct net_device *dev)
        /* Checksum mode */
        dm9000_set_rx_csum_unlocked(dev, db->rx_csum);
 
-       /* GPIO0 on pre-activate PHY */
-       iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */
        iow(db, DM9000_GPCR, GPCR_GEP_CNTL);    /* Let GPIO0 output */
-       iow(db, DM9000_GPR, 0); /* Enable PHY */
 
        ncr = (db->flags & DM9000_PLATF_EXT_PHY) ? NCR_EXT_PHY : 0;
 
@@ -852,8 +849,8 @@ static void dm9000_timeout(struct net_device *dev)
        unsigned long flags;
 
        /* Save previous register address */
-       reg_save = readb(db->io_addr);
        spin_lock_irqsave(&db->lock, flags);
+       reg_save = readb(db->io_addr);
 
        netif_stop_queue(dev);
        dm9000_reset(db);
@@ -1194,6 +1191,10 @@ dm9000_open(struct net_device *dev)
        if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
                return -EAGAIN;
 
+       /* GPIO0 on pre-activate PHY, Reg 1F is not set by reset */
+       iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */
+       mdelay(1); /* delay needs by DM9000B */
+
        /* Initialize DM9000 board */
        dm9000_reset(db);
        dm9000_init_dm9000(dev);
index 9d8a20b..8318ea0 100644 (file)
@@ -337,8 +337,6 @@ static int dnet_mii_init(struct dnet *bp)
        for (i = 0; i < PHY_MAX_ADDR; i++)
                bp->mii_bus->irq[i] = PHY_POLL;
 
-       platform_set_drvdata(bp->dev, bp->mii_bus);
-
        if (mdiobus_register(bp->mii_bus)) {
                err = -ENXIO;
                goto err_out_free_mdio_irq;
@@ -863,6 +861,7 @@ static int __devinit dnet_probe(struct platform_device *pdev)
        bp = netdev_priv(dev);
        bp->dev = dev;
 
+       platform_set_drvdata(pdev, dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
 
        spin_lock_init(&bp->lock);
index aed223b..7501d97 100644 (file)
@@ -124,6 +124,7 @@ static s32 e1000_set_phy_type(struct e1000_hw *hw)
        case M88E1000_I_PHY_ID:
        case M88E1011_I_PHY_ID:
        case M88E1111_I_PHY_ID:
+       case M88E1118_E_PHY_ID:
                hw->phy_type = e1000_phy_m88;
                break;
        case IGP01E1000_I_PHY_ID:
@@ -3222,7 +3223,8 @@ static s32 e1000_detect_gig_phy(struct e1000_hw *hw)
                break;
        case e1000_ce4100:
                if ((hw->phy_id == RTL8211B_PHY_ID) ||
-                   (hw->phy_id == RTL8201N_PHY_ID))
+                   (hw->phy_id == RTL8201N_PHY_ID) ||
+                   (hw->phy_id == M88E1118_E_PHY_ID))
                        match = true;
                break;
        case e1000_82541:
index 196eeda..c70b23d 100644 (file)
@@ -2917,6 +2917,7 @@ struct e1000_host_command_info {
 #define M88E1000_14_PHY_ID M88E1000_E_PHY_ID
 #define M88E1011_I_REV_4   0x04
 #define M88E1111_I_PHY_ID  0x01410CC0
+#define M88E1118_E_PHY_ID  0x01410E40
 #define L1LXT971A_PHY_ID   0x001378E0
 
 #define RTL8211B_PHY_ID    0x001CC910
index 55c1711..33e7c45 100644 (file)
@@ -42,7 +42,8 @@
 #define GBE_CONFIG_RAM_BASE \
        ((unsigned int)(CONFIG_RAM_BASE + GBE_CONFIG_OFFSET))
 
-#define GBE_CONFIG_BASE_VIRT    phys_to_virt(GBE_CONFIG_RAM_BASE)
+#define GBE_CONFIG_BASE_VIRT \
+       ((void __iomem *)phys_to_virt(GBE_CONFIG_RAM_BASE))
 
 #define GBE_CONFIG_FLASH_WRITE(base, offset, count, data) \
        (iowrite16_rep(base + offset, data, count))
index 1c18f26..2e50228 100644 (file)
@@ -937,6 +937,9 @@ static void e1000_print_hw_hang(struct work_struct *work)
        u16 phy_status, phy_1000t_status, phy_ext_status;
        u16 pci_status;
 
+       if (test_bit(__E1000_DOWN, &adapter->state))
+               return;
+
        e1e_rphy(hw, PHY_STATUS, &phy_status);
        e1e_rphy(hw, PHY_1000T_STATUS, &phy_1000t_status);
        e1e_rphy(hw, PHY_EXT_STATUS, &phy_ext_status);
@@ -1506,6 +1509,9 @@ static void e1000e_downshift_workaround(struct work_struct *work)
        struct e1000_adapter *adapter = container_of(work,
                                        struct e1000_adapter, downshift_task);
 
+       if (test_bit(__E1000_DOWN, &adapter->state))
+               return;
+
        e1000e_gig_downshift_workaround_ich8lan(&adapter->hw);
 }
 
@@ -3338,6 +3344,21 @@ int e1000e_up(struct e1000_adapter *adapter)
        return 0;
 }
 
+static void e1000e_flush_descriptors(struct e1000_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+
+       if (!(adapter->flags2 & FLAG2_DMA_BURST))
+               return;
+
+       /* flush pending descriptor writebacks to memory */
+       ew32(TIDV, adapter->tx_int_delay | E1000_TIDV_FPD);
+       ew32(RDTR, adapter->rx_int_delay | E1000_RDTR_FPD);
+
+       /* execute the writes immediately */
+       e1e_flush();
+}
+
 void e1000e_down(struct e1000_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
@@ -3377,6 +3398,9 @@ void e1000e_down(struct e1000_adapter *adapter)
 
        if (!pci_channel_offline(adapter->pdev))
                e1000e_reset(adapter);
+
+       e1000e_flush_descriptors(adapter);
+
        e1000_clean_tx_ring(adapter);
        e1000_clean_rx_ring(adapter);
 
@@ -3765,6 +3789,10 @@ static void e1000e_update_phy_task(struct work_struct *work)
 {
        struct e1000_adapter *adapter = container_of(work,
                                        struct e1000_adapter, update_phy_task);
+
+       if (test_bit(__E1000_DOWN, &adapter->state))
+               return;
+
        e1000_get_phy_info(&adapter->hw);
 }
 
@@ -3775,6 +3803,10 @@ static void e1000e_update_phy_task(struct work_struct *work)
 static void e1000_update_phy_info(unsigned long data)
 {
        struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+
+       if (test_bit(__E1000_DOWN, &adapter->state))
+               return;
+
        schedule_work(&adapter->update_phy_task);
 }
 
@@ -4149,6 +4181,9 @@ static void e1000_watchdog_task(struct work_struct *work)
        u32 link, tctl;
        int tx_pending = 0;
 
+       if (test_bit(__E1000_DOWN, &adapter->state))
+               return;
+
        link = e1000e_has_link(adapter);
        if ((netif_carrier_ok(netdev)) && link) {
                /* Cancel scheduled suspend requests. */
@@ -4309,7 +4344,6 @@ link_up:
                         * to get done, so reset controller to flush Tx.
                         * (Do the reset outside of interrupt context).
                         */
-                       adapter->tx_timeout_count++;
                        schedule_work(&adapter->reset_task);
                        /* return immediately since reset is imminent */
                        return;
@@ -4338,19 +4372,12 @@ link_up:
        else
                ew32(ICS, E1000_ICS_RXDMT0);
 
+       /* flush pending descriptors to memory before detecting Tx hang */
+       e1000e_flush_descriptors(adapter);
+
        /* Force detection of hung controller every watchdog period */
        adapter->detect_tx_hung = 1;
 
-       /* flush partial descriptors to memory before detecting Tx hang */
-       if (adapter->flags2 & FLAG2_DMA_BURST) {
-               ew32(TIDV, adapter->tx_int_delay | E1000_TIDV_FPD);
-               ew32(RDTR, adapter->rx_int_delay | E1000_RDTR_FPD);
-               /*
-                * no need to flush the writes because the timeout code does
-                * an er32 first thing
-                */
-       }
-
        /*
         * With 82571 controllers, LAA may be overwritten due to controller
         * reset from the other port. Set the appropriate LAA in RAR[0]
@@ -4888,6 +4915,10 @@ static void e1000_reset_task(struct work_struct *work)
        struct e1000_adapter *adapter;
        adapter = container_of(work, struct e1000_adapter, reset_task);
 
+       /* don't run the task if already down */
+       if (test_bit(__E1000_DOWN, &adapter->state))
+               return;
+
        if (!((adapter->flags & FLAG_RX_NEEDS_RESTART) &&
              (adapter->flags & FLAG_RX_RESTART_NOW))) {
                e1000e_dump(adapter);
@@ -5936,7 +5967,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
                /* APME bit in EEPROM is mapped to WUC.APME */
                eeprom_data = er32(WUC);
                eeprom_apme_mask = E1000_WUC_APME;
-               if (eeprom_data & E1000_WUC_PHY_WAKE)
+               if ((hw->mac.type > e1000_ich10lan) &&
+                   (eeprom_data & E1000_WUC_PHY_WAKE))
                        adapter->flags2 |= FLAG2_HAS_PHY_WAKEUP;
        } else if (adapter->flags & FLAG_APME_IN_CTRL3) {
                if (adapter->flags & FLAG_APME_CHECK_PORT_B &&
index 112c5aa..907b05a 100644 (file)
@@ -812,7 +812,7 @@ static void enc28j60_read_tsv(struct enc28j60_net *priv, u8 tsv[TSV_SIZE])
        if (netif_msg_hw(priv))
                printk(KERN_DEBUG DRV_NAME ": reading TSV at addr:0x%04x\n",
                         endptr + 1);
-       enc28j60_mem_read(priv, endptr + 1, sizeof(tsv), tsv);
+       enc28j60_mem_read(priv, endptr + 1, TSV_SIZE, tsv);
 }
 
 static void enc28j60_dump_tsv(struct enc28j60_net *priv, const char *msg,
index b79d7e1..db0290f 100644 (file)
@@ -1163,15 +1163,11 @@ static int ethoc_resume(struct platform_device *pdev)
 # define ethoc_resume  NULL
 #endif
 
-#ifdef CONFIG_OF
 static struct of_device_id ethoc_match[] = {
-       {
-               .compatible = "opencores,ethoc",
-       },
+       { .compatible = "opencores,ethoc", },
        {},
 };
 MODULE_DEVICE_TABLE(of, ethoc_match);
-#endif
 
 static struct platform_driver ethoc_driver = {
        .probe   = ethoc_probe,
@@ -1181,9 +1177,7 @@ static struct platform_driver ethoc_driver = {
        .driver  = {
                .name = "ethoc",
                .owner = THIS_MODULE,
-#ifdef CONFIG_OF
                .of_match_table = ethoc_match,
-#endif
        },
 };
 
index 2a71373..cd0282d 100644 (file)
@@ -74,7 +74,8 @@ static struct platform_device_id fec_devtype[] = {
        }, {
                .name = "imx28-fec",
                .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME,
-       }
+       },
+       { }
 };
 
 static unsigned char macaddr[ETH_ALEN];
index af09296..9c0b1ba 100644 (file)
@@ -5645,6 +5645,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
                goto out_error;
        }
 
+       netif_carrier_off(dev);
+
        dev_info(&pci_dev->dev, "ifname %s, PHY OUI 0x%x @ %d, addr %pM\n",
                 dev->name, np->phy_oui, np->phyaddr, dev->dev_addr);
 
index 74486a8..af3822f 100644 (file)
@@ -220,7 +220,7 @@ static u32 e1000_hash_mc_addr_vf(struct e1000_hw *hw, u8 *mc_addr)
  *  The parameter rar_count will usually be hw->mac.rar_entry_count
  *  unless there are workarounds that change this.
  **/
-void e1000_update_mc_addr_list_vf(struct e1000_hw *hw,
+static void e1000_update_mc_addr_list_vf(struct e1000_hw *hw,
                                   u8 *mc_addr_list, u32 mc_addr_count,
                                   u32 rar_used_count, u32 rar_count)
 {
index d5ede2d..ebbda7d 100644 (file)
@@ -1370,6 +1370,9 @@ s32 ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw)
                hw_dbg(hw, " New MAC Addr =%pM\n", hw->mac.addr);
 
                hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV);
+
+               /*  clear VMDq pool/queue selection for RAR 0 */
+               hw->mac.ops.clear_vmdq(hw, 0, IXGBE_CLEAR_VMDQ_ALL);
        }
        hw->addr_ctrl.overflow_promisc = 0;
 
index 6342d48..c54a882 100644 (file)
@@ -159,13 +159,13 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid,
        struct scatterlist *sg;
        unsigned int i, j, dmacount;
        unsigned int len;
-       static const unsigned int bufflen = 4096;
+       static const unsigned int bufflen = IXGBE_FCBUFF_MIN;
        unsigned int firstoff = 0;
        unsigned int lastsize;
        unsigned int thisoff = 0;
        unsigned int thislen = 0;
        u32 fcbuff, fcdmarw, fcfltrw;
-       dma_addr_t addr;
+       dma_addr_t addr = 0;
 
        if (!netdev || !sgl)
                return 0;
@@ -254,6 +254,24 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid,
        /* only the last buffer may have non-full bufflen */
        lastsize = thisoff + thislen;
 
+       /*
+        * lastsize can not be buffer len.
+        * If it is then adding another buffer with lastsize = 1.
+        */
+       if (lastsize == bufflen) {
+               if (j >= IXGBE_BUFFCNT_MAX) {
+                       e_err(drv, "xid=%x:%d,%d,%d:addr=%llx "
+                               "not enough user buffers. We need an extra "
+                               "buffer because lastsize is bufflen.\n",
+                               xid, i, j, dmacount, (u64)addr);
+                       goto out_noddp_free;
+               }
+
+               ddp->udl[j] = (u64)(fcoe->extra_ddp_buffer_dma);
+               j++;
+               lastsize = 1;
+       }
+
        fcbuff = (IXGBE_FCBUFF_4KB << IXGBE_FCBUFF_BUFFSIZE_SHIFT);
        fcbuff |= ((j & 0xff) << IXGBE_FCBUFF_BUFFCNT_SHIFT);
        fcbuff |= (firstoff << IXGBE_FCBUFF_OFFSET_SHIFT);
@@ -532,6 +550,24 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter)
                        e_err(drv, "failed to allocated FCoE DDP pool\n");
 
                spin_lock_init(&fcoe->lock);
+
+               /* Extra buffer to be shared by all DDPs for HW work around */
+               fcoe->extra_ddp_buffer = kmalloc(IXGBE_FCBUFF_MIN, GFP_ATOMIC);
+               if (fcoe->extra_ddp_buffer == NULL) {
+                       e_err(drv, "failed to allocated extra DDP buffer\n");
+                       goto out_extra_ddp_buffer_alloc;
+               }
+
+               fcoe->extra_ddp_buffer_dma =
+                       dma_map_single(&adapter->pdev->dev,
+                                      fcoe->extra_ddp_buffer,
+                                      IXGBE_FCBUFF_MIN,
+                                      DMA_FROM_DEVICE);
+               if (dma_mapping_error(&adapter->pdev->dev,
+                                     fcoe->extra_ddp_buffer_dma)) {
+                       e_err(drv, "failed to map extra DDP buffer\n");
+                       goto out_extra_ddp_buffer_dma;
+               }
        }
 
        /* Enable L2 eth type filter for FCoE */
@@ -581,6 +617,14 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter)
                }
        }
 #endif
+
+       return;
+
+out_extra_ddp_buffer_dma:
+       kfree(fcoe->extra_ddp_buffer);
+out_extra_ddp_buffer_alloc:
+       pci_pool_destroy(fcoe->pool);
+       fcoe->pool = NULL;
 }
 
 /**
@@ -600,6 +644,11 @@ void ixgbe_cleanup_fcoe(struct ixgbe_adapter *adapter)
        if (fcoe->pool) {
                for (i = 0; i < IXGBE_FCOE_DDP_MAX; i++)
                        ixgbe_fcoe_ddp_put(adapter->netdev, i);
+               dma_unmap_single(&adapter->pdev->dev,
+                                fcoe->extra_ddp_buffer_dma,
+                                IXGBE_FCBUFF_MIN,
+                                DMA_FROM_DEVICE);
+               kfree(fcoe->extra_ddp_buffer);
                pci_pool_destroy(fcoe->pool);
                fcoe->pool = NULL;
        }
index 4bc2c55..65cc8fb 100644 (file)
@@ -70,6 +70,8 @@ struct ixgbe_fcoe {
        spinlock_t lock;
        struct pci_pool *pool;
        struct ixgbe_fcoe_ddp ddp[IXGBE_FCOE_DDP_MAX];
+       unsigned char *extra_ddp_buffer;
+       dma_addr_t extra_ddp_buffer_dma;
 };
 
 #endif /* _IXGBE_FCOE_H */
index 602078b..30f9ccf 100644 (file)
@@ -52,7 +52,7 @@ char ixgbe_driver_name[] = "ixgbe";
 static const char ixgbe_driver_string[] =
                              "Intel(R) 10 Gigabit PCI Express Network Driver";
 
-#define DRV_VERSION "3.0.12-k2"
+#define DRV_VERSION "3.2.9-k2"
 const char ixgbe_driver_version[] = DRV_VERSION;
 static char ixgbe_copyright[] = "Copyright (c) 1999-2010 Intel Corporation.";
 
@@ -3176,9 +3176,16 @@ static void ixgbe_set_rx_buffer_len(struct ixgbe_adapter *adapter)
        u32 mhadd, hlreg0;
 
        /* Decide whether to use packet split mode or not */
+       /* On by default */
+       adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED;
+
        /* Do not use packet split if we're in SR-IOV Mode */
-       if (!adapter->num_vfs)
-               adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED;
+       if (adapter->num_vfs)
+               adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED;
+
+       /* Disable packet split due to 82599 erratum #45 */
+       if (hw->mac.type == ixgbe_mac_82599EB)
+               adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED;
 
        /* Set the RX buffer length according to the mode */
        if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
@@ -3721,7 +3728,8 @@ static void ixgbe_sfp_link_config(struct ixgbe_adapter *adapter)
                         * We need to try and force an autonegotiation
                         * session, then bring up link.
                         */
-                       hw->mac.ops.setup_sfp(hw);
+                       if (hw->mac.ops.setup_sfp)
+                               hw->mac.ops.setup_sfp(hw);
                        if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK))
                                schedule_work(&adapter->multispeed_fiber_task);
                } else {
@@ -4863,16 +4871,13 @@ static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter)
 {
        int q_idx, num_q_vectors;
        struct ixgbe_q_vector *q_vector;
-       int napi_vectors;
        int (*poll)(struct napi_struct *, int);
 
        if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
                num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
-               napi_vectors = adapter->num_rx_queues;
                poll = &ixgbe_clean_rxtx_many;
        } else {
                num_q_vectors = 1;
-               napi_vectors = 1;
                poll = &ixgbe_poll;
        }
 
@@ -5964,7 +5969,8 @@ static void ixgbe_sfp_config_module_task(struct work_struct *work)
                unregister_netdev(adapter->netdev);
                return;
        }
-       hw->mac.ops.setup_sfp(hw);
+       if (hw->mac.ops.setup_sfp)
+               hw->mac.ops.setup_sfp(hw);
 
        if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK))
                /* This will also work for DA Twinax connections */
index 47b1573..187b3a1 100644 (file)
@@ -110,12 +110,10 @@ static int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid,
        return adapter->hw.mac.ops.set_vfta(&adapter->hw, vid, vf, (bool)add);
 }
 
-
 static void ixgbe_set_vmolr(struct ixgbe_hw *hw, u32 vf, bool aupe)
 {
        u32 vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf));
        vmolr |= (IXGBE_VMOLR_ROMPE |
-                 IXGBE_VMOLR_ROPE |
                  IXGBE_VMOLR_BAM);
        if (aupe)
                vmolr |= IXGBE_VMOLR_AUPE;
index 3a89239..f2518b0 100644 (file)
@@ -133,17 +133,17 @@ static s32 ixgbe_reset_hw_X540(struct ixgbe_hw *hw)
        }
 
        ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
-       IXGBE_WRITE_REG(hw, IXGBE_CTRL, (ctrl | IXGBE_CTRL_RST));
+       IXGBE_WRITE_REG(hw, IXGBE_CTRL, (ctrl | reset_bit));
        IXGBE_WRITE_FLUSH(hw);
 
        /* Poll for reset bit to self-clear indicating reset is complete */
        for (i = 0; i < 10; i++) {
                udelay(1);
                ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
-               if (!(ctrl & IXGBE_CTRL_RST))
+               if (!(ctrl & reset_bit))
                        break;
        }
-       if (ctrl & IXGBE_CTRL_RST) {
+       if (ctrl & reset_bit) {
                status = IXGBE_ERR_RESET_FAILED;
                hw_dbg(hw, "Reset polling failed to complete.\n");
        }
index f69e73e..79ccb54 100644 (file)
@@ -260,7 +260,7 @@ static int macb_mii_init(struct macb *bp)
        for (i = 0; i < PHY_MAX_ADDR; i++)
                bp->mii_bus->irq[i] = PHY_POLL;
 
-       platform_set_drvdata(bp->dev, bp->mii_bus);
+       dev_set_drvdata(&bp->dev->dev, bp->mii_bus);
 
        if (mdiobus_register(bp->mii_bus))
                goto err_out_free_mdio_irq;
index 5933621..fc27a99 100644 (file)
@@ -528,8 +528,9 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q,
                vnet_hdr_len = q->vnet_hdr_sz;
 
                err = -EINVAL;
-               if ((len -= vnet_hdr_len) < 0)
+               if (len < vnet_hdr_len)
                        goto err;
+               len -= vnet_hdr_len;
 
                err = memcpy_fromiovecend((void *)&vnet_hdr, iv, 0,
                                           sizeof(vnet_hdr));
index 4ffdc18..2765a3c 100644 (file)
@@ -1286,6 +1286,21 @@ static DEFINE_PCI_DEVICE_TABLE(mlx4_pci_table) = {
        { PCI_VDEVICE(MELLANOX, 0x6764) }, /* MT26468 ConnectX EN 10GigE PCIe gen2*/
        { PCI_VDEVICE(MELLANOX, 0x6746) }, /* MT26438 ConnectX EN 40GigE PCIe gen2 5GT/s */
        { PCI_VDEVICE(MELLANOX, 0x676e) }, /* MT26478 ConnectX2 40GigE PCIe gen2 */
+       { PCI_VDEVICE(MELLANOX, 0x1002) }, /* MT25400 Family [ConnectX-2 Virtual Function] */
+       { PCI_VDEVICE(MELLANOX, 0x1003) }, /* MT27500 Family [ConnectX-3] */
+       { PCI_VDEVICE(MELLANOX, 0x1004) }, /* MT27500 Family [ConnectX-3 Virtual Function] */
+       { PCI_VDEVICE(MELLANOX, 0x1005) }, /* MT27510 Family */
+       { PCI_VDEVICE(MELLANOX, 0x1006) }, /* MT27511 Family */
+       { PCI_VDEVICE(MELLANOX, 0x1007) }, /* MT27520 Family */
+       { PCI_VDEVICE(MELLANOX, 0x1008) }, /* MT27521 Family */
+       { PCI_VDEVICE(MELLANOX, 0x1009) }, /* MT27530 Family */
+       { PCI_VDEVICE(MELLANOX, 0x100a) }, /* MT27531 Family */
+       { PCI_VDEVICE(MELLANOX, 0x100b) }, /* MT27540 Family */
+       { PCI_VDEVICE(MELLANOX, 0x100c) }, /* MT27541 Family */
+       { PCI_VDEVICE(MELLANOX, 0x100d) }, /* MT27550 Family */
+       { PCI_VDEVICE(MELLANOX, 0x100e) }, /* MT27551 Family */
+       { PCI_VDEVICE(MELLANOX, 0x100f) }, /* MT27560 Family */
+       { PCI_VDEVICE(MELLANOX, 0x1010) }, /* MT27561 Family */
        { 0, }
 };
 
index 2541321..9fb59d3 100644 (file)
@@ -4489,6 +4489,9 @@ static int niu_alloc_channels(struct niu *np)
 {
        struct niu_parent *parent = np->parent;
        int first_rx_channel, first_tx_channel;
+       int num_rx_rings, num_tx_rings;
+       struct rx_ring_info *rx_rings;
+       struct tx_ring_info *tx_rings;
        int i, port, err;
 
        port = np->port;
@@ -4498,18 +4501,21 @@ static int niu_alloc_channels(struct niu *np)
                first_tx_channel += parent->txchan_per_port[i];
        }
 
-       np->num_rx_rings = parent->rxchan_per_port[port];
-       np->num_tx_rings = parent->txchan_per_port[port];
+       num_rx_rings = parent->rxchan_per_port[port];
+       num_tx_rings = parent->txchan_per_port[port];
 
-       netif_set_real_num_rx_queues(np->dev, np->num_rx_rings);
-       netif_set_real_num_tx_queues(np->dev, np->num_tx_rings);
-
-       np->rx_rings = kcalloc(np->num_rx_rings, sizeof(struct rx_ring_info),
-                              GFP_KERNEL);
+       rx_rings = kcalloc(num_rx_rings, sizeof(struct rx_ring_info),
+                          GFP_KERNEL);
        err = -ENOMEM;
-       if (!np->rx_rings)
+       if (!rx_rings)
                goto out_err;
 
+       np->num_rx_rings = num_rx_rings;
+       smp_wmb();
+       np->rx_rings = rx_rings;
+
+       netif_set_real_num_rx_queues(np->dev, num_rx_rings);
+
        for (i = 0; i < np->num_rx_rings; i++) {
                struct rx_ring_info *rp = &np->rx_rings[i];
 
@@ -4538,12 +4544,18 @@ static int niu_alloc_channels(struct niu *np)
                        return err;
        }
 
-       np->tx_rings = kcalloc(np->num_tx_rings, sizeof(struct tx_ring_info),
-                              GFP_KERNEL);
+       tx_rings = kcalloc(num_tx_rings, sizeof(struct tx_ring_info),
+                          GFP_KERNEL);
        err = -ENOMEM;
-       if (!np->tx_rings)
+       if (!tx_rings)
                goto out_err;
 
+       np->num_tx_rings = num_tx_rings;
+       smp_wmb();
+       np->tx_rings = tx_rings;
+
+       netif_set_real_num_tx_queues(np->dev, num_tx_rings);
+
        for (i = 0; i < np->num_tx_rings; i++) {
                struct tx_ring_info *rp = &np->tx_rings[i];
 
@@ -6246,11 +6258,17 @@ static void niu_sync_mac_stats(struct niu *np)
 static void niu_get_rx_stats(struct niu *np)
 {
        unsigned long pkts, dropped, errors, bytes;
+       struct rx_ring_info *rx_rings;
        int i;
 
        pkts = dropped = errors = bytes = 0;
+
+       rx_rings = ACCESS_ONCE(np->rx_rings);
+       if (!rx_rings)
+               goto no_rings;
+
        for (i = 0; i < np->num_rx_rings; i++) {
-               struct rx_ring_info *rp = &np->rx_rings[i];
+               struct rx_ring_info *rp = &rx_rings[i];
 
                niu_sync_rx_discard_stats(np, rp, 0);
 
@@ -6259,6 +6277,8 @@ static void niu_get_rx_stats(struct niu *np)
                dropped += rp->rx_dropped;
                errors += rp->rx_errors;
        }
+
+no_rings:
        np->dev->stats.rx_packets = pkts;
        np->dev->stats.rx_bytes = bytes;
        np->dev->stats.rx_dropped = dropped;
@@ -6268,16 +6288,24 @@ static void niu_get_rx_stats(struct niu *np)
 static void niu_get_tx_stats(struct niu *np)
 {
        unsigned long pkts, errors, bytes;
+       struct tx_ring_info *tx_rings;
        int i;
 
        pkts = errors = bytes = 0;
+
+       tx_rings = ACCESS_ONCE(np->tx_rings);
+       if (!tx_rings)
+               goto no_rings;
+
        for (i = 0; i < np->num_tx_rings; i++) {
-               struct tx_ring_info *rp = &np->tx_rings[i];
+               struct tx_ring_info *rp = &tx_rings[i];
 
                pkts += rp->tx_packets;
                bytes += rp->tx_bytes;
                errors += rp->tx_errors;
        }
+
+no_rings:
        np->dev->stats.tx_packets = pkts;
        np->dev->stats.tx_bytes = bytes;
        np->dev->stats.tx_errors = errors;
@@ -6287,9 +6315,10 @@ static struct net_device_stats *niu_get_stats(struct net_device *dev)
 {
        struct niu *np = netdev_priv(dev);
 
-       niu_get_rx_stats(np);
-       niu_get_tx_stats(np);
-
+       if (netif_running(dev)) {
+               niu_get_rx_stats(np);
+               niu_get_tx_stats(np);
+       }
        return &dev->stats;
 }
 
index a0c26a9..e1e33c8 100644 (file)
@@ -73,7 +73,7 @@ struct pch_gbe_regs {
        struct pch_gbe_regs_mac_adr mac_adr[16];
        u32 ADDR_MASK;
        u32 MIIM;
-       u32 reserve2;
+       u32 MAC_ADDR_LOAD;
        u32 RGMII_ST;
        u32 RGMII_CTRL;
        u32 reserve3[3];
index d735530..b99e90a 100644 (file)
@@ -29,6 +29,7 @@ const char pch_driver_version[] = DRV_VERSION;
 #define PCH_GBE_SHORT_PKT              64
 #define DSC_INIT16                     0xC000
 #define PCH_GBE_DMA_ALIGN              0
+#define PCH_GBE_DMA_PADDING            2
 #define PCH_GBE_WATCHDOG_PERIOD                (1 * HZ)        /* watchdog time */
 #define PCH_GBE_COPYBREAK_DEFAULT      256
 #define PCH_GBE_PCI_BAR                        1
@@ -88,6 +89,12 @@ static unsigned int copybreak __read_mostly = PCH_GBE_COPYBREAK_DEFAULT;
 static int pch_gbe_mdio_read(struct net_device *netdev, int addr, int reg);
 static void pch_gbe_mdio_write(struct net_device *netdev, int addr, int reg,
                               int data);
+
+inline void pch_gbe_mac_load_mac_addr(struct pch_gbe_hw *hw)
+{
+       iowrite32(0x01, &hw->reg->MAC_ADDR_LOAD);
+}
+
 /**
  * pch_gbe_mac_read_mac_addr - Read MAC address
  * @hw:                    Pointer to the HW structure
@@ -519,7 +526,9 @@ static void pch_gbe_reset_task(struct work_struct *work)
        struct pch_gbe_adapter *adapter;
        adapter = container_of(work, struct pch_gbe_adapter, reset_task);
 
+       rtnl_lock();
        pch_gbe_reinit_locked(adapter);
+       rtnl_unlock();
 }
 
 /**
@@ -528,14 +537,8 @@ static void pch_gbe_reset_task(struct work_struct *work)
  */
 void pch_gbe_reinit_locked(struct pch_gbe_adapter *adapter)
 {
-       struct net_device *netdev = adapter->netdev;
-
-       rtnl_lock();
-       if (netif_running(netdev)) {
-               pch_gbe_down(adapter);
-               pch_gbe_up(adapter);
-       }
-       rtnl_unlock();
+       pch_gbe_down(adapter);
+       pch_gbe_up(adapter);
 }
 
 /**
@@ -1369,16 +1372,13 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,
        struct pch_gbe_buffer *buffer_info;
        struct pch_gbe_rx_desc *rx_desc;
        u32 length;
-       unsigned char tmp_packet[ETH_HLEN];
        unsigned int i;
        unsigned int cleaned_count = 0;
        bool cleaned = false;
-       struct sk_buff *skb;
+       struct sk_buff *skb, *new_skb;
        u8 dma_status;
        u16 gbec_status;
        u32 tcp_ip_status;
-       u8 skb_copy_flag = 0;
-       u8 skb_padding_flag = 0;
 
        i = rx_ring->next_to_clean;
 
@@ -1422,55 +1422,70 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,
                        pr_err("Receive CRC Error\n");
                } else {
                        /* get receive length */
-                       /* length convert[-3], padding[-2] */
-                       length = (rx_desc->rx_words_eob) - 3 - 2;
+                       /* length convert[-3] */
+                       length = (rx_desc->rx_words_eob) - 3;
 
                        /* Decide the data conversion method */
                        if (!adapter->rx_csum) {
                                /* [Header:14][payload] */
-                               skb_padding_flag = 0;
-                               skb_copy_flag = 1;
+                               if (NET_IP_ALIGN) {
+                                       /* Because alignment differs,
+                                        * the new_skb is newly allocated,
+                                        * and data is copied to new_skb.*/
+                                       new_skb = netdev_alloc_skb(netdev,
+                                                        length + NET_IP_ALIGN);
+                                       if (!new_skb) {
+                                               /* dorrop error */
+                                               pr_err("New skb allocation "
+                                                       "Error\n");
+                                               goto dorrop;
+                                       }
+                                       skb_reserve(new_skb, NET_IP_ALIGN);
+                                       memcpy(new_skb->data, skb->data,
+                                              length);
+                                       skb = new_skb;
+                               } else {
+                                       /* DMA buffer is used as SKB as it is.*/
+                                       buffer_info->skb = NULL;
+                               }
                        } else {
                                /* [Header:14][padding:2][payload] */
-                               skb_padding_flag = 1;
-                               if (length < copybreak)
-                                       skb_copy_flag = 1;
-                               else
-                                       skb_copy_flag = 0;
-                       }
-
-                       /* Data conversion */
-                       if (skb_copy_flag) {    /* recycle  skb */
-                               struct sk_buff *new_skb;
-                               new_skb =
-                                   netdev_alloc_skb(netdev,
-                                                    length + NET_IP_ALIGN);
-                               if (new_skb) {
-                                       if (!skb_padding_flag) {
-                                               skb_reserve(new_skb,
-                                                               NET_IP_ALIGN);
+                               /* The length includes padding length */
+                               length = length - PCH_GBE_DMA_PADDING;
+                               if ((length < copybreak) ||
+                                   (NET_IP_ALIGN != PCH_GBE_DMA_PADDING)) {
+                                       /* Because alignment differs,
+                                        * the new_skb is newly allocated,
+                                        * and data is copied to new_skb.
+                                        * Padding data is deleted
+                                        * at the time of a copy.*/
+                                       new_skb = netdev_alloc_skb(netdev,
+                                                        length + NET_IP_ALIGN);
+                                       if (!new_skb) {
+                                               /* dorrop error */
+                                               pr_err("New skb allocation "
+                                                       "Error\n");
+                                               goto dorrop;
                                        }
+                                       skb_reserve(new_skb, NET_IP_ALIGN);
                                        memcpy(new_skb->data, skb->data,
-                                               length);
-                                       /* save the skb
-                                        * in buffer_info as good */
+                                              ETH_HLEN);
+                                       memcpy(&new_skb->data[ETH_HLEN],
+                                              &skb->data[ETH_HLEN +
+                                              PCH_GBE_DMA_PADDING],
+                                              length - ETH_HLEN);
                                        skb = new_skb;
-                               } else if (!skb_padding_flag) {
-                                       /* dorrop error */
-                                       pr_err("New skb allocation Error\n");
-                                       goto dorrop;
+                               } else {
+                                       /* Padding data is deleted
+                                        * by moving header data.*/
+                                       memmove(&skb->data[PCH_GBE_DMA_PADDING],
+                                               &skb->data[0], ETH_HLEN);
+                                       skb_reserve(skb, NET_IP_ALIGN);
+                                       buffer_info->skb = NULL;
                                }
-                       } else {
-                               buffer_info->skb = NULL;
                        }
-                       if (skb_padding_flag) {
-                               memcpy(&tmp_packet[0], &skb->data[0], ETH_HLEN);
-                               memcpy(&skb->data[NET_IP_ALIGN], &tmp_packet[0],
-                                       ETH_HLEN);
-                               skb_reserve(skb, NET_IP_ALIGN);
-
-                       }
-
+                       /* The length includes FCS length */
+                       length = length - ETH_FCS_LEN;
                        /* update status of driver */
                        adapter->stats.rx_bytes += length;
                        adapter->stats.rx_packets++;
@@ -2247,7 +2262,7 @@ static void pch_gbe_remove(struct pci_dev *pdev)
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct pch_gbe_adapter *adapter = netdev_priv(netdev);
 
-       flush_scheduled_work();
+       cancel_work_sync(&adapter->reset_task);
        unregister_netdev(netdev);
 
        pch_gbe_hal_phy_hw_reset(&adapter->hw);
@@ -2322,6 +2337,7 @@ static int pch_gbe_probe(struct pci_dev *pdev,
        netdev->features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_GRO;
        pch_gbe_set_ethtool_ops(netdev);
 
+       pch_gbe_mac_load_mac_addr(&adapter->hw);
        pch_gbe_mac_reset_hw(&adapter->hw);
 
        /* setup the private structure */
index 1f42f6a..d3cb772 100644 (file)
@@ -1488,12 +1488,10 @@ static void ei_rx_overrun(struct net_device *dev)
     
        /* 
         * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total.
-        * Early datasheets said to poll the reset bit, but now they say that
-        * it "is not a reliable indicator and subsequently should be ignored."
-        * We wait at least 10ms.
+        * We wait at least 2ms.
         */
 
-       mdelay(10);
+       mdelay(2);
 
        /*
         * Reset RBCR[01] back to zero as per magic incantation.
index 9226cda..530ab5a 100644 (file)
@@ -691,6 +691,7 @@ static struct pcmcia_device_id fmvj18x_ids[] = {
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0e0a),
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0e01),
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0a05),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0b05),
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x1101),
        PCMCIA_DEVICE_NULL,
 };
index 27e6f6d..e3ebd90 100644 (file)
@@ -49,8 +49,8 @@
 #include <asm/processor.h>
 
 #define DRV_NAME       "r6040"
-#define DRV_VERSION    "0.26"
-#define DRV_RELDATE    "30May2010"
+#define DRV_VERSION    "0.27"
+#define DRV_RELDATE    "23Feb2011"
 
 /* PHY CHIP Address */
 #define PHY1_ADDR      1       /* For MAC1 */
@@ -69,6 +69,8 @@
 
 /* MAC registers */
 #define MCR0           0x00    /* Control register 0 */
+#define  MCR0_PROMISC  0x0020  /* Promiscuous mode */
+#define  MCR0_HASH_EN  0x0100  /* Enable multicast hash table function */
 #define MCR1           0x04    /* Control register 1 */
 #define  MAC_RST       0x0001  /* Reset the MAC */
 #define MBCR           0x08    /* Bus control */
@@ -851,77 +853,92 @@ static void r6040_multicast_list(struct net_device *dev)
 {
        struct r6040_private *lp = netdev_priv(dev);
        void __iomem *ioaddr = lp->base;
-       u16 *adrp;
-       u16 reg;
        unsigned long flags;
        struct netdev_hw_addr *ha;
        int i;
+       u16 *adrp;
+       u16 hash_table[4] = { 0 };
+
+       spin_lock_irqsave(&lp->lock, flags);
 
-       /* MAC Address */
+       /* Keep our MAC Address */
        adrp = (u16 *)dev->dev_addr;
        iowrite16(adrp[0], ioaddr + MID_0L);
        iowrite16(adrp[1], ioaddr + MID_0M);
        iowrite16(adrp[2], ioaddr + MID_0H);
 
-       /* Promiscous Mode */
-       spin_lock_irqsave(&lp->lock, flags);
-
        /* Clear AMCP & PROM bits */
-       reg = ioread16(ioaddr) & ~0x0120;
-       if (dev->flags & IFF_PROMISC) {
-               reg |= 0x0020;
-               lp->mcr0 |= 0x0020;
-       }
-       /* Too many multicast addresses
-        * accept all traffic */
-       else if ((netdev_mc_count(dev) > MCAST_MAX) ||
-                (dev->flags & IFF_ALLMULTI))
-               reg |= 0x0020;
+       lp->mcr0 = ioread16(ioaddr + MCR0) & ~(MCR0_PROMISC | MCR0_HASH_EN);
 
-       iowrite16(reg, ioaddr);
-       spin_unlock_irqrestore(&lp->lock, flags);
+       /* Promiscuous mode */
+       if (dev->flags & IFF_PROMISC)
+               lp->mcr0 |= MCR0_PROMISC;
 
-       /* Build the hash table */
-       if (netdev_mc_count(dev) > MCAST_MAX) {
-               u16 hash_table[4];
-               u32 crc;
+       /* Enable multicast hash table function to
+        * receive all multicast packets. */
+       else if (dev->flags & IFF_ALLMULTI) {
+               lp->mcr0 |= MCR0_HASH_EN;
 
-               for (i = 0; i < 4; i++)
-                       hash_table[i] = 0;
+               for (i = 0; i < MCAST_MAX ; i++) {
+                       iowrite16(0, ioaddr + MID_1L + 8 * i);
+                       iowrite16(0, ioaddr + MID_1M + 8 * i);
+                       iowrite16(0, ioaddr + MID_1H + 8 * i);
+               }
 
+               for (i = 0; i < 4; i++)
+                       hash_table[i] = 0xffff;
+       }
+       /* Use internal multicast address registers if the number of
+        * multicast addresses is not greater than MCAST_MAX. */
+       else if (netdev_mc_count(dev) <= MCAST_MAX) {
+               i = 0;
                netdev_for_each_mc_addr(ha, dev) {
-                       char *addrs = ha->addr;
+                       u16 *adrp = (u16 *) ha->addr;
+                       iowrite16(adrp[0], ioaddr + MID_1L + 8 * i);
+                       iowrite16(adrp[1], ioaddr + MID_1M + 8 * i);
+                       iowrite16(adrp[2], ioaddr + MID_1H + 8 * i);
+                       i++;
+               }
+               while (i < MCAST_MAX) {
+                       iowrite16(0, ioaddr + MID_1L + 8 * i);
+                       iowrite16(0, ioaddr + MID_1M + 8 * i);
+                       iowrite16(0, ioaddr + MID_1H + 8 * i);
+                       i++;
+               }
+       }
+       /* Otherwise, Enable multicast hash table function. */
+       else {
+               u32 crc;
 
-                       if (!(*addrs & 1))
-                               continue;
+               lp->mcr0 |= MCR0_HASH_EN;
+
+               for (i = 0; i < MCAST_MAX ; i++) {
+                       iowrite16(0, ioaddr + MID_1L + 8 * i);
+                       iowrite16(0, ioaddr + MID_1M + 8 * i);
+                       iowrite16(0, ioaddr + MID_1H + 8 * i);
+               }
 
-                       crc = ether_crc_le(6, addrs);
+               /* Build multicast hash table */
+               netdev_for_each_mc_addr(ha, dev) {
+                       u8 *addrs = ha->addr;
+
+                       crc = ether_crc(ETH_ALEN, addrs);
                        crc >>= 26;
-                       hash_table[crc >> 4] |= 1 << (15 - (crc & 0xf));
+                       hash_table[crc >> 4] |= 1 << (crc & 0xf);
                }
-               /* Fill the MAC hash tables with their values */
+       }
+
+       iowrite16(lp->mcr0, ioaddr + MCR0);
+
+       /* Fill the MAC hash tables with their values */
+       if (lp->mcr0 && MCR0_HASH_EN) {
                iowrite16(hash_table[0], ioaddr + MAR0);
                iowrite16(hash_table[1], ioaddr + MAR1);
                iowrite16(hash_table[2], ioaddr + MAR2);
                iowrite16(hash_table[3], ioaddr + MAR3);
        }
-       /* Multicast Address 1~4 case */
-       i = 0;
-       netdev_for_each_mc_addr(ha, dev) {
-               if (i >= MCAST_MAX)
-                       break;
-               adrp = (u16 *) ha->addr;
-               iowrite16(adrp[0], ioaddr + MID_1L + 8 * i);
-               iowrite16(adrp[1], ioaddr + MID_1M + 8 * i);
-               iowrite16(adrp[2], ioaddr + MID_1H + 8 * i);
-               i++;
-       }
-       while (i < MCAST_MAX) {
-               iowrite16(0xffff, ioaddr + MID_1L + 8 * i);
-               iowrite16(0xffff, ioaddr + MID_1M + 8 * i);
-               iowrite16(0xffff, ioaddr + MID_1H + 8 * i);
-               i++;
-       }
+
+       spin_unlock_irqrestore(&lp->lock, flags);
 }
 
 static void netdev_get_drvinfo(struct net_device *dev,
index bde7d61..7ffdb80 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/pm_runtime.h>
 #include <linux/firmware.h>
+#include <linux/pci-aspm.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -617,8 +618,9 @@ static void ocp_write(struct rtl8169_private *tp, u8 mask, u16 reg, u32 data)
        }
 }
 
-static void rtl8168_oob_notify(void __iomem *ioaddr, u8 cmd)
+static void rtl8168_oob_notify(struct rtl8169_private *tp, u8 cmd)
 {
+       void __iomem *ioaddr = tp->mmio_addr;
        int i;
 
        RTL_W8(ERIDR, cmd);
@@ -630,7 +632,7 @@ static void rtl8168_oob_notify(void __iomem *ioaddr, u8 cmd)
                        break;
        }
 
-       ocp_write(ioaddr, 0x1, 0x30, 0x00000001);
+       ocp_write(tp, 0x1, 0x30, 0x00000001);
 }
 
 #define OOB_CMD_RESET          0x00
@@ -973,7 +975,8 @@ static void __rtl8169_check_link_status(struct net_device *dev,
                if (pm)
                        pm_request_resume(&tp->pci_dev->dev);
                netif_carrier_on(dev);
-               netif_info(tp, ifup, dev, "link up\n");
+               if (net_ratelimit())
+                       netif_info(tp, ifup, dev, "link up\n");
        } else {
                netif_carrier_off(dev);
                netif_info(tp, ifdown, dev, "link down\n");
@@ -2867,8 +2870,11 @@ static void r8168_pll_power_down(struct rtl8169_private *tp)
 {
        void __iomem *ioaddr = tp->mmio_addr;
 
-       if (tp->mac_version == RTL_GIGA_MAC_VER_27)
+       if (((tp->mac_version == RTL_GIGA_MAC_VER_27) ||
+            (tp->mac_version == RTL_GIGA_MAC_VER_28)) &&
+           (ocp_read(tp, 0x0f, 0x0010) & 0x00008000)) {
                return;
+       }
 
        if (((tp->mac_version == RTL_GIGA_MAC_VER_23) ||
             (tp->mac_version == RTL_GIGA_MAC_VER_24)) &&
@@ -2890,6 +2896,8 @@ static void r8168_pll_power_down(struct rtl8169_private *tp)
        switch (tp->mac_version) {
        case RTL_GIGA_MAC_VER_25:
        case RTL_GIGA_MAC_VER_26:
+       case RTL_GIGA_MAC_VER_27:
+       case RTL_GIGA_MAC_VER_28:
                RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80);
                break;
        }
@@ -2899,12 +2907,17 @@ static void r8168_pll_power_up(struct rtl8169_private *tp)
 {
        void __iomem *ioaddr = tp->mmio_addr;
 
-       if (tp->mac_version == RTL_GIGA_MAC_VER_27)
+       if (((tp->mac_version == RTL_GIGA_MAC_VER_27) ||
+            (tp->mac_version == RTL_GIGA_MAC_VER_28)) &&
+           (ocp_read(tp, 0x0f, 0x0010) & 0x00008000)) {
                return;
+       }
 
        switch (tp->mac_version) {
        case RTL_GIGA_MAC_VER_25:
        case RTL_GIGA_MAC_VER_26:
+       case RTL_GIGA_MAC_VER_27:
+       case RTL_GIGA_MAC_VER_28:
                RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
                break;
        }
@@ -3008,6 +3021,11 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        mii->reg_num_mask = 0x1f;
        mii->supports_gmii = !!(cfg->features & RTL_FEATURE_GMII);
 
+       /* disable ASPM completely as that cause random device stop working
+        * problems as well as full system hangs for some PCIe devices users */
+       pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
+                                    PCIE_LINK_STATE_CLKPM);
+
        /* enable device (incl. PCI PM wakeup and hotplug setup) */
        rc = pci_enable_device(pdev);
        if (rc < 0) {
@@ -3041,7 +3059,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_out_mwi_2;
        }
 
-       tp->cp_cmd = PCIMulRW | RxChkSum;
+       tp->cp_cmd = RxChkSum;
 
        if ((sizeof(dma_addr_t) > 4) &&
            !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && use_dac) {
@@ -3189,6 +3207,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (pci_dev_run_wake(pdev))
                pm_runtime_put_noidle(&pdev->dev);
 
+       netif_carrier_off(dev);
+
 out:
        return rc;
 
@@ -3315,7 +3335,8 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp)
        /* Disable interrupts */
        rtl8169_irq_mask_and_ack(ioaddr);
 
-       if (tp->mac_version == RTL_GIGA_MAC_VER_28) {
+       if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
+           tp->mac_version == RTL_GIGA_MAC_VER_28) {
                while (RTL_R8(TxPoll) & NPQ)
                        udelay(20);
 
@@ -3757,7 +3778,8 @@ static void rtl_hw_start_8168(struct net_device *dev)
        RTL_W16(IntrMitigate, 0x5151);
 
        /* Work around for RxFIFO overflow. */
-       if (tp->mac_version == RTL_GIGA_MAC_VER_11) {
+       if (tp->mac_version == RTL_GIGA_MAC_VER_11 ||
+           tp->mac_version == RTL_GIGA_MAC_VER_22) {
                tp->intr_event |= RxFIFOOver | PCSTimeout;
                tp->intr_event &= ~RxOverflow;
        }
@@ -3843,8 +3865,7 @@ static void rtl_hw_start_8168(struct net_device *dev)
        Cxpl_dbg_sel | \
        ASF | \
        PktCntrDisable | \
-       PCIDAC | \
-       PCIMulRW)
+       Mac_dbgo_sel)
 
 static void rtl_hw_start_8102e_1(void __iomem *ioaddr, struct pci_dev *pdev)
 {
@@ -3874,8 +3895,6 @@ static void rtl_hw_start_8102e_1(void __iomem *ioaddr, struct pci_dev *pdev)
        if ((cfg1 & LEDS0) && (cfg1 & LEDS1))
                RTL_W8(Config1, cfg1 & ~LEDS0);
 
-       RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK);
-
        rtl_ephy_init(ioaddr, e_info_8102e_1, ARRAY_SIZE(e_info_8102e_1));
 }
 
@@ -3887,8 +3906,6 @@ static void rtl_hw_start_8102e_2(void __iomem *ioaddr, struct pci_dev *pdev)
 
        RTL_W8(Config1, MEMMAP | IOMAP | VPD | PMEnable);
        RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
-
-       RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK);
 }
 
 static void rtl_hw_start_8102e_3(void __iomem *ioaddr, struct pci_dev *pdev)
@@ -3914,6 +3931,8 @@ static void rtl_hw_start_8101(struct net_device *dev)
                }
        }
 
+       RTL_W8(Cfg9346, Cfg9346_Unlock);
+
        switch (tp->mac_version) {
        case RTL_GIGA_MAC_VER_07:
                rtl_hw_start_8102e_1(ioaddr, pdev);
@@ -3928,14 +3947,13 @@ static void rtl_hw_start_8101(struct net_device *dev)
                break;
        }
 
-       RTL_W8(Cfg9346, Cfg9346_Unlock);
+       RTL_W8(Cfg9346, Cfg9346_Lock);
 
        RTL_W8(MaxTxPacketSize, TxPacketMax);
 
        rtl_set_rx_max_size(ioaddr, rx_buf_sz);
 
-       tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
-
+       tp->cp_cmd &= ~R810X_CPCMD_QUIRK_MASK;
        RTL_W16(CPlusCmd, tp->cp_cmd);
 
        RTL_W16(IntrMitigate, 0x0000);
@@ -3945,14 +3963,10 @@ static void rtl_hw_start_8101(struct net_device *dev)
        RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
        rtl_set_rx_tx_config_registers(tp);
 
-       RTL_W8(Cfg9346, Cfg9346_Lock);
-
        RTL_R8(IntrMask);
 
        rtl_set_rx_mode(dev);
 
-       RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
-
        RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000);
 
        RTL_W16(IntrMask, tp->intr_event);
@@ -4639,12 +4653,33 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
                        break;
                }
 
-               /* Work around for rx fifo overflow */
-               if (unlikely(status & RxFIFOOver) &&
-               (tp->mac_version == RTL_GIGA_MAC_VER_11)) {
-                       netif_stop_queue(dev);
-                       rtl8169_tx_timeout(dev);
-                       break;
+               if (unlikely(status & RxFIFOOver)) {
+                       switch (tp->mac_version) {
+                       /* Work around for rx fifo overflow */
+                       case RTL_GIGA_MAC_VER_11:
+                       case RTL_GIGA_MAC_VER_22:
+                       case RTL_GIGA_MAC_VER_26:
+                               netif_stop_queue(dev);
+                               rtl8169_tx_timeout(dev);
+                               goto done;
+                       /* Testers needed. */
+                       case RTL_GIGA_MAC_VER_17:
+                       case RTL_GIGA_MAC_VER_19:
+                       case RTL_GIGA_MAC_VER_20:
+                       case RTL_GIGA_MAC_VER_21:
+                       case RTL_GIGA_MAC_VER_23:
+                       case RTL_GIGA_MAC_VER_24:
+                       case RTL_GIGA_MAC_VER_27:
+                       case RTL_GIGA_MAC_VER_28:
+                       /* Experimental science. Pktgen proof. */
+                       case RTL_GIGA_MAC_VER_12:
+                       case RTL_GIGA_MAC_VER_25:
+                               if (status == RxFIFOOver)
+                                       goto done;
+                               break;
+                       default:
+                               break;
+                       }
                }
 
                if (unlikely(status & SYSErr)) {
@@ -4680,7 +4715,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
                        (status & RxFIFOOver) ? (status | RxOverflow) : status);
                status = RTL_R16(IntrStatus);
        }
-
+done:
        return IRQ_RETVAL(handled);
 }
 
index 0e8bb19..ca886d9 100644 (file)
@@ -569,9 +569,14 @@ static void efx_ethtool_self_test(struct net_device *net_dev,
                                  struct ethtool_test *test, u64 *data)
 {
        struct efx_nic *efx = netdev_priv(net_dev);
-       struct efx_self_tests efx_tests;
+       struct efx_self_tests *efx_tests;
        int already_up;
-       int rc;
+       int rc = -ENOMEM;
+
+       efx_tests = kzalloc(sizeof(*efx_tests), GFP_KERNEL);
+       if (!efx_tests)
+               goto fail;
+
 
        ASSERT_RTNL();
        if (efx->state != STATE_RUNNING) {
@@ -589,13 +594,11 @@ static void efx_ethtool_self_test(struct net_device *net_dev,
                if (rc) {
                        netif_err(efx, drv, efx->net_dev,
                                  "failed opening device.\n");
-                       goto fail2;
+                       goto fail1;
                }
        }
 
-       memset(&efx_tests, 0, sizeof(efx_tests));
-
-       rc = efx_selftest(efx, &efx_tests, test->flags);
+       rc = efx_selftest(efx, efx_tests, test->flags);
 
        if (!already_up)
                dev_close(efx->net_dev);
@@ -604,10 +607,11 @@ static void efx_ethtool_self_test(struct net_device *net_dev,
                   rc == 0 ? "passed" : "failed",
                   (test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on");
 
- fail2:
- fail1:
+fail1:
        /* Fill ethtool results structures */
-       efx_ethtool_fill_self_tests(efx, &efx_tests, NULL, data);
+       efx_ethtool_fill_self_tests(efx, efx_tests, NULL, data);
+       kfree(efx_tests);
+fail:
        if (rc)
                test->flags |= ETH_TEST_FL_FAILED;
 }
index 5976d1d..640e368 100644 (file)
@@ -1777,6 +1777,7 @@ static int sis900_rx(struct net_device *net_dev)
                                              "cur_rx:%4.4d, dirty_rx:%4.4d\n",
                                              net_dev->name, sis_priv->cur_rx,
                                              sis_priv->dirty_rx);
+                               dev_kfree_skb(skb);
                                break;
                        }
 
index 42daf98..35b28f4 100644 (file)
@@ -3856,9 +3856,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
        memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port*8, ETH_ALEN);
        memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
-       /* device is off until link detection */
-       netif_carrier_off(dev);
-
        return dev;
 }
 
index 64bfdae..d70bde9 100644 (file)
@@ -1178,6 +1178,11 @@ static int smsc911x_open(struct net_device *dev)
        smsc911x_reg_write(pdata, HW_CFG, 0x00050000);
        smsc911x_reg_write(pdata, AFC_CFG, 0x006E3740);
 
+       /* Increase the legal frame size of VLAN tagged frames to 1522 bytes */
+       spin_lock_irq(&pdata->mac_lock);
+       smsc911x_mac_write(pdata, VLAN1, ETH_P_8021Q);
+       spin_unlock_irq(&pdata->mac_lock);
+
        /* Make sure EEPROM has finished loading before setting GPIO_CFG */
        timeout = 50;
        while ((smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_) &&
index 34a0af3..0e5f031 100644 (file)
@@ -1560,8 +1560,10 @@ static int stmmac_mac_device_setup(struct net_device *dev)
 
        priv->hw = device;
 
-       if (device_can_wakeup(priv->device))
+       if (device_can_wakeup(priv->device)) {
                priv->wolopts = WAKE_MAGIC; /* Magic Frame as default */
+               enable_irq_wake(dev->irq);
+       }
 
        return 0;
 }
index 7841a8f..06c0e50 100644 (file)
 #define BAR_0  0
 #define BAR_2  2
 
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-#define TG3_VLAN_TAG_USED 1
-#else
-#define TG3_VLAN_TAG_USED 0
-#endif
-
 #include "tg3.h"
 
 #define DRV_MODULE_NAME                "tg3"
                                 TG3_TX_RING_SIZE)
 #define NEXT_TX(N)             (((N) + 1) & (TG3_TX_RING_SIZE - 1))
 
-#define TG3_RX_DMA_ALIGN               16
-#define TG3_RX_HEADROOM                        ALIGN(VLAN_HLEN, TG3_RX_DMA_ALIGN)
-
 #define TG3_DMA_BYTE_ENAB              64
 
 #define TG3_RX_STD_DMA_SZ              1536
@@ -4722,8 +4713,6 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
                struct sk_buff *skb;
                dma_addr_t dma_addr;
                u32 opaque_key, desc_idx, *post_ptr;
-               bool hw_vlan __maybe_unused = false;
-               u16 vtag __maybe_unused = 0;
 
                desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK;
                opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK;
@@ -4782,12 +4771,12 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
                        tg3_recycle_rx(tnapi, tpr, opaque_key,
                                       desc_idx, *post_ptr);
 
-                       copy_skb = netdev_alloc_skb(tp->dev, len + VLAN_HLEN +
+                       copy_skb = netdev_alloc_skb(tp->dev, len +
                                                    TG3_RAW_IP_ALIGN);
                        if (copy_skb == NULL)
                                goto drop_it_no_recycle;
 
-                       skb_reserve(copy_skb, TG3_RAW_IP_ALIGN + VLAN_HLEN);
+                       skb_reserve(copy_skb, TG3_RAW_IP_ALIGN);
                        skb_put(copy_skb, len);
                        pci_dma_sync_single_for_cpu(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
                        skb_copy_from_linear_data(skb, copy_skb->data, len);
@@ -4814,30 +4803,11 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
                }
 
                if (desc->type_flags & RXD_FLAG_VLAN &&
-                   !(tp->rx_mode & RX_MODE_KEEP_VLAN_TAG)) {
-                       vtag = desc->err_vlan & RXD_VLAN_MASK;
-#if TG3_VLAN_TAG_USED
-                       if (tp->vlgrp)
-                               hw_vlan = true;
-                       else
-#endif
-                       {
-                               struct vlan_ethhdr *ve = (struct vlan_ethhdr *)
-                                                   __skb_push(skb, VLAN_HLEN);
-
-                               memmove(ve, skb->data + VLAN_HLEN,
-                                       ETH_ALEN * 2);
-                               ve->h_vlan_proto = htons(ETH_P_8021Q);
-                               ve->h_vlan_TCI = htons(vtag);
-                       }
-               }
+                   !(tp->rx_mode & RX_MODE_KEEP_VLAN_TAG))
+                       __vlan_hwaccel_put_tag(skb,
+                                              desc->err_vlan & RXD_VLAN_MASK);
 
-#if TG3_VLAN_TAG_USED
-               if (hw_vlan)
-                       vlan_gro_receive(&tnapi->napi, tp->vlgrp, vtag, skb);
-               else
-#endif
-                       napi_gro_receive(&tnapi->napi, skb);
+               napi_gro_receive(&tnapi->napi, skb);
 
                received++;
                budget--;
@@ -5740,11 +5710,9 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb,
                base_flags |= TXD_FLAG_TCPUDP_CSUM;
        }
 
-#if TG3_VLAN_TAG_USED
        if (vlan_tx_tag_present(skb))
                base_flags |= (TXD_FLAG_VLAN |
                               (vlan_tx_tag_get(skb) << 16));
-#endif
 
        len = skb_headlen(skb);
 
@@ -5986,11 +5954,10 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
                        }
                }
        }
-#if TG3_VLAN_TAG_USED
+
        if (vlan_tx_tag_present(skb))
                base_flags |= (TXD_FLAG_VLAN |
                               (vlan_tx_tag_get(skb) << 16));
-#endif
 
        if ((tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) &&
            !mss && skb->len > VLAN_ETH_FRAME_LEN)
@@ -9532,17 +9499,10 @@ static void __tg3_set_rx_mode(struct net_device *dev)
        rx_mode = tp->rx_mode & ~(RX_MODE_PROMISC |
                                  RX_MODE_KEEP_VLAN_TAG);
 
+#if !defined(CONFIG_VLAN_8021Q) && !defined(CONFIG_VLAN_8021Q_MODULE)
        /* When ASF is in use, we always keep the RX_MODE_KEEP_VLAN_TAG
         * flag clear.
         */
-#if TG3_VLAN_TAG_USED
-       if (!tp->vlgrp &&
-           !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
-               rx_mode |= RX_MODE_KEEP_VLAN_TAG;
-#else
-       /* By definition, VLAN is disabled always in this
-        * case.
-        */
        if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
                rx_mode |= RX_MODE_KEEP_VLAN_TAG;
 #endif
@@ -11198,7 +11158,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
                        break;                  /* We have no PHY */
 
-               if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
+               if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) ||
+                   ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
+                    !netif_running(dev)))
                        return -EAGAIN;
 
                spin_lock_bh(&tp->lock);
@@ -11214,7 +11176,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
                        break;                  /* We have no PHY */
 
-               if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
+               if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) ||
+                   ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
+                    !netif_running(dev)))
                        return -EAGAIN;
 
                spin_lock_bh(&tp->lock);
@@ -11230,31 +11194,6 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        return -EOPNOTSUPP;
 }
 
-#if TG3_VLAN_TAG_USED
-static void tg3_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
-{
-       struct tg3 *tp = netdev_priv(dev);
-
-       if (!netif_running(dev)) {
-               tp->vlgrp = grp;
-               return;
-       }
-
-       tg3_netif_stop(tp);
-
-       tg3_full_lock(tp, 0);
-
-       tp->vlgrp = grp;
-
-       /* Update RX_MODE_KEEP_VLAN_TAG bit in RX_MODE register. */
-       __tg3_set_rx_mode(dev);
-
-       tg3_netif_start(tp);
-
-       tg3_full_unlock(tp);
-}
-#endif
-
 static int tg3_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec)
 {
        struct tg3 *tp = netdev_priv(dev);
@@ -13066,9 +13005,7 @@ static struct pci_dev * __devinit tg3_find_peer(struct tg3 *);
 
 static void inline vlan_features_add(struct net_device *dev, unsigned long flags)
 {
-#if TG3_VLAN_TAG_USED
        dev->vlan_features |= flags;
-#endif
 }
 
 static inline u32 tg3_rx_ret_ring_size(struct tg3 *tp)
@@ -13861,11 +13798,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        else
                tp->tg3_flags &= ~TG3_FLAG_POLL_SERDES;
 
-       tp->rx_offset = NET_IP_ALIGN + TG3_RX_HEADROOM;
+       tp->rx_offset = NET_IP_ALIGN;
        tp->rx_copy_thresh = TG3_RX_COPY_THRESHOLD;
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
            (tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) {
-               tp->rx_offset -= NET_IP_ALIGN;
+               tp->rx_offset = 0;
 #ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
                tp->rx_copy_thresh = ~(u16)0;
 #endif
@@ -14629,9 +14566,6 @@ static const struct net_device_ops tg3_netdev_ops = {
        .ndo_do_ioctl           = tg3_ioctl,
        .ndo_tx_timeout         = tg3_tx_timeout,
        .ndo_change_mtu         = tg3_change_mtu,
-#if TG3_VLAN_TAG_USED
-       .ndo_vlan_rx_register   = tg3_vlan_rx_register,
-#endif
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = tg3_poll_controller,
 #endif
@@ -14648,9 +14582,6 @@ static const struct net_device_ops tg3_netdev_ops_dma_bug = {
        .ndo_do_ioctl           = tg3_ioctl,
        .ndo_tx_timeout         = tg3_tx_timeout,
        .ndo_change_mtu         = tg3_change_mtu,
-#if TG3_VLAN_TAG_USED
-       .ndo_vlan_rx_register   = tg3_vlan_rx_register,
-#endif
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = tg3_poll_controller,
 #endif
@@ -14700,9 +14631,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 
        SET_NETDEV_DEV(dev, &pdev->dev);
 
-#if TG3_VLAN_TAG_USED
        dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-#endif
 
        tp = netdev_priv(dev);
        tp->pdev = pdev;
index d62c8d9..f528243 100644 (file)
@@ -2808,9 +2808,6 @@ struct tg3 {
        u32                             rx_std_max_post;
        u32                             rx_offset;
        u32                             rx_pkt_map_sz;
-#if TG3_VLAN_TAG_USED
-       struct vlan_group               *vlgrp;
-#endif
 
 
        /* begin "everything else" cacheline(s) section */
index 04e8ce1..7113168 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * cdc_ncm.c
  *
- * Copyright (C) ST-Ericsson 2010
+ * Copyright (C) ST-Ericsson 2010-2011
  * Contact: Alexey Orishko <alexey.orishko@stericsson.com>
  * Original author: Hans Petter Selasky <hans.petter.selasky@stericsson.com>
  *
@@ -54,7 +54,7 @@
 #include <linux/usb/usbnet.h>
 #include <linux/usb/cdc.h>
 
-#define        DRIVER_VERSION                          "17-Jan-2011"
+#define        DRIVER_VERSION                          "7-Feb-2011"
 
 /* CDC NCM subclass 3.2.1 */
 #define USB_CDC_NCM_NDP16_LENGTH_MIN           0x10
@@ -77,6 +77,9 @@
  */
 #define        CDC_NCM_DPT_DATAGRAMS_MAX               32
 
+/* Maximum amount of IN datagrams in NTB */
+#define        CDC_NCM_DPT_DATAGRAMS_IN_MAX            0 /* unlimited */
+
 /* Restart the timer, if amount of datagrams is less than given value */
 #define        CDC_NCM_RESTART_TIMER_DATAGRAM_CNT      3
 
        (sizeof(struct usb_cdc_ncm_nth16) + sizeof(struct usb_cdc_ncm_ndp16) + \
        (CDC_NCM_DPT_DATAGRAMS_MAX + 1) * sizeof(struct usb_cdc_ncm_dpe16))
 
-struct connection_speed_change {
-       __le32  USBitRate; /* holds 3GPP downlink value, bits per second */
-       __le32  DSBitRate; /* holds 3GPP uplink value, bits per second */
-} __attribute__ ((packed));
-
 struct cdc_ncm_data {
        struct usb_cdc_ncm_nth16 nth16;
        struct usb_cdc_ncm_ndp16 ndp16;
@@ -198,10 +196,10 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx)
 {
        struct usb_cdc_notification req;
        u32 val;
-       __le16 max_datagram_size;
        u8 flags;
        u8 iface_no;
        int err;
+       u16 ntb_fmt_supported;
 
        iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber;
 
@@ -223,6 +221,9 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx)
        ctx->tx_remainder = le16_to_cpu(ctx->ncm_parm.wNdpOutPayloadRemainder);
        ctx->tx_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutDivisor);
        ctx->tx_ndp_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutAlignment);
+       /* devices prior to NCM Errata shall set this field to zero */
+       ctx->tx_max_datagrams = le16_to_cpu(ctx->ncm_parm.wNtbOutMaxDatagrams);
+       ntb_fmt_supported = le16_to_cpu(ctx->ncm_parm.bmNtbFormatsSupported);
 
        if (ctx->func_desc != NULL)
                flags = ctx->func_desc->bmNetworkCapabilities;
@@ -231,22 +232,58 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx)
 
        pr_debug("dwNtbInMaxSize=%u dwNtbOutMaxSize=%u "
                 "wNdpOutPayloadRemainder=%u wNdpOutDivisor=%u "
-                "wNdpOutAlignment=%u flags=0x%x\n",
+                "wNdpOutAlignment=%u wNtbOutMaxDatagrams=%u flags=0x%x\n",
                 ctx->rx_max, ctx->tx_max, ctx->tx_remainder, ctx->tx_modulus,
-                ctx->tx_ndp_modulus, flags);
+                ctx->tx_ndp_modulus, ctx->tx_max_datagrams, flags);
 
-       /* max count of tx datagrams without terminating NULL entry */
-       ctx->tx_max_datagrams = CDC_NCM_DPT_DATAGRAMS_MAX;
+       /* max count of tx datagrams */
+       if ((ctx->tx_max_datagrams == 0) ||
+                       (ctx->tx_max_datagrams > CDC_NCM_DPT_DATAGRAMS_MAX))
+               ctx->tx_max_datagrams = CDC_NCM_DPT_DATAGRAMS_MAX;
 
        /* verify maximum size of received NTB in bytes */
-       if ((ctx->rx_max <
-           (CDC_NCM_MIN_HDR_SIZE + CDC_NCM_MIN_DATAGRAM_SIZE)) ||
-           (ctx->rx_max > CDC_NCM_NTB_MAX_SIZE_RX)) {
+       if (ctx->rx_max < USB_CDC_NCM_NTB_MIN_IN_SIZE) {
+               pr_debug("Using min receive length=%d\n",
+                                               USB_CDC_NCM_NTB_MIN_IN_SIZE);
+               ctx->rx_max = USB_CDC_NCM_NTB_MIN_IN_SIZE;
+       }
+
+       if (ctx->rx_max > CDC_NCM_NTB_MAX_SIZE_RX) {
                pr_debug("Using default maximum receive length=%d\n",
                                                CDC_NCM_NTB_MAX_SIZE_RX);
                ctx->rx_max = CDC_NCM_NTB_MAX_SIZE_RX;
        }
 
+       /* inform device about NTB input size changes */
+       if (ctx->rx_max != le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize)) {
+               req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT |
+                                                       USB_RECIP_INTERFACE;
+               req.bNotificationType = USB_CDC_SET_NTB_INPUT_SIZE;
+               req.wValue = 0;
+               req.wIndex = cpu_to_le16(iface_no);
+
+               if (flags & USB_CDC_NCM_NCAP_NTB_INPUT_SIZE) {
+                       struct usb_cdc_ncm_ndp_input_size ndp_in_sz;
+
+                       req.wLength = 8;
+                       ndp_in_sz.dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
+                       ndp_in_sz.wNtbInMaxDatagrams =
+                                       cpu_to_le16(CDC_NCM_DPT_DATAGRAMS_MAX);
+                       ndp_in_sz.wReserved = 0;
+                       err = cdc_ncm_do_request(ctx, &req, &ndp_in_sz, 0, NULL,
+                                                                       1000);
+               } else {
+                       __le32 dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
+
+                       req.wLength = 4;
+                       err = cdc_ncm_do_request(ctx, &req, &dwNtbInMaxSize, 0,
+                                                               NULL, 1000);
+               }
+
+               if (err)
+                       pr_debug("Setting NTB Input Size failed\n");
+       }
+
        /* verify maximum size of transmitted NTB in bytes */
        if ((ctx->tx_max <
            (CDC_NCM_MIN_HDR_SIZE + CDC_NCM_MIN_DATAGRAM_SIZE)) ||
@@ -297,47 +334,84 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx)
        /* additional configuration */
 
        /* set CRC Mode */
-       req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE;
-       req.bNotificationType = USB_CDC_SET_CRC_MODE;
-       req.wValue = cpu_to_le16(USB_CDC_NCM_CRC_NOT_APPENDED);
-       req.wIndex = cpu_to_le16(iface_no);
-       req.wLength = 0;
-
-       err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000);
-       if (err)
-               pr_debug("Setting CRC mode off failed\n");
+       if (flags & USB_CDC_NCM_NCAP_CRC_MODE) {
+               req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT |
+                                                       USB_RECIP_INTERFACE;
+               req.bNotificationType = USB_CDC_SET_CRC_MODE;
+               req.wValue = cpu_to_le16(USB_CDC_NCM_CRC_NOT_APPENDED);
+               req.wIndex = cpu_to_le16(iface_no);
+               req.wLength = 0;
+
+               err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000);
+               if (err)
+                       pr_debug("Setting CRC mode off failed\n");
+       }
 
-       /* set NTB format */
-       req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE;
-       req.bNotificationType = USB_CDC_SET_NTB_FORMAT;
-       req.wValue = cpu_to_le16(USB_CDC_NCM_NTB16_FORMAT);
-       req.wIndex = cpu_to_le16(iface_no);
-       req.wLength = 0;
+       /* set NTB format, if both formats are supported */
+       if (ntb_fmt_supported & USB_CDC_NCM_NTH32_SIGN) {
+               req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT |
+                                                       USB_RECIP_INTERFACE;
+               req.bNotificationType = USB_CDC_SET_NTB_FORMAT;
+               req.wValue = cpu_to_le16(USB_CDC_NCM_NTB16_FORMAT);
+               req.wIndex = cpu_to_le16(iface_no);
+               req.wLength = 0;
+
+               err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000);
+               if (err)
+                       pr_debug("Setting NTB format to 16-bit failed\n");
+       }
 
-       err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000);
-       if (err)
-               pr_debug("Setting NTB format to 16-bit failed\n");
+       ctx->max_datagram_size = CDC_NCM_MIN_DATAGRAM_SIZE;
 
        /* set Max Datagram Size (MTU) */
-       req.bmRequestType = USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE;
-       req.bNotificationType = USB_CDC_GET_MAX_DATAGRAM_SIZE;
-       req.wValue = 0;
-       req.wIndex = cpu_to_le16(iface_no);
-       req.wLength = cpu_to_le16(2);
+       if (flags & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE) {
+               __le16 max_datagram_size;
+               u16 eth_max_sz = le16_to_cpu(ctx->ether_desc->wMaxSegmentSize);
+
+               req.bmRequestType = USB_TYPE_CLASS | USB_DIR_IN |
+                                                       USB_RECIP_INTERFACE;
+               req.bNotificationType = USB_CDC_GET_MAX_DATAGRAM_SIZE;
+               req.wValue = 0;
+               req.wIndex = cpu_to_le16(iface_no);
+               req.wLength = cpu_to_le16(2);
+
+               err = cdc_ncm_do_request(ctx, &req, &max_datagram_size, 0, NULL,
+                                                                       1000);
+               if (err) {
+                       pr_debug("GET_MAX_DATAGRAM_SIZE failed, use size=%u\n",
+                                               CDC_NCM_MIN_DATAGRAM_SIZE);
+               } else {
+                       ctx->max_datagram_size = le16_to_cpu(max_datagram_size);
+                       /* Check Eth descriptor value */
+                       if (eth_max_sz < CDC_NCM_MAX_DATAGRAM_SIZE) {
+                               if (ctx->max_datagram_size > eth_max_sz)
+                                       ctx->max_datagram_size = eth_max_sz;
+                       } else {
+                               if (ctx->max_datagram_size >
+                                               CDC_NCM_MAX_DATAGRAM_SIZE)
+                                       ctx->max_datagram_size =
+                                               CDC_NCM_MAX_DATAGRAM_SIZE;
+                       }
 
-       err = cdc_ncm_do_request(ctx, &req, &max_datagram_size, 0, NULL, 1000);
-       if (err) {
-               pr_debug(" GET_MAX_DATAGRAM_SIZE failed, using size=%u\n",
-                        CDC_NCM_MIN_DATAGRAM_SIZE);
-               /* use default */
-               ctx->max_datagram_size = CDC_NCM_MIN_DATAGRAM_SIZE;
-       } else {
-               ctx->max_datagram_size = le16_to_cpu(max_datagram_size);
+                       if (ctx->max_datagram_size < CDC_NCM_MIN_DATAGRAM_SIZE)
+                               ctx->max_datagram_size =
+                                       CDC_NCM_MIN_DATAGRAM_SIZE;
+
+                       /* if value changed, update device */
+                       req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT |
+                                                       USB_RECIP_INTERFACE;
+                       req.bNotificationType = USB_CDC_SET_MAX_DATAGRAM_SIZE;
+                       req.wValue = 0;
+                       req.wIndex = cpu_to_le16(iface_no);
+                       req.wLength = 2;
+                       max_datagram_size = cpu_to_le16(ctx->max_datagram_size);
+
+                       err = cdc_ncm_do_request(ctx, &req, &max_datagram_size,
+                                                               0, NULL, 1000);
+                       if (err)
+                               pr_debug("SET_MAX_DATAGRAM_SIZE failed\n");
+               }
 
-               if (ctx->max_datagram_size < CDC_NCM_MIN_DATAGRAM_SIZE)
-                       ctx->max_datagram_size = CDC_NCM_MIN_DATAGRAM_SIZE;
-               else if (ctx->max_datagram_size > CDC_NCM_MAX_DATAGRAM_SIZE)
-                       ctx->max_datagram_size = CDC_NCM_MAX_DATAGRAM_SIZE;
        }
 
        if (ctx->netdev->mtu != (ctx->max_datagram_size - ETH_HLEN))
@@ -466,19 +540,13 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
 
                        ctx->ether_desc =
                                        (const struct usb_cdc_ether_desc *)buf;
-
                        dev->hard_mtu =
                                le16_to_cpu(ctx->ether_desc->wMaxSegmentSize);
 
-                       if (dev->hard_mtu <
-                           (CDC_NCM_MIN_DATAGRAM_SIZE - ETH_HLEN))
-                               dev->hard_mtu =
-                                       CDC_NCM_MIN_DATAGRAM_SIZE - ETH_HLEN;
-
-                       else if (dev->hard_mtu >
-                                (CDC_NCM_MAX_DATAGRAM_SIZE - ETH_HLEN))
-                               dev->hard_mtu =
-                                       CDC_NCM_MAX_DATAGRAM_SIZE - ETH_HLEN;
+                       if (dev->hard_mtu < CDC_NCM_MIN_DATAGRAM_SIZE)
+                               dev->hard_mtu = CDC_NCM_MIN_DATAGRAM_SIZE;
+                       else if (dev->hard_mtu > CDC_NCM_MAX_DATAGRAM_SIZE)
+                               dev->hard_mtu = CDC_NCM_MAX_DATAGRAM_SIZE;
                        break;
 
                case USB_CDC_NCM_TYPE:
@@ -628,13 +696,13 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
        u32 offset;
        u32 last_offset;
        u16 n = 0;
-       u8 timeout = 0;
+       u8 ready2send = 0;
 
        /* if there is a remaining skb, it gets priority */
        if (skb != NULL)
                swap(skb, ctx->tx_rem_skb);
        else
-               timeout = 1;
+               ready2send = 1;
 
        /*
         * +----------------+
@@ -682,9 +750,10 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
 
        for (; n < ctx->tx_max_datagrams; n++) {
                /* check if end of transmit buffer is reached */
-               if (offset >= ctx->tx_max)
+               if (offset >= ctx->tx_max) {
+                       ready2send = 1;
                        break;
-
+               }
                /* compute maximum buffer size */
                rem = ctx->tx_max - offset;
 
@@ -711,9 +780,7 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
                                }
                                ctx->tx_rem_skb = skb;
                                skb = NULL;
-
-                               /* loop one more time */
-                               timeout = 1;
+                               ready2send = 1;
                        }
                        break;
                }
@@ -756,7 +823,7 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
                ctx->tx_curr_last_offset = last_offset;
                goto exit_no_skb;
 
-       } else if ((n < ctx->tx_max_datagrams) && (timeout == 0)) {
+       } else if ((n < ctx->tx_max_datagrams) && (ready2send == 0)) {
                /* wait for more frames */
                /* push variables */
                ctx->tx_curr_skb = skb_out;
@@ -813,7 +880,7 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
                                        cpu_to_le16(sizeof(ctx->tx_ncm.nth16));
        ctx->tx_ncm.nth16.wSequence = cpu_to_le16(ctx->tx_seq);
        ctx->tx_ncm.nth16.wBlockLength = cpu_to_le16(last_offset);
-       ctx->tx_ncm.nth16.wFpIndex = ALIGN(sizeof(struct usb_cdc_ncm_nth16),
+       ctx->tx_ncm.nth16.wNdpIndex = ALIGN(sizeof(struct usb_cdc_ncm_nth16),
                                                        ctx->tx_ndp_modulus);
 
        memcpy(skb_out->data, &(ctx->tx_ncm.nth16), sizeof(ctx->tx_ncm.nth16));
@@ -825,13 +892,13 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
        rem = sizeof(ctx->tx_ncm.ndp16) + ((ctx->tx_curr_frame_num + 1) *
                                        sizeof(struct usb_cdc_ncm_dpe16));
        ctx->tx_ncm.ndp16.wLength = cpu_to_le16(rem);
-       ctx->tx_ncm.ndp16.wNextFpIndex = 0; /* reserved */
+       ctx->tx_ncm.ndp16.wNextNdpIndex = 0; /* reserved */
 
-       memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wFpIndex,
+       memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wNdpIndex,
                                                &(ctx->tx_ncm.ndp16),
                                                sizeof(ctx->tx_ncm.ndp16));
 
-       memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wFpIndex +
+       memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wNdpIndex +
                                        sizeof(ctx->tx_ncm.ndp16),
                                        &(ctx->tx_ncm.dpe16),
                                        (ctx->tx_curr_frame_num + 1) *
@@ -961,7 +1028,7 @@ static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
                goto error;
        }
 
-       temp = le16_to_cpu(ctx->rx_ncm.nth16.wFpIndex);
+       temp = le16_to_cpu(ctx->rx_ncm.nth16.wNdpIndex);
        if ((temp + sizeof(ctx->rx_ncm.ndp16)) > actlen) {
                pr_debug("invalid DPT16 index\n");
                goto error;
@@ -1048,10 +1115,10 @@ error:
 
 static void
 cdc_ncm_speed_change(struct cdc_ncm_ctx *ctx,
-                    struct connection_speed_change *data)
+                    struct usb_cdc_speed_change *data)
 {
-       uint32_t rx_speed = le32_to_cpu(data->USBitRate);
-       uint32_t tx_speed = le32_to_cpu(data->DSBitRate);
+       uint32_t rx_speed = le32_to_cpu(data->DLBitRRate);
+       uint32_t tx_speed = le32_to_cpu(data->ULBitRate);
 
        /*
         * Currently the USB-NET API does not support reporting the actual
@@ -1092,7 +1159,7 @@ static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)
        /* test for split data in 8-byte chunks */
        if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) {
                cdc_ncm_speed_change(ctx,
-                     (struct connection_speed_change *)urb->transfer_buffer);
+                     (struct usb_cdc_speed_change *)urb->transfer_buffer);
                return;
        }
 
@@ -1120,12 +1187,12 @@ static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)
                break;
 
        case USB_CDC_NOTIFY_SPEED_CHANGE:
-               if (urb->actual_length <
-                   (sizeof(*event) + sizeof(struct connection_speed_change)))
+               if (urb->actual_length < (sizeof(*event) +
+                                       sizeof(struct usb_cdc_speed_change)))
                        set_bit(EVENT_STS_SPLIT, &dev->flags);
                else
                        cdc_ncm_speed_change(ctx,
-                               (struct connection_speed_change *) &event[1]);
+                               (struct usb_cdc_speed_change *) &event[1]);
                break;
 
        default:
index 02b622e..5002f5b 100644 (file)
@@ -650,6 +650,10 @@ static const struct usb_device_id products[] = {
        USB_DEVICE(0x0fe6, 0x8101),     /* DM9601 USB to Fast Ethernet Adapter */
        .driver_info = (unsigned long)&dm9601_info,
         },
+       {
+        USB_DEVICE(0x0fe6, 0x9700),    /* DM9601 USB to Fast Ethernet Adapter */
+        .driver_info = (unsigned long)&dm9601_info,
+        },
        {
         USB_DEVICE(0x0a46, 0x9000),    /* DM9000E */
         .driver_info = (unsigned long)&dm9601_info,
index bed8fce..6d83812 100644 (file)
@@ -2628,15 +2628,15 @@ exit:
 
 static void hso_free_tiomget(struct hso_serial *serial)
 {
-       struct hso_tiocmget *tiocmget = serial->tiocmget;
+       struct hso_tiocmget *tiocmget;
+       if (!serial)
+               return;
+       tiocmget = serial->tiocmget;
        if (tiocmget) {
-               if (tiocmget->urb) {
-                       usb_free_urb(tiocmget->urb);
-                       tiocmget->urb = NULL;
-               }
+               usb_free_urb(tiocmget->urb);
+               tiocmget->urb = NULL;
                serial->tiocmget = NULL;
                kfree(tiocmget);
-
        }
 }
 
index 5e98643..7dc8497 100644 (file)
@@ -406,6 +406,7 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth,
 
        if (fw->size > KAWETH_FIRMWARE_BUF_SIZE) {
                err("Firmware too big: %zu", fw->size);
+               release_firmware(fw);
                return -ENOSPC;
        }
        data_len = fw->size;
index ed9a416..95c41d5 100644 (file)
@@ -931,8 +931,10 @@ fail_halt:
                if (urb != NULL) {
                        clear_bit (EVENT_RX_MEMORY, &dev->flags);
                        status = usb_autopm_get_interface(dev->intf);
-                       if (status < 0)
+                       if (status < 0) {
+                               usb_free_urb(urb);
                                goto fail_lowmem;
+                       }
                        if (rx_submit (dev, urb, GFP_KERNEL) == -ENOLINK)
                                resched = 0;
                        usb_autopm_put_interface(dev->intf);
index 90a23e4..82dba5a 100644 (file)
@@ -446,6 +446,20 @@ static void skb_recv_done(struct virtqueue *rvq)
        }
 }
 
+static void virtnet_napi_enable(struct virtnet_info *vi)
+{
+       napi_enable(&vi->napi);
+
+       /* If all buffers were filled by other side before we napi_enabled, we
+        * won't get another interrupt, so process any outstanding packets
+        * now.  virtnet_poll wants re-enable the queue, so we disable here.
+        * We synchronize against interrupts via NAPI_STATE_SCHED */
+       if (napi_schedule_prep(&vi->napi)) {
+               virtqueue_disable_cb(vi->rvq);
+               __napi_schedule(&vi->napi);
+       }
+}
+
 static void refill_work(struct work_struct *work)
 {
        struct virtnet_info *vi;
@@ -454,7 +468,7 @@ static void refill_work(struct work_struct *work)
        vi = container_of(work, struct virtnet_info, refill.work);
        napi_disable(&vi->napi);
        still_empty = !try_fill_recv(vi, GFP_KERNEL);
-       napi_enable(&vi->napi);
+       virtnet_napi_enable(vi);
 
        /* In theory, this can happen: if we don't get any buffers in
         * we will *never* try to fill again. */
@@ -638,16 +652,7 @@ static int virtnet_open(struct net_device *dev)
 {
        struct virtnet_info *vi = netdev_priv(dev);
 
-       napi_enable(&vi->napi);
-
-       /* If all buffers were filled by other side before we napi_enabled, we
-        * won't get another interrupt, so process any outstanding packets
-        * now.  virtnet_poll wants re-enable the queue, so we disable here.
-        * We synchronize against interrupts via NAPI_STATE_SCHED */
-       if (napi_schedule_prep(&vi->napi)) {
-               virtqueue_disable_cb(vi->rvq);
-               __napi_schedule(&vi->napi);
-       }
+       virtnet_napi_enable(vi);
        return 0;
 }
 
index 01c05f5..228d4f7 100644 (file)
@@ -3690,7 +3690,7 @@ __vxge_hw_vpath_rts_table_get(struct __vxge_hw_vpath_handle *vp,
        if (status != VXGE_HW_OK)
                goto exit;
 
-       if ((rts_table != VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA) ||
+       if ((rts_table != VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA) &&
            (rts_table !=
             VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT))
                *data1 = 0;
index 0064be7..21091c2 100644 (file)
@@ -838,9 +838,9 @@ int ath5k_hw_dma_stop(struct ath5k_hw *ah)
        for (i = 0; i < qmax; i++) {
                err = ath5k_hw_stop_tx_dma(ah, i);
                /* -EINVAL -> queue inactive */
-               if (err != -EINVAL)
+               if (err && err != -EINVAL)
                        return err;
        }
 
-       return err;
+       return 0;
 }
index e5f2b96..a702817 100644 (file)
@@ -86,7 +86,7 @@ int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
        if (!ah->ah_bwmode) {
                dur = ieee80211_generic_frame_duration(sc->hw,
                                                NULL, len, rate);
-               return dur;
+               return le16_to_cpu(dur);
        }
 
        bitrate = rate->bitrate;
@@ -265,8 +265,6 @@ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah)
                 * what rate we should choose to TX ACKs. */
                tx_time = ath5k_hw_get_frame_duration(ah, 10, rate);
 
-               tx_time = le16_to_cpu(tx_time);
-
                ath5k_hw_reg_write(ah, tx_time, reg);
 
                if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE))
index 78c26fd..62ce2f4 100644 (file)
@@ -282,6 +282,34 @@ int ath5k_hw_phy_disable(struct ath5k_hw *ah)
        return 0;
 }
 
+/*
+ * Wait for synth to settle
+ */
+static void ath5k_hw_wait_for_synth(struct ath5k_hw *ah,
+                       struct ieee80211_channel *channel)
+{
+       /*
+        * On 5211+ read activation -> rx delay
+        * and use it (100ns steps).
+        */
+       if (ah->ah_version != AR5K_AR5210) {
+               u32 delay;
+               delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
+                       AR5K_PHY_RX_DELAY_M;
+               delay = (channel->hw_value & CHANNEL_CCK) ?
+                       ((delay << 2) / 22) : (delay / 10);
+               if (ah->ah_bwmode == AR5K_BWMODE_10MHZ)
+                       delay = delay << 1;
+               if (ah->ah_bwmode == AR5K_BWMODE_5MHZ)
+                       delay = delay << 2;
+               /* XXX: /2 on turbo ? Let's be safe
+                * for now */
+               udelay(100 + delay);
+       } else {
+               mdelay(1);
+       }
+}
+
 
 /**********************\
 * RF Gain optimization *
@@ -1253,6 +1281,7 @@ static int ath5k_hw_channel(struct ath5k_hw *ah,
        case AR5K_RF5111:
                ret = ath5k_hw_rf5111_channel(ah, channel);
                break;
+       case AR5K_RF2317:
        case AR5K_RF2425:
                ret = ath5k_hw_rf2425_channel(ah, channel);
                break;
@@ -3237,6 +3266,13 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
                /* Failed */
                if (i >= 100)
                        return -EIO;
+
+               /* Set channel and wait for synth */
+               ret = ath5k_hw_channel(ah, channel);
+               if (ret)
+                       return ret;
+
+               ath5k_hw_wait_for_synth(ah, channel);
        }
 
        /*
@@ -3251,13 +3287,53 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
        if (ret)
                return ret;
 
+       /* Write OFDM timings on 5212*/
+       if (ah->ah_version == AR5K_AR5212 &&
+               channel->hw_value & CHANNEL_OFDM) {
+
+               ret = ath5k_hw_write_ofdm_timings(ah, channel);
+               if (ret)
+                       return ret;
+
+               /* Spur info is available only from EEPROM versions
+                * greater than 5.3, but the EEPROM routines will use
+                * static values for older versions */
+               if (ah->ah_mac_srev >= AR5K_SREV_AR5424)
+                       ath5k_hw_set_spur_mitigation_filter(ah,
+                                                           channel);
+       }
+
+       /* If we used fast channel switching
+        * we are done, release RF bus and
+        * fire up NF calibration.
+        *
+        * Note: Only NF calibration due to
+        * channel change, not AGC calibration
+        * since AGC is still running !
+        */
+       if (fast) {
+               /*
+                * Release RF Bus grant
+                */
+               AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_RFBUS_REQ,
+                                   AR5K_PHY_RFBUS_REQ_REQUEST);
+
+               /*
+                * Start NF calibration
+                */
+               AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
+                                       AR5K_PHY_AGCCTL_NF);
+
+               return ret;
+       }
+
        /*
         * For 5210 we do all initialization using
         * initvals, so we don't have to modify
         * any settings (5210 also only supports
         * a/aturbo modes)
         */
-       if ((ah->ah_version != AR5K_AR5210) && !fast) {
+       if (ah->ah_version != AR5K_AR5210) {
 
                /*
                 * Write initial RF gain settings
@@ -3276,22 +3352,6 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
                if (ret)
                        return ret;
 
-               /* Write OFDM timings on 5212*/
-               if (ah->ah_version == AR5K_AR5212 &&
-                       channel->hw_value & CHANNEL_OFDM) {
-
-                       ret = ath5k_hw_write_ofdm_timings(ah, channel);
-                       if (ret)
-                               return ret;
-
-                       /* Spur info is available only from EEPROM versions
-                        * greater than 5.3, but the EEPROM routines will use
-                        * static values for older versions */
-                       if (ah->ah_mac_srev >= AR5K_SREV_AR5424)
-                               ath5k_hw_set_spur_mitigation_filter(ah,
-                                                                   channel);
-               }
-
                /*Enable/disable 802.11b mode on 5111
                (enable 2111 frequency converter + CCK)*/
                if (ah->ah_radio == AR5K_RF5111) {
@@ -3322,47 +3382,20 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
         */
        ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
 
+       ath5k_hw_wait_for_synth(ah, channel);
+
        /*
-        * On 5211+ read activation -> rx delay
-        * and use it.
+        * Perform ADC test to see if baseband is ready
+        * Set tx hold and check adc test register
         */
-       if (ah->ah_version != AR5K_AR5210) {
-               u32 delay;
-               delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
-                       AR5K_PHY_RX_DELAY_M;
-               delay = (channel->hw_value & CHANNEL_CCK) ?
-                       ((delay << 2) / 22) : (delay / 10);
-               if (ah->ah_bwmode == AR5K_BWMODE_10MHZ)
-                       delay = delay << 1;
-               if (ah->ah_bwmode == AR5K_BWMODE_5MHZ)
-                       delay = delay << 2;
-               /* XXX: /2 on turbo ? Let's be safe
-                * for now */
-               udelay(100 + delay);
-       } else {
-               mdelay(1);
-       }
-
-       if (fast)
-               /*
-                * Release RF Bus grant
-                */
-               AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_RFBUS_REQ,
-                                   AR5K_PHY_RFBUS_REQ_REQUEST);
-       else {
-               /*
-                * Perform ADC test to see if baseband is ready
-                * Set tx hold and check adc test register
-                */
-               phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
-               ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
-               for (i = 0; i <= 20; i++) {
-                       if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
-                               break;
-                       udelay(200);
-               }
-               ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1);
+       phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
+       ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
+       for (i = 0; i <= 20; i++) {
+               if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
+                       break;
+               udelay(200);
        }
+       ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1);
 
        /*
         * Start automatic gain control calibration
index f8a7771..f44c84a 100644 (file)
@@ -426,9 +426,8 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah,
                }
 
                /* WAR for ASPM system hang */
-               if (AR_SREV_9280(ah) || AR_SREV_9285(ah) || AR_SREV_9287(ah)) {
+               if (AR_SREV_9285(ah) || AR_SREV_9287(ah))
                        val |= (AR_WA_BIT6 | AR_WA_BIT7);
-               }
 
                if (AR_SREV_9285E_20(ah))
                        val |= AR_WA_BIT23;
index 3681caf..1a7fa6e 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/device.h>
 #include <linux/leds.h>
 #include <linux/completion.h>
-#include <linux/pm_qos_params.h>
 
 #include "debug.h"
 #include "common.h"
@@ -57,8 +56,6 @@ struct ath_node;
 
 #define A_MAX(a, b) ((a) > (b) ? (a) : (b))
 
-#define ATH9K_PM_QOS_DEFAULT_VALUE     55
-
 #define TSF_TO_TU(_h,_l) \
        ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
 
@@ -218,6 +215,7 @@ struct ath_frame_info {
 struct ath_buf_state {
        u8 bf_type;
        u8 bfs_paprd;
+       unsigned long bfs_paprd_timestamp;
        enum ath9k_internal_frame_type bfs_ftype;
 };
 
@@ -593,7 +591,6 @@ struct ath_softc {
        struct work_struct paprd_work;
        struct work_struct hw_check_work;
        struct completion paprd_complete;
-       bool paprd_pending;
 
        u32 intrstatus;
        u32 sc_flags; /* SC_OP_* */
@@ -633,8 +630,6 @@ struct ath_softc {
        struct ath_descdma txsdma;
 
        struct ath_ant_comb ant_comb;
-
-       struct pm_qos_request_list pm_qos_req;
 };
 
 struct ath_wiphy {
@@ -666,7 +661,6 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz)
 extern struct ieee80211_ops ath9k_ops;
 extern int ath9k_modparam_nohwcrypt;
 extern int led_blink;
-extern int ath9k_pm_qos_value;
 extern bool is_ath9k_unloaded;
 
 irqreturn_t ath_isr(int irq, void *dev);
index 5ab3084..07b1633 100644 (file)
@@ -219,8 +219,9 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev)
        struct tx_buf *tx_buf = NULL;
        struct sk_buff *nskb = NULL;
        int ret = 0, i;
-       u16 *hdr, tx_skb_cnt = 0;
+       u16 tx_skb_cnt = 0;
        u8 *buf;
+       __le16 *hdr;
 
        if (hif_dev->tx.tx_skb_cnt == 0)
                return 0;
@@ -245,9 +246,9 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev)
 
                buf = tx_buf->buf;
                buf += tx_buf->offset;
-               hdr = (u16 *)buf;
-               *hdr++ = nskb->len;
-               *hdr++ = ATH_USB_TX_STREAM_MODE_TAG;
+               hdr = (__le16 *)buf;
+               *hdr++ = cpu_to_le16(nskb->len);
+               *hdr++ = cpu_to_le16(ATH_USB_TX_STREAM_MODE_TAG);
                buf += 4;
                memcpy(buf, nskb->data, nskb->len);
                tx_buf->len = nskb->len + 4;
index 38433f9..0352f09 100644 (file)
@@ -142,9 +142,6 @@ static void ath9k_deinit_priv(struct ath9k_htc_priv *priv)
 {
        ath9k_htc_exit_debug(priv->ah);
        ath9k_hw_deinit(priv->ah);
-       tasklet_kill(&priv->swba_tasklet);
-       tasklet_kill(&priv->rx_tasklet);
-       tasklet_kill(&priv->tx_tasklet);
        kfree(priv->ah);
        priv->ah = NULL;
 }
index f4d576b..6bb5995 100644 (file)
@@ -1025,12 +1025,6 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
        int ret = 0;
        u8 cmd_rsp;
 
-       /* Cancel all the running timers/work .. */
-       cancel_work_sync(&priv->fatal_work);
-       cancel_work_sync(&priv->ps_work);
-       cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
-       ath9k_led_stop_brightness(priv);
-
        mutex_lock(&priv->mutex);
 
        if (priv->op_flags & OP_INVALID) {
@@ -1044,8 +1038,23 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
        WMI_CMD(WMI_DISABLE_INTR_CMDID);
        WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
        WMI_CMD(WMI_STOP_RECV_CMDID);
+
+       tasklet_kill(&priv->swba_tasklet);
+       tasklet_kill(&priv->rx_tasklet);
+       tasklet_kill(&priv->tx_tasklet);
+
        skb_queue_purge(&priv->tx_queue);
 
+       mutex_unlock(&priv->mutex);
+
+       /* Cancel all the running timers/work .. */
+       cancel_work_sync(&priv->fatal_work);
+       cancel_work_sync(&priv->ps_work);
+       cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
+       ath9k_led_stop_brightness(priv);
+
+       mutex_lock(&priv->mutex);
+
        /* Remove monitor interface here */
        if (ah->opmode == NL80211_IFTYPE_MONITOR) {
                if (ath9k_htc_remove_monitor_interface(priv))
index 1afb8bb..9f01e50 100644 (file)
@@ -369,6 +369,9 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
        else
                ah->config.ht_enable = 0;
 
+       /* PAPRD needs some more work to be enabled */
+       ah->config.paprd_disable = 1;
+
        ah->config.rx_intr_mitigation = true;
        ah->config.pcieSerDesWrite = true;
 
@@ -1933,7 +1936,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
                pCap->rx_status_len = sizeof(struct ar9003_rxs);
                pCap->tx_desc_len = sizeof(struct ar9003_txc);
                pCap->txs_len = sizeof(struct ar9003_txs);
-               if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD))
+               if (!ah->config.paprd_disable &&
+                   ah->eep_ops->get_eeprom(ah, EEP_PAPRD))
                        pCap->hw_caps |= ATH9K_HW_CAP_PAPRD;
        } else {
                pCap->tx_desc_len = sizeof(struct ath_desc);
index 5a3dfec..ea9fde6 100644 (file)
@@ -225,6 +225,7 @@ struct ath9k_ops_config {
        u32 pcie_waen;
        u8 analog_shiftreg;
        u8 ht_enable;
+       u8 paprd_disable;
        u32 ofdm_trig_low;
        u32 ofdm_trig_high;
        u32 cck_trig_high;
index 767d8b8..a033d01 100644 (file)
@@ -41,10 +41,6 @@ static int ath9k_btcoex_enable;
 module_param_named(btcoex_enable, ath9k_btcoex_enable, int, 0444);
 MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence");
 
-int ath9k_pm_qos_value = ATH9K_PM_QOS_DEFAULT_VALUE;
-module_param_named(pmqos, ath9k_pm_qos_value, int, S_IRUSR | S_IRGRP | S_IROTH);
-MODULE_PARM_DESC(pmqos, "User specified PM-QOS value");
-
 bool is_ath9k_unloaded;
 /* We use the hw_value as an index into our private channel structure */
 
@@ -598,8 +594,6 @@ err_btcoex:
 err_queues:
        ath9k_hw_deinit(ah);
 err_hw:
-       tasklet_kill(&sc->intr_tq);
-       tasklet_kill(&sc->bcon_tasklet);
 
        kfree(ah);
        sc->sc_ah = NULL;
@@ -764,9 +758,6 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
        ath_init_leds(sc);
        ath_start_rfkill_poll(sc);
 
-       pm_qos_add_request(&sc->pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
-                          PM_QOS_DEFAULT_VALUE);
-
        return 0;
 
 error_world:
@@ -807,9 +798,6 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
 
        ath9k_hw_deinit(sc->sc_ah);
 
-       tasklet_kill(&sc->intr_tq);
-       tasklet_kill(&sc->bcon_tasklet);
-
        kfree(sc->sc_ah);
        sc->sc_ah = NULL;
 }
@@ -824,6 +812,8 @@ void ath9k_deinit_device(struct ath_softc *sc)
        wiphy_rfkill_stop_polling(sc->hw->wiphy);
        ath_deinit_leds(sc);
 
+       ath9k_ps_restore(sc);
+
        for (i = 0; i < sc->num_sec_wiphy; i++) {
                struct ath_wiphy *aphy = sc->sec_wiphy[i];
                if (aphy == NULL)
@@ -834,7 +824,6 @@ void ath9k_deinit_device(struct ath_softc *sc)
        }
 
        ieee80211_unregister_hw(hw);
-       pm_qos_remove_request(&sc->pm_qos_req);
        ath_rx_cleanup(sc);
        ath_tx_cleanup(sc);
        ath9k_deinit_softc(sc);
index 180170d..2915b11 100644 (file)
@@ -885,7 +885,7 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
        struct ath_common *common = ath9k_hw_common(ah);
 
        if (!(ints & ATH9K_INT_GLOBAL))
-               ath9k_hw_enable_interrupts(ah);
+               ath9k_hw_disable_interrupts(ah);
 
        ath_dbg(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
 
@@ -963,7 +963,8 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
                        REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
        }
 
-       ath9k_hw_enable_interrupts(ah);
+       if (ints & ATH9K_INT_GLOBAL)
+               ath9k_hw_enable_interrupts(ah);
 
        return;
 }
index f90a6ca..a09d15f 100644 (file)
@@ -325,6 +325,8 @@ static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int
 {
        struct ieee80211_hw *hw = sc->hw;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
        struct ath_tx_control txctl;
        int time_left;
 
@@ -340,14 +342,16 @@ static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int
        tx_info->control.rates[1].idx = -1;
 
        init_completion(&sc->paprd_complete);
-       sc->paprd_pending = true;
        txctl.paprd = BIT(chain);
-       if (ath_tx_start(hw, skb, &txctl) != 0)
+
+       if (ath_tx_start(hw, skb, &txctl) != 0) {
+               ath_dbg(common, ATH_DBG_XMIT, "PAPRD TX failed\n");
+               dev_kfree_skb_any(skb);
                return false;
+       }
 
        time_left = wait_for_completion_timeout(&sc->paprd_complete,
                        msecs_to_jiffies(ATH_PAPRD_TIMEOUT));
-       sc->paprd_pending = false;
 
        if (!time_left)
                ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_CALIBRATE,
@@ -592,14 +596,12 @@ void ath9k_tasklet(unsigned long data)
        u32 status = sc->intrstatus;
        u32 rxmask;
 
-       ath9k_ps_wakeup(sc);
-
        if (status & ATH9K_INT_FATAL) {
                ath_reset(sc, true);
-               ath9k_ps_restore(sc);
                return;
        }
 
+       ath9k_ps_wakeup(sc);
        spin_lock(&sc->sc_pcu_lock);
 
        if (!ath9k_hw_check_alive(ah))
@@ -955,8 +957,6 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
 
        spin_unlock_bh(&sc->sc_pcu_lock);
        ath9k_ps_restore(sc);
-
-       ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP);
 }
 
 int ath_reset(struct ath_softc *sc, bool retry_tx)
@@ -969,6 +969,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
        /* Stop ANI */
        del_timer_sync(&common->ani.timer);
 
+       ath9k_ps_wakeup(sc);
        spin_lock_bh(&sc->sc_pcu_lock);
 
        ieee80211_stop_queues(hw);
@@ -1015,6 +1016,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
 
        /* Start ANI */
        ath_start_ani(common);
+       ath9k_ps_restore(sc);
 
        return r;
 }
@@ -1171,12 +1173,6 @@ static int ath9k_start(struct ieee80211_hw *hw)
                        ath9k_btcoex_timer_resume(sc);
        }
 
-       /* User has the option to provide pm-qos value as a module
-        * parameter rather than using the default value of
-        * 'ATH9K_PM_QOS_DEFAULT_VALUE'.
-        */
-       pm_qos_update_request(&sc->pm_qos_req, ath9k_pm_qos_value);
-
        if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en)
                common->bus_ops->extn_synch_en(common);
 
@@ -1309,6 +1305,9 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 
        spin_lock_bh(&sc->sc_pcu_lock);
 
+       /* prevent tasklets to enable interrupts once we disable them */
+       ah->imask &= ~ATH9K_INT_GLOBAL;
+
        /* make sure h/w will not generate any interrupt
         * before setting the invalid flag. */
        ath9k_hw_disable_interrupts(ah);
@@ -1326,6 +1325,12 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 
        spin_unlock_bh(&sc->sc_pcu_lock);
 
+       /* we can now sync irq and kill any running tasklets, since we already
+        * disabled interrupts and not holding a spin lock */
+       synchronize_irq(sc->irq);
+       tasklet_kill(&sc->intr_tq);
+       tasklet_kill(&sc->bcon_tasklet);
+
        ath9k_ps_restore(sc);
 
        sc->ps_idle = true;
@@ -1334,8 +1339,6 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 
        sc->sc_flags |= SC_OP_INVALID;
 
-       pm_qos_update_request(&sc->pm_qos_req, PM_QOS_DEFAULT_VALUE);
-
        mutex_unlock(&sc->mutex);
 
        ath_dbg(common, ATH_DBG_CONFIG, "Driver halt\n");
@@ -1701,7 +1704,9 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 skip_chan_change:
        if (changed & IEEE80211_CONF_CHANGE_POWER) {
                sc->config.txpowlimit = 2 * conf->power_level;
+               ath9k_ps_wakeup(sc);
                ath_update_txpow(sc);
+               ath9k_ps_restore(sc);
        }
 
        spin_lock_bh(&sc->wiphy_lock);
index 332d1fe..07b7804 100644 (file)
@@ -1725,6 +1725,9 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
                        ar9003_hw_set_paprd_txdesc(sc->sc_ah, bf->bf_desc,
                                                   bf->bf_state.bfs_paprd);
 
+               if (txctl->paprd)
+                       bf->bf_state.bfs_paprd_timestamp = jiffies;
+
                ath_tx_send_normal(sc, txctl->txq, tid, &bf_head);
        }
 
@@ -1886,7 +1889,9 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
        bf->bf_buf_addr = 0;
 
        if (bf->bf_state.bfs_paprd) {
-               if (!sc->paprd_pending)
+               if (time_after(jiffies,
+                               bf->bf_state.bfs_paprd_timestamp +
+                               msecs_to_jiffies(ATH_PAPRD_TIMEOUT)))
                        dev_kfree_skb_any(skb);
                else
                        complete(&sc->paprd_complete);
@@ -2113,9 +2118,7 @@ static void ath_tx_complete_poll_work(struct work_struct *work)
        if (needreset) {
                ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
                        "tx hung, resetting the chip\n");
-               ath9k_ps_wakeup(sc);
                ath_reset(sc, true);
-               ath9k_ps_restore(sc);
        }
 
        ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
index 939a0e9..84866a4 100644 (file)
@@ -564,7 +564,7 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len)
        cam = ieee80211_check_tim(tim_ie, tim_len, ar->common.curaid);
 
        /* 2. Maybe the AP wants to send multicast/broadcast data? */
-       cam = !!(tim_ie->bitmap_ctrl & 0x01);
+       cam |= !!(tim_ie->bitmap_ctrl & 0x01);
 
        if (!cam) {
                /* back to low-power land. */
index 537732e..f82c400 100644 (file)
@@ -118,6 +118,8 @@ static struct usb_device_id carl9170_usb_ids[] = {
        { USB_DEVICE(0x057c, 0x8402) },
        /* Qwest/Actiontec 802AIN Wireless N USB Network Adapter */
        { USB_DEVICE(0x1668, 0x1200) },
+       /* Airlive X.USB a/b/g/n */
+       { USB_DEVICE(0x1b75, 0x9170) },
 
        /* terminate */
        {}
index 61915f3..471a52a 100644 (file)
@@ -706,11 +706,10 @@ static void schedule_reset(struct ipw2100_priv *priv)
                netif_stop_queue(priv->net_dev);
                priv->status |= STATUS_RESET_PENDING;
                if (priv->reset_backoff)
-                       queue_delayed_work(priv->workqueue, &priv->reset_work,
-                                          priv->reset_backoff * HZ);
+                       schedule_delayed_work(&priv->reset_work,
+                                             priv->reset_backoff * HZ);
                else
-                       queue_delayed_work(priv->workqueue, &priv->reset_work,
-                                          0);
+                       schedule_delayed_work(&priv->reset_work, 0);
 
                if (priv->reset_backoff < MAX_RESET_BACKOFF)
                        priv->reset_backoff++;
@@ -1474,7 +1473,7 @@ static int ipw2100_enable_adapter(struct ipw2100_priv *priv)
 
        if (priv->stop_hang_check) {
                priv->stop_hang_check = 0;
-               queue_delayed_work(priv->workqueue, &priv->hang_check, HZ / 2);
+               schedule_delayed_work(&priv->hang_check, HZ / 2);
        }
 
       fail_up:
@@ -1808,8 +1807,8 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
 
                if (priv->stop_rf_kill) {
                        priv->stop_rf_kill = 0;
-                       queue_delayed_work(priv->workqueue, &priv->rf_kill,
-                                          round_jiffies_relative(HZ));
+                       schedule_delayed_work(&priv->rf_kill,
+                                             round_jiffies_relative(HZ));
                }
 
                deferred = 1;
@@ -2086,7 +2085,7 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
        priv->status |= STATUS_ASSOCIATING;
        priv->connect_start = get_seconds();
 
-       queue_delayed_work(priv->workqueue, &priv->wx_event_work, HZ / 10);
+       schedule_delayed_work(&priv->wx_event_work, HZ / 10);
 }
 
 static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
@@ -2166,9 +2165,9 @@ static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
                return;
 
        if (priv->status & STATUS_SECURITY_UPDATED)
-               queue_delayed_work(priv->workqueue, &priv->security_work, 0);
+               schedule_delayed_work(&priv->security_work, 0);
 
-       queue_delayed_work(priv->workqueue, &priv->wx_event_work, 0);
+       schedule_delayed_work(&priv->wx_event_work, 0);
 }
 
 static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
@@ -2183,8 +2182,7 @@ static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
        /* Make sure the RF Kill check timer is running */
        priv->stop_rf_kill = 0;
        cancel_delayed_work(&priv->rf_kill);
-       queue_delayed_work(priv->workqueue, &priv->rf_kill,
-                          round_jiffies_relative(HZ));
+       schedule_delayed_work(&priv->rf_kill, round_jiffies_relative(HZ));
 }
 
 static void send_scan_event(void *data)
@@ -2219,13 +2217,12 @@ static void isr_scan_complete(struct ipw2100_priv *priv, u32 status)
        /* Only userspace-requested scan completion events go out immediately */
        if (!priv->user_requested_scan) {
                if (!delayed_work_pending(&priv->scan_event_later))
-                       queue_delayed_work(priv->workqueue,
-                                       &priv->scan_event_later,
-                                       round_jiffies_relative(msecs_to_jiffies(4000)));
+                       schedule_delayed_work(&priv->scan_event_later,
+                                             round_jiffies_relative(msecs_to_jiffies(4000)));
        } else {
                priv->user_requested_scan = 0;
                cancel_delayed_work(&priv->scan_event_later);
-               queue_work(priv->workqueue, &priv->scan_event_now);
+               schedule_work(&priv->scan_event_now);
        }
 }
 
@@ -4329,8 +4326,8 @@ static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio)
                        /* Make sure the RF_KILL check timer is running */
                        priv->stop_rf_kill = 0;
                        cancel_delayed_work(&priv->rf_kill);
-                       queue_delayed_work(priv->workqueue, &priv->rf_kill,
-                                          round_jiffies_relative(HZ));
+                       schedule_delayed_work(&priv->rf_kill,
+                                             round_jiffies_relative(HZ));
                } else
                        schedule_reset(priv);
        }
@@ -4461,20 +4458,17 @@ static void bd_queue_initialize(struct ipw2100_priv *priv,
        IPW_DEBUG_INFO("exit\n");
 }
 
-static void ipw2100_kill_workqueue(struct ipw2100_priv *priv)
+static void ipw2100_kill_works(struct ipw2100_priv *priv)
 {
-       if (priv->workqueue) {
-               priv->stop_rf_kill = 1;
-               priv->stop_hang_check = 1;
-               cancel_delayed_work(&priv->reset_work);
-               cancel_delayed_work(&priv->security_work);
-               cancel_delayed_work(&priv->wx_event_work);
-               cancel_delayed_work(&priv->hang_check);
-               cancel_delayed_work(&priv->rf_kill);
-               cancel_delayed_work(&priv->scan_event_later);
-               destroy_workqueue(priv->workqueue);
-               priv->workqueue = NULL;
-       }
+       priv->stop_rf_kill = 1;
+       priv->stop_hang_check = 1;
+       cancel_delayed_work_sync(&priv->reset_work);
+       cancel_delayed_work_sync(&priv->security_work);
+       cancel_delayed_work_sync(&priv->wx_event_work);
+       cancel_delayed_work_sync(&priv->hang_check);
+       cancel_delayed_work_sync(&priv->rf_kill);
+       cancel_work_sync(&priv->scan_event_now);
+       cancel_delayed_work_sync(&priv->scan_event_later);
 }
 
 static int ipw2100_tx_allocate(struct ipw2100_priv *priv)
@@ -6046,7 +6040,7 @@ static void ipw2100_hang_check(struct work_struct *work)
        priv->last_rtc = rtc;
 
        if (!priv->stop_hang_check)
-               queue_delayed_work(priv->workqueue, &priv->hang_check, HZ / 2);
+               schedule_delayed_work(&priv->hang_check, HZ / 2);
 
        spin_unlock_irqrestore(&priv->low_lock, flags);
 }
@@ -6062,8 +6056,8 @@ static void ipw2100_rf_kill(struct work_struct *work)
        if (rf_kill_active(priv)) {
                IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n");
                if (!priv->stop_rf_kill)
-                       queue_delayed_work(priv->workqueue, &priv->rf_kill,
-                                          round_jiffies_relative(HZ));
+                       schedule_delayed_work(&priv->rf_kill,
+                                             round_jiffies_relative(HZ));
                goto exit_unlock;
        }
 
@@ -6209,8 +6203,6 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
        INIT_LIST_HEAD(&priv->fw_pend_list);
        INIT_STAT(&priv->fw_pend_stat);
 
-       priv->workqueue = create_workqueue(DRV_NAME);
-
        INIT_DELAYED_WORK(&priv->reset_work, ipw2100_reset_adapter);
        INIT_DELAYED_WORK(&priv->security_work, ipw2100_security_work);
        INIT_DELAYED_WORK(&priv->wx_event_work, ipw2100_wx_event_work);
@@ -6410,7 +6402,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
                if (dev->irq)
                        free_irq(dev->irq, priv);
 
-               ipw2100_kill_workqueue(priv);
+               ipw2100_kill_works(priv);
 
                /* These are safe to call even if they weren't allocated */
                ipw2100_queues_free(priv);
@@ -6460,9 +6452,7 @@ static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev)
                 * first, then close() will crash. */
                unregister_netdev(dev);
 
-               /* ipw2100_down will ensure that there is no more pending work
-                * in the workqueue's, so we can safely remove them now. */
-               ipw2100_kill_workqueue(priv);
+               ipw2100_kill_works(priv);
 
                ipw2100_queues_free(priv);
 
index 838002b..99cba96 100644 (file)
@@ -580,7 +580,6 @@ struct ipw2100_priv {
 
        struct tasklet_struct irq_tasklet;
 
-       struct workqueue_struct *workqueue;
        struct delayed_work reset_work;
        struct delayed_work security_work;
        struct delayed_work wx_event_work;
index ae438ed..160881f 100644 (file)
@@ -894,9 +894,8 @@ static void ipw_led_link_on(struct ipw_priv *priv)
 
                /* If we aren't associated, schedule turning the LED off */
                if (!(priv->status & STATUS_ASSOCIATED))
-                       queue_delayed_work(priv->workqueue,
-                                          &priv->led_link_off,
-                                          LD_TIME_LINK_ON);
+                       schedule_delayed_work(&priv->led_link_off,
+                                             LD_TIME_LINK_ON);
        }
 
        spin_unlock_irqrestore(&priv->lock, flags);
@@ -939,8 +938,8 @@ static void ipw_led_link_off(struct ipw_priv *priv)
                 * turning the LED on (blink while unassociated) */
                if (!(priv->status & STATUS_RF_KILL_MASK) &&
                    !(priv->status & STATUS_ASSOCIATED))
-                       queue_delayed_work(priv->workqueue, &priv->led_link_on,
-                                          LD_TIME_LINK_OFF);
+                       schedule_delayed_work(&priv->led_link_on,
+                                             LD_TIME_LINK_OFF);
 
        }
 
@@ -980,13 +979,11 @@ static void __ipw_led_activity_on(struct ipw_priv *priv)
                priv->status |= STATUS_LED_ACT_ON;
 
                cancel_delayed_work(&priv->led_act_off);
-               queue_delayed_work(priv->workqueue, &priv->led_act_off,
-                                  LD_TIME_ACT_ON);
+               schedule_delayed_work(&priv->led_act_off, LD_TIME_ACT_ON);
        } else {
                /* Reschedule LED off for full time period */
                cancel_delayed_work(&priv->led_act_off);
-               queue_delayed_work(priv->workqueue, &priv->led_act_off,
-                                  LD_TIME_ACT_ON);
+               schedule_delayed_work(&priv->led_act_off, LD_TIME_ACT_ON);
        }
 }
 
@@ -1795,13 +1792,11 @@ static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio)
        if (disable_radio) {
                priv->status |= STATUS_RF_KILL_SW;
 
-               if (priv->workqueue) {
-                       cancel_delayed_work(&priv->request_scan);
-                       cancel_delayed_work(&priv->request_direct_scan);
-                       cancel_delayed_work(&priv->request_passive_scan);
-                       cancel_delayed_work(&priv->scan_event);
-               }
-               queue_work(priv->workqueue, &priv->down);
+               cancel_delayed_work(&priv->request_scan);
+               cancel_delayed_work(&priv->request_direct_scan);
+               cancel_delayed_work(&priv->request_passive_scan);
+               cancel_delayed_work(&priv->scan_event);
+               schedule_work(&priv->down);
        } else {
                priv->status &= ~STATUS_RF_KILL_SW;
                if (rf_kill_active(priv)) {
@@ -1809,10 +1804,10 @@ static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio)
                                          "disabled by HW switch\n");
                        /* Make sure the RF_KILL check timer is running */
                        cancel_delayed_work(&priv->rf_kill);
-                       queue_delayed_work(priv->workqueue, &priv->rf_kill,
-                                          round_jiffies_relative(2 * HZ));
+                       schedule_delayed_work(&priv->rf_kill,
+                                             round_jiffies_relative(2 * HZ));
                } else
-                       queue_work(priv->workqueue, &priv->up);
+                       schedule_work(&priv->up);
        }
 
        return 1;
@@ -2063,7 +2058,7 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
                cancel_delayed_work(&priv->request_passive_scan);
                cancel_delayed_work(&priv->scan_event);
                schedule_work(&priv->link_down);
-               queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ);
+               schedule_delayed_work(&priv->rf_kill, 2 * HZ);
                handled |= IPW_INTA_BIT_RF_KILL_DONE;
        }
 
@@ -2103,7 +2098,7 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
                priv->status &= ~STATUS_HCMD_ACTIVE;
                wake_up_interruptible(&priv->wait_command_queue);
 
-               queue_work(priv->workqueue, &priv->adapter_restart);
+               schedule_work(&priv->adapter_restart);
                handled |= IPW_INTA_BIT_FATAL_ERROR;
        }
 
@@ -2323,11 +2318,6 @@ static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac)
        return ipw_send_cmd_pdu(priv, IPW_CMD_ADAPTER_ADDRESS, ETH_ALEN, mac);
 }
 
-/*
- * NOTE: This must be executed from our workqueue as it results in udelay
- * being called which may corrupt the keyboard if executed on default
- * workqueue
- */
 static void ipw_adapter_restart(void *adapter)
 {
        struct ipw_priv *priv = adapter;
@@ -2368,13 +2358,13 @@ static void ipw_scan_check(void *data)
                IPW_DEBUG_SCAN("Scan completion watchdog resetting "
                               "adapter after (%dms).\n",
                               jiffies_to_msecs(IPW_SCAN_CHECK_WATCHDOG));
-               queue_work(priv->workqueue, &priv->adapter_restart);
+               schedule_work(&priv->adapter_restart);
        } else if (priv->status & STATUS_SCANNING) {
                IPW_DEBUG_SCAN("Scan completion watchdog aborting scan "
                               "after (%dms).\n",
                               jiffies_to_msecs(IPW_SCAN_CHECK_WATCHDOG));
                ipw_abort_scan(priv);
-               queue_delayed_work(priv->workqueue, &priv->scan_check, HZ);
+               schedule_delayed_work(&priv->scan_check, HZ);
        }
 }
 
@@ -3943,7 +3933,7 @@ static void ipw_send_disassociate(struct ipw_priv *priv, int quiet)
 
        if (priv->status & STATUS_ASSOCIATING) {
                IPW_DEBUG_ASSOC("Disassociating while associating.\n");
-               queue_work(priv->workqueue, &priv->disassociate);
+               schedule_work(&priv->disassociate);
                return;
        }
 
@@ -4360,8 +4350,7 @@ static void ipw_gather_stats(struct ipw_priv *priv)
 
        priv->quality = quality;
 
-       queue_delayed_work(priv->workqueue, &priv->gather_stats,
-                          IPW_STATS_INTERVAL);
+       schedule_delayed_work(&priv->gather_stats, IPW_STATS_INTERVAL);
 }
 
 static void ipw_bg_gather_stats(struct work_struct *work)
@@ -4396,10 +4385,10 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv,
                        IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF |
                                  IPW_DL_STATE,
                                  "Aborting scan with missed beacon.\n");
-                       queue_work(priv->workqueue, &priv->abort_scan);
+                       schedule_work(&priv->abort_scan);
                }
 
-               queue_work(priv->workqueue, &priv->disassociate);
+               schedule_work(&priv->disassociate);
                return;
        }
 
@@ -4425,8 +4414,7 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv,
                if (!(priv->status & STATUS_ROAMING)) {
                        priv->status |= STATUS_ROAMING;
                        if (!(priv->status & STATUS_SCANNING))
-                               queue_delayed_work(priv->workqueue,
-                                                  &priv->request_scan, 0);
+                               schedule_delayed_work(&priv->request_scan, 0);
                }
                return;
        }
@@ -4439,7 +4427,7 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv,
                 * channels..) */
                IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | IPW_DL_STATE,
                          "Aborting scan with missed beacon.\n");
-               queue_work(priv->workqueue, &priv->abort_scan);
+               schedule_work(&priv->abort_scan);
        }
 
        IPW_DEBUG_NOTIF("Missed beacon: %d\n", missed_count);
@@ -4462,8 +4450,8 @@ static void handle_scan_event(struct ipw_priv *priv)
        /* Only userspace-requested scan completion events go out immediately */
        if (!priv->user_requested_scan) {
                if (!delayed_work_pending(&priv->scan_event))
-                       queue_delayed_work(priv->workqueue, &priv->scan_event,
-                                        round_jiffies_relative(msecs_to_jiffies(4000)));
+                       schedule_delayed_work(&priv->scan_event,
+                                             round_jiffies_relative(msecs_to_jiffies(4000)));
        } else {
                union iwreq_data wrqu;
 
@@ -4516,20 +4504,17 @@ static void ipw_rx_notification(struct ipw_priv *priv,
 
                                                IPW_DEBUG_ASSOC
                                                    ("queueing adhoc check\n");
-                                               queue_delayed_work(priv->
-                                                                  workqueue,
-                                                                  &priv->
-                                                                  adhoc_check,
-                                                                  le16_to_cpu(priv->
-                                                                  assoc_request.
-                                                                  beacon_interval));
+                                               schedule_delayed_work(
+                                                       &priv->adhoc_check,
+                                                       le16_to_cpu(priv->
+                                                       assoc_request.
+                                                       beacon_interval));
                                                break;
                                        }
 
                                        priv->status &= ~STATUS_ASSOCIATING;
                                        priv->status |= STATUS_ASSOCIATED;
-                                       queue_work(priv->workqueue,
-                                                  &priv->system_config);
+                                       schedule_work(&priv->system_config);
 
 #ifdef CONFIG_IPW2200_QOS
 #define IPW_GET_PACKET_STYPE(x) WLAN_FC_GET_STYPE( \
@@ -4792,43 +4777,37 @@ static void ipw_rx_notification(struct ipw_priv *priv,
 #ifdef CONFIG_IPW2200_MONITOR
                        if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
                                priv->status |= STATUS_SCAN_FORCED;
-                               queue_delayed_work(priv->workqueue,
-                                                  &priv->request_scan, 0);
+                               schedule_delayed_work(&priv->request_scan, 0);
                                break;
                        }
                        priv->status &= ~STATUS_SCAN_FORCED;
 #endif                         /* CONFIG_IPW2200_MONITOR */
 
                        /* Do queued direct scans first */
-                       if (priv->status & STATUS_DIRECT_SCAN_PENDING) {
-                               queue_delayed_work(priv->workqueue,
-                                                  &priv->request_direct_scan, 0);
-                       }
+                       if (priv->status & STATUS_DIRECT_SCAN_PENDING)
+                               schedule_delayed_work(&priv->request_direct_scan, 0);
 
                        if (!(priv->status & (STATUS_ASSOCIATED |
                                              STATUS_ASSOCIATING |
                                              STATUS_ROAMING |
                                              STATUS_DISASSOCIATING)))
-                               queue_work(priv->workqueue, &priv->associate);
+                               schedule_work(&priv->associate);
                        else if (priv->status & STATUS_ROAMING) {
                                if (x->status == SCAN_COMPLETED_STATUS_COMPLETE)
                                        /* If a scan completed and we are in roam mode, then
                                         * the scan that completed was the one requested as a
                                         * result of entering roam... so, schedule the
                                         * roam work */
-                                       queue_work(priv->workqueue,
-                                                  &priv->roam);
+                                       schedule_work(&priv->roam);
                                else
                                        /* Don't schedule if we aborted the scan */
                                        priv->status &= ~STATUS_ROAMING;
                        } else if (priv->status & STATUS_SCAN_PENDING)
-                               queue_delayed_work(priv->workqueue,
-                                                  &priv->request_scan, 0);
+                               schedule_delayed_work(&priv->request_scan, 0);
                        else if (priv->config & CFG_BACKGROUND_SCAN
                                 && priv->status & STATUS_ASSOCIATED)
-                               queue_delayed_work(priv->workqueue,
-                                                  &priv->request_scan,
-                                                  round_jiffies_relative(HZ));
+                               schedule_delayed_work(&priv->request_scan,
+                                                     round_jiffies_relative(HZ));
 
                        /* Send an empty event to user space.
                         * We don't send the received data on the event because
@@ -5192,7 +5171,7 @@ static void ipw_rx_queue_restock(struct ipw_priv *priv)
        /* If the pre-allocated buffer pool is dropping low, schedule to
         * refill it */
        if (rxq->free_count <= RX_LOW_WATERMARK)
-               queue_work(priv->workqueue, &priv->rx_replenish);
+               schedule_work(&priv->rx_replenish);
 
        /* If we've added more space for the firmware to place data, tell it */
        if (write != rxq->write)
@@ -6133,8 +6112,8 @@ static void ipw_adhoc_check(void *data)
                return;
        }
 
-       queue_delayed_work(priv->workqueue, &priv->adhoc_check,
-                          le16_to_cpu(priv->assoc_request.beacon_interval));
+       schedule_delayed_work(&priv->adhoc_check,
+                             le16_to_cpu(priv->assoc_request.beacon_interval));
 }
 
 static void ipw_bg_adhoc_check(struct work_struct *work)
@@ -6523,8 +6502,7 @@ send_request:
        } else
                priv->status &= ~STATUS_SCAN_PENDING;
 
-       queue_delayed_work(priv->workqueue, &priv->scan_check,
-                          IPW_SCAN_CHECK_WATCHDOG);
+       schedule_delayed_work(&priv->scan_check, IPW_SCAN_CHECK_WATCHDOG);
 done:
        mutex_unlock(&priv->mutex);
        return err;
@@ -6994,8 +6972,7 @@ static int ipw_qos_handle_probe_response(struct ipw_priv *priv,
                                    !memcmp(network->ssid,
                                            priv->assoc_network->ssid,
                                            network->ssid_len)) {
-                                       queue_work(priv->workqueue,
-                                                  &priv->merge_networks);
+                                       schedule_work(&priv->merge_networks);
                                }
        }
 
@@ -7663,7 +7640,7 @@ static int ipw_associate(void *data)
        if (priv->status & STATUS_DISASSOCIATING) {
                IPW_DEBUG_ASSOC("Not attempting association (in "
                                "disassociating)\n ");
-               queue_work(priv->workqueue, &priv->associate);
+               schedule_work(&priv->associate);
                return 0;
        }
 
@@ -7731,12 +7708,10 @@ static int ipw_associate(void *data)
 
                if (!(priv->status & STATUS_SCANNING)) {
                        if (!(priv->config & CFG_SPEED_SCAN))
-                               queue_delayed_work(priv->workqueue,
-                                                  &priv->request_scan,
-                                                  SCAN_INTERVAL);
+                               schedule_delayed_work(&priv->request_scan,
+                                                     SCAN_INTERVAL);
                        else
-                               queue_delayed_work(priv->workqueue,
-                                                  &priv->request_scan, 0);
+                               schedule_delayed_work(&priv->request_scan, 0);
                }
 
                return 0;
@@ -8899,7 +8874,7 @@ static int ipw_wx_set_mode(struct net_device *dev,
 
        priv->ieee->iw_mode = wrqu->mode;
 
-       queue_work(priv->workqueue, &priv->adapter_restart);
+       schedule_work(&priv->adapter_restart);
        mutex_unlock(&priv->mutex);
        return err;
 }
@@ -9598,7 +9573,7 @@ static int ipw_wx_set_scan(struct net_device *dev,
 
        IPW_DEBUG_WX("Start scan\n");
 
-       queue_delayed_work(priv->workqueue, work, 0);
+       schedule_delayed_work(work, 0);
 
        return 0;
 }
@@ -9937,7 +9912,7 @@ static int ipw_wx_set_monitor(struct net_device *dev,
 #else
                        priv->net_dev->type = ARPHRD_IEEE80211;
 #endif
-                       queue_work(priv->workqueue, &priv->adapter_restart);
+                       schedule_work(&priv->adapter_restart);
                }
 
                ipw_set_channel(priv, parms[1]);
@@ -9947,7 +9922,7 @@ static int ipw_wx_set_monitor(struct net_device *dev,
                        return 0;
                }
                priv->net_dev->type = ARPHRD_ETHER;
-               queue_work(priv->workqueue, &priv->adapter_restart);
+               schedule_work(&priv->adapter_restart);
        }
        mutex_unlock(&priv->mutex);
        return 0;
@@ -9961,7 +9936,7 @@ static int ipw_wx_reset(struct net_device *dev,
 {
        struct ipw_priv *priv = libipw_priv(dev);
        IPW_DEBUG_WX("RESET\n");
-       queue_work(priv->workqueue, &priv->adapter_restart);
+       schedule_work(&priv->adapter_restart);
        return 0;
 }
 
@@ -10551,7 +10526,7 @@ static int ipw_net_set_mac_address(struct net_device *dev, void *p)
        memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
        printk(KERN_INFO "%s: Setting MAC to %pM\n",
               priv->net_dev->name, priv->mac_addr);
-       queue_work(priv->workqueue, &priv->adapter_restart);
+       schedule_work(&priv->adapter_restart);
        mutex_unlock(&priv->mutex);
        return 0;
 }
@@ -10684,9 +10659,7 @@ static void ipw_rf_kill(void *adapter)
 
        if (rf_kill_active(priv)) {
                IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n");
-               if (priv->workqueue)
-                       queue_delayed_work(priv->workqueue,
-                                          &priv->rf_kill, 2 * HZ);
+               schedule_delayed_work(&priv->rf_kill, 2 * HZ);
                goto exit_unlock;
        }
 
@@ -10697,7 +10670,7 @@ static void ipw_rf_kill(void *adapter)
                                  "device\n");
 
                /* we can not do an adapter restart while inside an irq lock */
-               queue_work(priv->workqueue, &priv->adapter_restart);
+               schedule_work(&priv->adapter_restart);
        } else
                IPW_DEBUG_RF_KILL("HW RF Kill deactivated.  SW RF Kill still "
                                  "enabled\n");
@@ -10735,7 +10708,7 @@ static void ipw_link_up(struct ipw_priv *priv)
        notify_wx_assoc_event(priv);
 
        if (priv->config & CFG_BACKGROUND_SCAN)
-               queue_delayed_work(priv->workqueue, &priv->request_scan, HZ);
+               schedule_delayed_work(&priv->request_scan, HZ);
 }
 
 static void ipw_bg_link_up(struct work_struct *work)
@@ -10764,7 +10737,7 @@ static void ipw_link_down(struct ipw_priv *priv)
 
        if (!(priv->status & STATUS_EXIT_PENDING)) {
                /* Queue up another scan... */
-               queue_delayed_work(priv->workqueue, &priv->request_scan, 0);
+               schedule_delayed_work(&priv->request_scan, 0);
        } else
                cancel_delayed_work(&priv->scan_event);
 }
@@ -10782,7 +10755,6 @@ static int __devinit ipw_setup_deferred_work(struct ipw_priv *priv)
 {
        int ret = 0;
 
-       priv->workqueue = create_workqueue(DRV_NAME);
        init_waitqueue_head(&priv->wait_command_queue);
        init_waitqueue_head(&priv->wait_state);
 
@@ -11339,8 +11311,7 @@ static int ipw_up(struct ipw_priv *priv)
                        IPW_WARNING("Radio Frequency Kill Switch is On:\n"
                                    "Kill switch must be turned off for "
                                    "wireless networking to work.\n");
-                       queue_delayed_work(priv->workqueue, &priv->rf_kill,
-                                          2 * HZ);
+                       schedule_delayed_work(&priv->rf_kill, 2 * HZ);
                        return 0;
                }
 
@@ -11350,8 +11321,7 @@ static int ipw_up(struct ipw_priv *priv)
 
                        /* If configure to try and auto-associate, kick
                         * off a scan. */
-                       queue_delayed_work(priv->workqueue,
-                                          &priv->request_scan, 0);
+                       schedule_delayed_work(&priv->request_scan, 0);
 
                        return 0;
                }
@@ -11817,7 +11787,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
        err = request_irq(pdev->irq, ipw_isr, IRQF_SHARED, DRV_NAME, priv);
        if (err) {
                IPW_ERROR("Error allocating IRQ %d\n", pdev->irq);
-               goto out_destroy_workqueue;
+               goto out_iounmap;
        }
 
        SET_NETDEV_DEV(net_dev, &pdev->dev);
@@ -11885,9 +11855,6 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
        sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group);
       out_release_irq:
        free_irq(pdev->irq, priv);
-      out_destroy_workqueue:
-       destroy_workqueue(priv->workqueue);
-       priv->workqueue = NULL;
       out_iounmap:
        iounmap(priv->hw_base);
       out_pci_release_regions:
@@ -11930,18 +11897,31 @@ static void __devexit ipw_pci_remove(struct pci_dev *pdev)
                kfree(priv->cmdlog);
                priv->cmdlog = NULL;
        }
-       /* ipw_down will ensure that there is no more pending work
-        * in the workqueue's, so we can safely remove them now. */
-       cancel_delayed_work(&priv->adhoc_check);
-       cancel_delayed_work(&priv->gather_stats);
-       cancel_delayed_work(&priv->request_scan);
-       cancel_delayed_work(&priv->request_direct_scan);
-       cancel_delayed_work(&priv->request_passive_scan);
-       cancel_delayed_work(&priv->scan_event);
-       cancel_delayed_work(&priv->rf_kill);
-       cancel_delayed_work(&priv->scan_check);
-       destroy_workqueue(priv->workqueue);
-       priv->workqueue = NULL;
+
+       /* make sure all works are inactive */
+       cancel_delayed_work_sync(&priv->adhoc_check);
+       cancel_work_sync(&priv->associate);
+       cancel_work_sync(&priv->disassociate);
+       cancel_work_sync(&priv->system_config);
+       cancel_work_sync(&priv->rx_replenish);
+       cancel_work_sync(&priv->adapter_restart);
+       cancel_delayed_work_sync(&priv->rf_kill);
+       cancel_work_sync(&priv->up);
+       cancel_work_sync(&priv->down);
+       cancel_delayed_work_sync(&priv->request_scan);
+       cancel_delayed_work_sync(&priv->request_direct_scan);
+       cancel_delayed_work_sync(&priv->request_passive_scan);
+       cancel_delayed_work_sync(&priv->scan_event);
+       cancel_delayed_work_sync(&priv->gather_stats);
+       cancel_work_sync(&priv->abort_scan);
+       cancel_work_sync(&priv->roam);
+       cancel_delayed_work_sync(&priv->scan_check);
+       cancel_work_sync(&priv->link_up);
+       cancel_work_sync(&priv->link_down);
+       cancel_delayed_work_sync(&priv->led_link_on);
+       cancel_delayed_work_sync(&priv->led_link_off);
+       cancel_delayed_work_sync(&priv->led_act_off);
+       cancel_work_sync(&priv->merge_networks);
 
        /* Free MAC hash list for ADHOC */
        for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) {
@@ -12029,7 +12009,7 @@ static int ipw_pci_resume(struct pci_dev *pdev)
        priv->suspend_time = get_seconds() - priv->suspend_at;
 
        /* Bring the device back up */
-       queue_work(priv->workqueue, &priv->up);
+       schedule_work(&priv->up);
 
        return 0;
 }
index d7d049c..0441445 100644 (file)
@@ -1299,8 +1299,6 @@ struct ipw_priv {
        u8 direct_scan_ssid[IW_ESSID_MAX_SIZE];
        u8 direct_scan_ssid_len;
 
-       struct workqueue_struct *workqueue;
-
        struct delayed_work adhoc_check;
        struct work_struct associate;
        struct work_struct disassociate;
index a9b852b..39b6f16 100644 (file)
@@ -402,72 +402,6 @@ static void iwl3945_accumulative_statistics(struct iwl_priv *priv,
 }
 #endif
 
-/**
- * iwl3945_good_plcp_health - checks for plcp error.
- *
- * When the plcp error is exceeding the thresholds, reset the radio
- * to improve the throughput.
- */
-static bool iwl3945_good_plcp_health(struct iwl_priv *priv,
-                               struct iwl_rx_packet *pkt)
-{
-       bool rc = true;
-       struct iwl3945_notif_statistics current_stat;
-       int combined_plcp_delta;
-       unsigned int plcp_msec;
-       unsigned long plcp_received_jiffies;
-
-       if (priv->cfg->base_params->plcp_delta_threshold ==
-           IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) {
-               IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n");
-               return rc;
-       }
-       memcpy(&current_stat, pkt->u.raw, sizeof(struct
-                       iwl3945_notif_statistics));
-       /*
-        * check for plcp_err and trigger radio reset if it exceeds
-        * the plcp error threshold plcp_delta.
-        */
-       plcp_received_jiffies = jiffies;
-       plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies -
-                                       (long) priv->plcp_jiffies);
-       priv->plcp_jiffies = plcp_received_jiffies;
-       /*
-        * check to make sure plcp_msec is not 0 to prevent division
-        * by zero.
-        */
-       if (plcp_msec) {
-               combined_plcp_delta =
-                       (le32_to_cpu(current_stat.rx.ofdm.plcp_err) -
-                       le32_to_cpu(priv->_3945.statistics.rx.ofdm.plcp_err));
-
-               if ((combined_plcp_delta > 0) &&
-                       ((combined_plcp_delta * 100) / plcp_msec) >
-                       priv->cfg->base_params->plcp_delta_threshold) {
-                       /*
-                        * if plcp_err exceed the threshold, the following
-                        * data is printed in csv format:
-                        *    Text: plcp_err exceeded %d,
-                        *    Received ofdm.plcp_err,
-                        *    Current ofdm.plcp_err,
-                        *    combined_plcp_delta,
-                        *    plcp_msec
-                        */
-                       IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, "
-                               "%u, %d, %u mSecs\n",
-                               priv->cfg->base_params->plcp_delta_threshold,
-                               le32_to_cpu(current_stat.rx.ofdm.plcp_err),
-                               combined_plcp_delta, plcp_msec);
-                       /*
-                        * Reset the RF radio due to the high plcp
-                        * error rate
-                        */
-                       rc = false;
-               }
-       }
-       return rc;
-}
-
 void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
                struct iwl_rx_mem_buffer *rxb)
 {
@@ -2734,7 +2668,6 @@ static struct iwl_lib_ops iwl3945_lib = {
        .isr_ops = {
                .isr = iwl_isr_legacy,
        },
-       .check_plcp_health = iwl3945_good_plcp_health,
 
        .debugfs_ops = {
                .rx_stats_read = iwl3945_ucode_rx_stats_read,
index 3f1e5f1..91a9f52 100644 (file)
@@ -2624,6 +2624,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
        .fw_name_pre = IWL4965_FW_PRE,
        .ucode_api_max = IWL4965_UCODE_API_MAX,
        .ucode_api_min = IWL4965_UCODE_API_MIN,
+       .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
        .valid_tx_ant = ANT_AB,
        .valid_rx_ant = ANT_ABC,
        .eeprom_ver = EEPROM_4965_EEPROM_VERSION,
index 79ab0a6..537fb8c 100644 (file)
@@ -51,7 +51,7 @@
 #include "iwl-agn-debugfs.h"
 
 /* Highest firmware API version supported */
-#define IWL5000_UCODE_API_MAX 2
+#define IWL5000_UCODE_API_MAX 5
 #define IWL5150_UCODE_API_MAX 2
 
 /* Lowest firmware API version supported */
index af505bc..ef36aff 100644 (file)
@@ -681,6 +681,8 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
        .fw_name_pre = IWL6050_FW_PRE,                          \
        .ucode_api_max = IWL6050_UCODE_API_MAX,                 \
        .ucode_api_min = IWL6050_UCODE_API_MIN,                 \
+       .valid_tx_ant = ANT_AB,         /* .cfg overwrite */    \
+       .valid_rx_ant = ANT_AB,         /* .cfg overwrite */    \
        .ops = &iwl6050_ops,                                    \
        .eeprom_ver = EEPROM_6050_EEPROM_VERSION,               \
        .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,       \
index 14ceb4d..27b5a3e 100644 (file)
@@ -152,11 +152,14 @@ int iwl_eeprom_check_sku(struct iwl_priv *priv)
 
        eeprom_sku = iwl_eeprom_query16(priv, EEPROM_SKU_CAP);
 
-       priv->cfg->sku = ((eeprom_sku & EEPROM_SKU_CAP_BAND_SELECTION) >>
+       if (!priv->cfg->sku) {
+               /* not using sku overwrite */
+               priv->cfg->sku =
+                       ((eeprom_sku & EEPROM_SKU_CAP_BAND_SELECTION) >>
                        EEPROM_SKU_CAP_BAND_POS);
-       if (eeprom_sku & EEPROM_SKU_CAP_11N_ENABLE)
-               priv->cfg->sku |= IWL_SKU_N;
-
+               if (eeprom_sku & EEPROM_SKU_CAP_11N_ENABLE)
+                       priv->cfg->sku |= IWL_SKU_N;
+       }
        if (!priv->cfg->sku) {
                IWL_ERR(priv, "Invalid device sku\n");
                return -EINVAL;
index 36335b1..c1cfd99 100644 (file)
@@ -1157,6 +1157,9 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
        /* only Re-enable if disabled by irq */
        if (test_bit(STATUS_INT_ENABLED, &priv->status))
                iwl_enable_interrupts(priv);
+       /* Re-enable RF_KILL if it occurred */
+       else if (handled & CSR_INT_BIT_RF_KILL)
+               iwl_enable_rfkill_int(priv);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
        if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
@@ -1371,6 +1374,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
        /* only Re-enable if disabled by irq */
        if (test_bit(STATUS_INT_ENABLED, &priv->status))
                iwl_enable_interrupts(priv);
+       /* Re-enable RF_KILL if it occurred */
+       else if (handled & CSR_INT_BIT_RF_KILL)
+               iwl_enable_rfkill_int(priv);
 }
 
 /* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */
index 1eacba4..0494d7b 100644 (file)
@@ -199,6 +199,7 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index,
        while (i != idx) {
                u16 len;
                struct sk_buff *skb;
+               dma_addr_t dma_addr;
                desc = &ring[i];
                len = le16_to_cpu(desc->len);
                skb = rx_buf[i];
@@ -216,17 +217,20 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index,
 
                        len = priv->common.rx_mtu;
                }
+               dma_addr = le32_to_cpu(desc->host_addr);
+               pci_dma_sync_single_for_cpu(priv->pdev, dma_addr,
+                       priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE);
                skb_put(skb, len);
 
                if (p54_rx(dev, skb)) {
-                       pci_unmap_single(priv->pdev,
-                                        le32_to_cpu(desc->host_addr),
-                                        priv->common.rx_mtu + 32,
-                                        PCI_DMA_FROMDEVICE);
+                       pci_unmap_single(priv->pdev, dma_addr,
+                               priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE);
                        rx_buf[i] = NULL;
-                       desc->host_addr = 0;
+                       desc->host_addr = cpu_to_le32(0);
                } else {
                        skb_trim(skb, 0);
+                       pci_dma_sync_single_for_device(priv->pdev, dma_addr,
+                               priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE);
                        desc->len = cpu_to_le16(priv->common.rx_mtu + 32);
                }
 
index 21713a7..9b344a9 100644 (file)
@@ -98,6 +98,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
        {USB_DEVICE(0x1413, 0x5400)},   /* Telsey 802.11g USB2.0 Adapter */
        {USB_DEVICE(0x1435, 0x0427)},   /* Inventel UR054G */
        {USB_DEVICE(0x1668, 0x1050)},   /* Actiontec 802UIG-1 */
+       {USB_DEVICE(0x1740, 0x1000)},   /* Senao NUB-350 */
        {USB_DEVICE(0x2001, 0x3704)},   /* DLink DWL-G122 rev A2 */
        {USB_DEVICE(0x2001, 0x3705)},   /* D-Link DWL-G120 rev C1 */
        {USB_DEVICE(0x413c, 0x5513)},   /* Dell WLA3310 USB Wireless Adapter */
index 848cc2c..518542b 100644 (file)
@@ -2597,6 +2597,9 @@ static int rndis_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
        __le32 mode;
        int ret;
 
+       if (priv->device_type != RNDIS_BCM4320B)
+               return -ENOTSUPP;
+
        netdev_dbg(usbdev->net, "%s(): %s, %d\n", __func__,
                                enabled ? "enabled" : "disabled",
                                timeout);
index aa97971..3b3f1e4 100644 (file)
@@ -652,6 +652,12 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
                 */
                rxdesc->flags |= RX_FLAG_IV_STRIPPED;
 
+               /*
+                * The hardware has already checked the Michael Mic and has
+                * stripped it from the frame. Signal this to mac80211.
+                */
+               rxdesc->flags |= RX_FLAG_MMIC_STRIPPED;
+
                if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS)
                        rxdesc->flags |= RX_FLAG_DECRYPTED;
                else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC)
@@ -1065,6 +1071,8 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
        { PCI_DEVICE(0x1814, 0x3390), PCI_DEVICE_DATA(&rt2800pci_ops) },
 #endif
 #ifdef CONFIG_RT2800PCI_RT35XX
+       { PCI_DEVICE(0x1432, 0x7711), PCI_DEVICE_DATA(&rt2800pci_ops) },
+       { PCI_DEVICE(0x1432, 0x7722), PCI_DEVICE_DATA(&rt2800pci_ops) },
        { PCI_DEVICE(0x1814, 0x3060), PCI_DEVICE_DATA(&rt2800pci_ops) },
        { PCI_DEVICE(0x1814, 0x3062), PCI_DEVICE_DATA(&rt2800pci_ops) },
        { PCI_DEVICE(0x1814, 0x3562), PCI_DEVICE_DATA(&rt2800pci_ops) },
index b97a4a5..197a36c 100644 (file)
@@ -486,6 +486,12 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
                 */
                rxdesc->flags |= RX_FLAG_IV_STRIPPED;
 
+               /*
+                * The hardware has already checked the Michael Mic and has
+                * stripped it from the frame. Signal this to mac80211.
+                */
+               rxdesc->flags |= RX_FLAG_MMIC_STRIPPED;
+
                if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS)
                        rxdesc->flags |= RX_FLAG_DECRYPTED;
                else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC)
index 0b4e859..029be3c 100644 (file)
@@ -2446,6 +2446,7 @@ static struct usb_device_id rt73usb_device_table[] = {
        { USB_DEVICE(0x04bb, 0x093d), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x148f, 0x2671), USB_DEVICE_DATA(&rt73usb_ops) },
+       { USB_DEVICE(0x0812, 0x3101), USB_DEVICE_DATA(&rt73usb_ops) },
        /* Qcom */
        { USB_DEVICE(0x18e8, 0x6196), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x18e8, 0x6229), USB_DEVICE_DATA(&rt73usb_ops) },
index b8433f3..62876cd 100644 (file)
@@ -726,9 +726,9 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data)
 }
 
 static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
-                               u8 efuse_data, u8 offset, int *bcontinual,
-                               u8 *write_state, struct pgpkt_struct target_pkt,
-                               int *repeat_times, int *bresult, u8 word_en)
+                       u8 efuse_data, u8 offset, int *bcontinual,
+                       u8 *write_state, struct pgpkt_struct *target_pkt,
+                       int *repeat_times, int *bresult, u8 word_en)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct pgpkt_struct tmp_pkt;
@@ -744,8 +744,8 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
        tmp_pkt.word_en = tmp_header & 0x0F;
        tmp_word_cnts = efuse_calculate_word_cnts(tmp_pkt.word_en);
 
-       if (tmp_pkt.offset != target_pkt.offset) {
-               efuse_addr = efuse_addr + (tmp_word_cnts * 2) + 1;
+       if (tmp_pkt.offset != target_pkt->offset) {
+               *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1;
                *write_state = PG_STATE_HEADER;
        } else {
                for (tmpindex = 0; tmpindex < (tmp_word_cnts * 2); tmpindex++) {
@@ -756,23 +756,23 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
                }
 
                if (bdataempty == false) {
-                       efuse_addr = efuse_addr + (tmp_word_cnts * 2) + 1;
+                       *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1;
                        *write_state = PG_STATE_HEADER;
                } else {
                        match_word_en = 0x0F;
-                       if (!((target_pkt.word_en & BIT(0)) |
+                       if (!((target_pkt->word_en & BIT(0)) |
                             (tmp_pkt.word_en & BIT(0))))
                                match_word_en &= (~BIT(0));
 
-                       if (!((target_pkt.word_en & BIT(1)) |
+                       if (!((target_pkt->word_en & BIT(1)) |
                             (tmp_pkt.word_en & BIT(1))))
                                match_word_en &= (~BIT(1));
 
-                       if (!((target_pkt.word_en & BIT(2)) |
+                       if (!((target_pkt->word_en & BIT(2)) |
                             (tmp_pkt.word_en & BIT(2))))
                                match_word_en &= (~BIT(2));
 
-                       if (!((target_pkt.word_en & BIT(3)) |
+                       if (!((target_pkt->word_en & BIT(3)) |
                             (tmp_pkt.word_en & BIT(3))))
                                match_word_en &= (~BIT(3));
 
@@ -780,7 +780,7 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
                                badworden = efuse_word_enable_data_write(
                                                            hw, *efuse_addr + 1,
                                                            tmp_pkt.word_en,
-                                                           target_pkt.data);
+                                                           target_pkt->data);
 
                                if (0x0F != (badworden & 0x0F)) {
                                        u8 reorg_offset = offset;
@@ -791,26 +791,26 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
                                }
 
                                tmp_word_en = 0x0F;
-                               if ((target_pkt.word_en & BIT(0)) ^
+                               if ((target_pkt->word_en & BIT(0)) ^
                                    (match_word_en & BIT(0)))
                                        tmp_word_en &= (~BIT(0));
 
-                               if ((target_pkt.word_en & BIT(1)) ^
+                               if ((target_pkt->word_en & BIT(1)) ^
                                    (match_word_en & BIT(1)))
                                        tmp_word_en &= (~BIT(1));
 
-                               if ((target_pkt.word_en & BIT(2)) ^
+                               if ((target_pkt->word_en & BIT(2)) ^
                                        (match_word_en & BIT(2)))
                                        tmp_word_en &= (~BIT(2));
 
-                               if ((target_pkt.word_en & BIT(3)) ^
+                               if ((target_pkt->word_en & BIT(3)) ^
                                    (match_word_en & BIT(3)))
                                        tmp_word_en &= (~BIT(3));
 
                                if ((tmp_word_en & 0x0F) != 0x0F) {
                                        *efuse_addr = efuse_get_current_size(hw);
-                                       target_pkt.offset = offset;
-                                       target_pkt.word_en = tmp_word_en;
+                                       target_pkt->offset = offset;
+                                       target_pkt->word_en = tmp_word_en;
                                } else
                                        *bcontinual = false;
                                *write_state = PG_STATE_HEADER;
@@ -821,8 +821,8 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
                                }
                        } else {
                                *efuse_addr += (2 * tmp_word_cnts) + 1;
-                               target_pkt.offset = offset;
-                               target_pkt.word_en = word_en;
+                               target_pkt->offset = offset;
+                               target_pkt->word_en = word_en;
                                *write_state = PG_STATE_HEADER;
                        }
                }
@@ -938,7 +938,7 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw,
                                efuse_write_data_case1(hw, &efuse_addr,
                                                       efuse_data, offset,
                                                       &bcontinual,
-                                                      &write_state, target_pkt,
+                                                      &write_state, &target_pkt,
                                                       &repeat_times, &bresult,
                                                       word_en);
                        else
index 0fa36aa..1758d44 100644 (file)
@@ -619,6 +619,13 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
                                        struct sk_buff *uskb = NULL;
                                        u8 *pdata;
                                        uskb = dev_alloc_skb(skb->len + 128);
+                                       if (!uskb) {
+                                               RT_TRACE(rtlpriv,
+                                                       (COMP_INTR | COMP_RECV),
+                                                       DBG_EMERG,
+                                                       ("can't alloc rx skb\n"));
+                                               goto done;
+                                       }
                                        memcpy(IEEE80211_SKB_RXCB(uskb),
                                                        &rx_status,
                                                        sizeof(rx_status));
@@ -641,7 +648,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
                        new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
                        if (unlikely(!new_skb)) {
                                RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV),
-                                        DBG_DMESG,
+                                        DBG_EMERG,
                                         ("can't alloc skb for rx\n"));
                                goto done;
                        }
@@ -1066,9 +1073,9 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw)
                        struct sk_buff *skb =
                            dev_alloc_skb(rtlpci->rxbuffersize);
                        u32 bufferaddress;
-                       entry = &rtlpci->rx_ring[rx_queue_idx].desc[i];
                        if (!skb)
                                return 0;
+                       entry = &rtlpci->rx_ring[rx_queue_idx].desc[i];
 
                        /*skb->dev = dev; */
 
index 012e1a4..40372ba 100644 (file)
@@ -1039,6 +1039,9 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
 
        if (changed & BSS_CHANGED_BEACON) {
                beacon = ieee80211_beacon_get(hw, vif);
+               if (!beacon)
+                       goto out_sleep;
+
                ret = wl1251_cmd_template_set(wl, CMD_BEACON, beacon->data,
                                              beacon->len);
 
index 4671491..7145ea5 100644 (file)
@@ -110,9 +110,8 @@ static void wl1271_spi_reset(struct wl1271 *wl)
        spi_message_add_tail(&t, &m);
 
        spi_sync(wl_to_spi(wl), &m);
-       kfree(cmd);
-
        wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
+       kfree(cmd);
 }
 
 static void wl1271_spi_init(struct wl1271 *wl)
index 546de57..da1f121 100644 (file)
@@ -120,6 +120,9 @@ struct netfront_info {
        unsigned long rx_pfn_array[NET_RX_RING_SIZE];
        struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1];
        struct mmu_update rx_mmu[NET_RX_RING_SIZE];
+
+       /* Statistics */
+       int rx_gso_checksum_fixup;
 };
 
 struct netfront_rx_info {
@@ -770,11 +773,29 @@ static RING_IDX xennet_fill_frags(struct netfront_info *np,
        return cons;
 }
 
-static int skb_checksum_setup(struct sk_buff *skb)
+static int checksum_setup(struct net_device *dev, struct sk_buff *skb)
 {
        struct iphdr *iph;
        unsigned char *th;
        int err = -EPROTO;
+       int recalculate_partial_csum = 0;
+
+       /*
+        * A GSO SKB must be CHECKSUM_PARTIAL. However some buggy
+        * peers can fail to set NETRXF_csum_blank when sending a GSO
+        * frame. In this case force the SKB to CHECKSUM_PARTIAL and
+        * recalculate the partial checksum.
+        */
+       if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) {
+               struct netfront_info *np = netdev_priv(dev);
+               np->rx_gso_checksum_fixup++;
+               skb->ip_summed = CHECKSUM_PARTIAL;
+               recalculate_partial_csum = 1;
+       }
+
+       /* A non-CHECKSUM_PARTIAL SKB does not require setup. */
+       if (skb->ip_summed != CHECKSUM_PARTIAL)
+               return 0;
 
        if (skb->protocol != htons(ETH_P_IP))
                goto out;
@@ -788,9 +809,23 @@ static int skb_checksum_setup(struct sk_buff *skb)
        switch (iph->protocol) {
        case IPPROTO_TCP:
                skb->csum_offset = offsetof(struct tcphdr, check);
+
+               if (recalculate_partial_csum) {
+                       struct tcphdr *tcph = (struct tcphdr *)th;
+                       tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
+                                                        skb->len - iph->ihl*4,
+                                                        IPPROTO_TCP, 0);
+               }
                break;
        case IPPROTO_UDP:
                skb->csum_offset = offsetof(struct udphdr, check);
+
+               if (recalculate_partial_csum) {
+                       struct udphdr *udph = (struct udphdr *)th;
+                       udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
+                                                        skb->len - iph->ihl*4,
+                                                        IPPROTO_UDP, 0);
+               }
                break;
        default:
                if (net_ratelimit())
@@ -829,13 +864,11 @@ static int handle_incoming_queue(struct net_device *dev,
                /* Ethernet work: Delayed to here as it peeks the header. */
                skb->protocol = eth_type_trans(skb, dev);
 
-               if (skb->ip_summed == CHECKSUM_PARTIAL) {
-                       if (skb_checksum_setup(skb)) {
-                               kfree_skb(skb);
-                               packets_dropped++;
-                               dev->stats.rx_errors++;
-                               continue;
-                       }
+               if (checksum_setup(dev, skb)) {
+                       kfree_skb(skb);
+                       packets_dropped++;
+                       dev->stats.rx_errors++;
+                       continue;
                }
 
                dev->stats.rx_packets++;
@@ -1632,12 +1665,59 @@ static void netback_changed(struct xenbus_device *dev,
        }
 }
 
+static const struct xennet_stat {
+       char name[ETH_GSTRING_LEN];
+       u16 offset;
+} xennet_stats[] = {
+       {
+               "rx_gso_checksum_fixup",
+               offsetof(struct netfront_info, rx_gso_checksum_fixup)
+       },
+};
+
+static int xennet_get_sset_count(struct net_device *dev, int string_set)
+{
+       switch (string_set) {
+       case ETH_SS_STATS:
+               return ARRAY_SIZE(xennet_stats);
+       default:
+               return -EINVAL;
+       }
+}
+
+static void xennet_get_ethtool_stats(struct net_device *dev,
+                                    struct ethtool_stats *stats, u64 * data)
+{
+       void *np = netdev_priv(dev);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(xennet_stats); i++)
+               data[i] = *(int *)(np + xennet_stats[i].offset);
+}
+
+static void xennet_get_strings(struct net_device *dev, u32 stringset, u8 * data)
+{
+       int i;
+
+       switch (stringset) {
+       case ETH_SS_STATS:
+               for (i = 0; i < ARRAY_SIZE(xennet_stats); i++)
+                       memcpy(data + i * ETH_GSTRING_LEN,
+                              xennet_stats[i].name, ETH_GSTRING_LEN);
+               break;
+       }
+}
+
 static const struct ethtool_ops xennet_ethtool_ops =
 {
        .set_tx_csum = ethtool_op_set_tx_csum,
        .set_sg = xennet_set_sg,
        .set_tso = xennet_set_tso,
        .get_link = ethtool_op_get_link,
+
+       .get_sset_count = xennet_get_sset_count,
+       .get_ethtool_stats = xennet_get_ethtool_stats,
+       .get_strings = xennet_get_strings,
 };
 
 #ifdef CONFIG_SYSFS
index ffedfd4..ea15800 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 menuconfig NFC_DEVICES
-       bool "NFC devices"
+       bool "Near Field Communication (NFC) devices"
        default n
        ---help---
          You'll have to say Y if your computer contains an NFC device that
index bae6472..724f65d 100644 (file)
@@ -60,7 +60,7 @@ enum pn544_irq {
 struct pn544_info {
        struct miscdevice miscdev;
        struct i2c_client *i2c_dev;
-       struct regulator_bulk_data regs[2];
+       struct regulator_bulk_data regs[3];
 
        enum pn544_state state;
        wait_queue_head_t read_wait;
@@ -74,6 +74,7 @@ struct pn544_info {
 
 static const char reg_vdd_io[] = "Vdd_IO";
 static const char reg_vbat[]   = "VBat";
+static const char reg_vsim[]   = "VSim";
 
 /* sysfs interface */
 static ssize_t pn544_test(struct device *dev,
@@ -740,6 +741,7 @@ static int __devinit pn544_probe(struct i2c_client *client,
 
        info->regs[0].supply = reg_vdd_io;
        info->regs[1].supply = reg_vbat;
+       info->regs[2].supply = reg_vsim;
        r = regulator_bulk_get(&client->dev, ARRAY_SIZE(info->regs),
                                 info->regs);
        if (r < 0)
index 3c6e100..d06a637 100644 (file)
@@ -69,4 +69,10 @@ config OF_MDIO
        help
          OpenFirmware MDIO bus (Ethernet PHY) accessors
 
+config OF_PCI
+       def_tristate PCI
+       depends on PCI && (PPC || MICROBLAZE || X86)
+       help
+         OpenFirmware PCI bus accessors
+
 endmenu # OF
index 3ab21a0..f7861ed 100644 (file)
@@ -9,3 +9,4 @@ obj-$(CONFIG_OF_I2C)    += of_i2c.o
 obj-$(CONFIG_OF_NET)   += of_net.o
 obj-$(CONFIG_OF_SPI)   += of_spi.o
 obj-$(CONFIG_OF_MDIO)  += of_mdio.o
+obj-$(CONFIG_OF_PCI)   += of_pci.o
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
new file mode 100644 (file)
index 0000000..ac1ec54
--- /dev/null
@@ -0,0 +1,92 @@
+#include <linux/kernel.h>
+#include <linux/of_pci.h>
+#include <linux/of_irq.h>
+#include <asm/prom.h>
+
+/**
+ * of_irq_map_pci - Resolve the interrupt for a PCI device
+ * @pdev:       the device whose interrupt is to be resolved
+ * @out_irq:    structure of_irq filled by this function
+ *
+ * This function resolves the PCI interrupt for a given PCI device. If a
+ * device-node exists for a given pci_dev, it will use normal OF tree
+ * walking. If not, it will implement standard swizzling and walk up the
+ * PCI tree until an device-node is found, at which point it will finish
+ * resolving using the OF tree walking.
+ */
+int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
+{
+       struct device_node *dn, *ppnode;
+       struct pci_dev *ppdev;
+       u32 lspec;
+       __be32 lspec_be;
+       __be32 laddr[3];
+       u8 pin;
+       int rc;
+
+       /* Check if we have a device node, if yes, fallback to standard
+        * device tree parsing
+        */
+       dn = pci_device_to_OF_node(pdev);
+       if (dn) {
+               rc = of_irq_map_one(dn, 0, out_irq);
+               if (!rc)
+                       return rc;
+       }
+
+       /* Ok, we don't, time to have fun. Let's start by building up an
+        * interrupt spec.  we assume #interrupt-cells is 1, which is standard
+        * for PCI. If you do different, then don't use that routine.
+        */
+       rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin);
+       if (rc != 0)
+               return rc;
+       /* No pin, exit */
+       if (pin == 0)
+               return -ENODEV;
+
+       /* Now we walk up the PCI tree */
+       lspec = pin;
+       for (;;) {
+               /* Get the pci_dev of our parent */
+               ppdev = pdev->bus->self;
+
+               /* Ouch, it's a host bridge... */
+               if (ppdev == NULL) {
+                       ppnode = pci_bus_to_OF_node(pdev->bus);
+
+                       /* No node for host bridge ? give up */
+                       if (ppnode == NULL)
+                               return -EINVAL;
+               } else {
+                       /* We found a P2P bridge, check if it has a node */
+                       ppnode = pci_device_to_OF_node(ppdev);
+               }
+
+               /* Ok, we have found a parent with a device-node, hand over to
+                * the OF parsing code.
+                * We build a unit address from the linux device to be used for
+                * resolution. Note that we use the linux bus number which may
+                * not match your firmware bus numbering.
+                * Fortunately, in most cases, interrupt-map-mask doesn't
+                * include the bus number as part of the matching.
+                * You should still be careful about that though if you intend
+                * to rely on this function (you ship  a firmware that doesn't
+                * create device nodes for all PCI devices).
+                */
+               if (ppnode)
+                       break;
+
+               /* We can only get here if we hit a P2P bridge with no node,
+                * let's do standard swizzling and try again
+                */
+               lspec = pci_swizzle_interrupt_pin(pdev, lspec);
+               pdev = ppdev;
+       }
+
+       lspec_be = cpu_to_be32(lspec);
+       laddr[0] = cpu_to_be32((pdev->bus->number << 16) | (pdev->devfn << 8));
+       laddr[1]  = laddr[2] = cpu_to_be32(0);
+       return of_irq_map_raw(ppnode, &lspec_be, 1, laddr, out_irq);
+}
+EXPORT_SYMBOL_GPL(of_irq_map_pci);
index 28295d0..4d87b5d 100644 (file)
@@ -36,19 +36,55 @@ unsigned int of_pdt_unique_id __initdata;
        (p)->unique_id = of_pdt_unique_id++; \
 } while (0)
 
-static inline const char *of_pdt_node_name(struct device_node *dp)
+static char * __init of_pdt_build_full_name(struct device_node *dp)
 {
-       return dp->path_component_name;
+       int len, ourlen, plen;
+       char *n;
+
+       dp->path_component_name = build_path_component(dp);
+
+       plen = strlen(dp->parent->full_name);
+       ourlen = strlen(dp->path_component_name);
+       len = ourlen + plen + 2;
+
+       n = prom_early_alloc(len);
+       strcpy(n, dp->parent->full_name);
+       if (!of_node_is_root(dp->parent)) {
+               strcpy(n + plen, "/");
+               plen++;
+       }
+       strcpy(n + plen, dp->path_component_name);
+
+       return n;
 }
 
-#else
+#else /* CONFIG_SPARC */
 
 static inline void of_pdt_incr_unique_id(void *p) { }
 static inline void irq_trans_init(struct device_node *dp) { }
 
-static inline const char *of_pdt_node_name(struct device_node *dp)
+static char * __init of_pdt_build_full_name(struct device_node *dp)
 {
-       return dp->name;
+       static int failsafe_id = 0; /* for generating unique names on failure */
+       char *buf;
+       int len;
+
+       if (of_pdt_prom_ops->pkg2path(dp->phandle, NULL, 0, &len))
+               goto failsafe;
+
+       buf = prom_early_alloc(len + 1);
+       if (of_pdt_prom_ops->pkg2path(dp->phandle, buf, len, &len))
+               goto failsafe;
+       return buf;
+
+ failsafe:
+       buf = prom_early_alloc(strlen(dp->parent->full_name) +
+                              strlen(dp->name) + 16);
+       sprintf(buf, "%s/%s@unknown%i",
+               of_node_is_root(dp->parent) ? "" : dp->parent->full_name,
+               dp->name, failsafe_id++);
+       pr_err("%s: pkg2path failed; assigning %s\n", __func__, buf);
+       return buf;
 }
 
 #endif /* !CONFIG_SPARC */
@@ -132,47 +168,6 @@ static char * __init of_pdt_get_one_property(phandle node, const char *name)
        return buf;
 }
 
-static char * __init of_pdt_try_pkg2path(phandle node)
-{
-       char *res, *buf = NULL;
-       int len;
-
-       if (!of_pdt_prom_ops->pkg2path)
-               return NULL;
-
-       if (of_pdt_prom_ops->pkg2path(node, buf, 0, &len))
-               return NULL;
-       buf = prom_early_alloc(len + 1);
-       if (of_pdt_prom_ops->pkg2path(node, buf, len, &len)) {
-               pr_err("%s: package-to-path failed\n", __func__);
-               return NULL;
-       }
-
-       res = strrchr(buf, '/');
-       if (!res) {
-               pr_err("%s: couldn't find / in %s\n", __func__, buf);
-               return NULL;
-       }
-       return res+1;
-}
-
-/*
- * When fetching the node's name, first try using package-to-path; if
- * that fails (either because the arch hasn't supplied a PROM callback,
- * or some other random failure), fall back to just looking at the node's
- * 'name' property.
- */
-static char * __init of_pdt_build_name(phandle node)
-{
-       char *buf;
-
-       buf = of_pdt_try_pkg2path(node);
-       if (!buf)
-               buf = of_pdt_get_one_property(node, "name");
-
-       return buf;
-}
-
 static struct device_node * __init of_pdt_create_node(phandle node,
                                                    struct device_node *parent)
 {
@@ -187,7 +182,7 @@ static struct device_node * __init of_pdt_create_node(phandle node,
 
        kref_init(&dp->kref);
 
-       dp->name = of_pdt_build_name(node);
+       dp->name = of_pdt_get_one_property(node, "name");
        dp->type = of_pdt_get_one_property(node, "device_type");
        dp->phandle = node;
 
@@ -198,26 +193,6 @@ static struct device_node * __init of_pdt_create_node(phandle node,
        return dp;
 }
 
-static char * __init of_pdt_build_full_name(struct device_node *dp)
-{
-       int len, ourlen, plen;
-       char *n;
-
-       plen = strlen(dp->parent->full_name);
-       ourlen = strlen(of_pdt_node_name(dp));
-       len = ourlen + plen + 2;
-
-       n = prom_early_alloc(len);
-       strcpy(n, dp->parent->full_name);
-       if (!of_node_is_root(dp->parent)) {
-               strcpy(n + plen, "/");
-               plen++;
-       }
-       strcpy(n + plen, of_pdt_node_name(dp));
-
-       return n;
-}
-
 static struct device_node * __init of_pdt_build_tree(struct device_node *parent,
                                                   phandle node,
                                                   struct device_node ***nextp)
@@ -240,9 +215,6 @@ static struct device_node * __init of_pdt_build_tree(struct device_node *parent,
                *(*nextp) = dp;
                *nextp = &dp->allnext;
 
-#if defined(CONFIG_SPARC)
-               dp->path_component_name = build_path_component(dp);
-#endif
                dp->full_name = of_pdt_build_full_name(dp);
 
                dp->child = of_pdt_build_tree(dp,
index a2d9d1e..a848e02 100644 (file)
@@ -678,7 +678,7 @@ void parport_unregister_device(struct pardevice *dev)
 
        /* Make sure we haven't left any pointers around in the wait
         * list. */
-       spin_lock (&port->waitlist_lock);
+       spin_lock_irq(&port->waitlist_lock);
        if (dev->waitprev || dev->waitnext || port->waithead == dev) {
                if (dev->waitprev)
                        dev->waitprev->waitnext = dev->waitnext;
@@ -689,7 +689,7 @@ void parport_unregister_device(struct pardevice *dev)
                else
                        port->waittail = dev->waitprev;
        }
-       spin_unlock (&port->waitlist_lock);
+       spin_unlock_irq(&port->waitlist_lock);
 
        kfree(dev->state);
        kfree(dev);
index 8ecaac9..ea25e5b 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/capability.h>
+#include <linux/security.h>
 #include <linux/pci-aspm.h>
 #include <linux/slab.h>
 #include "pci.h"
@@ -368,7 +369,7 @@ pci_read_config(struct file *filp, struct kobject *kobj,
        u8 *data = (u8*) buf;
 
        /* Several chips lock up trying to read undefined config space */
-       if (cap_raised(filp->f_cred->cap_effective, CAP_SYS_ADMIN)) {
+       if (security_capable(filp->f_cred, CAP_SYS_ADMIN) == 0) {
                size = dev->cfg_size;
        } else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
                size = 128;
index 3a5a6fc..492b7d8 100644 (file)
@@ -243,7 +243,7 @@ struct pci_ops pcifront_bus_ops = {
 
 #ifdef CONFIG_PCI_MSI
 static int pci_frontend_enable_msix(struct pci_dev *dev,
-                                   int **vector, int nvec)
+                                   int vector[], int nvec)
 {
        int err;
        int i;
@@ -277,18 +277,24 @@ static int pci_frontend_enable_msix(struct pci_dev *dev,
        if (likely(!err)) {
                if (likely(!op.value)) {
                        /* we get the result */
-                       for (i = 0; i < nvec; i++)
-                               *(*vector+i) = op.msix_entries[i].vector;
-                       return 0;
+                       for (i = 0; i < nvec; i++) {
+                               if (op.msix_entries[i].vector <= 0) {
+                                       dev_warn(&dev->dev, "MSI-X entry %d is invalid: %d!\n",
+                                               i, op.msix_entries[i].vector);
+                                       err = -EINVAL;
+                                       vector[i] = -1;
+                                       continue;
+                               }
+                               vector[i] = op.msix_entries[i].vector;
+                       }
                } else {
                        printk(KERN_DEBUG "enable msix get value %x\n",
                                op.value);
-                       return op.value;
                }
        } else {
                dev_err(&dev->dev, "enable msix get err %x\n", err);
-               return err;
        }
+       return err;
 }
 
 static void pci_frontend_disable_msix(struct pci_dev *dev)
@@ -310,7 +316,7 @@ static void pci_frontend_disable_msix(struct pci_dev *dev)
                dev_err(&dev->dev, "pci_disable_msix get err %x\n", err);
 }
 
-static int pci_frontend_enable_msi(struct pci_dev *dev, int **vector)
+static int pci_frontend_enable_msi(struct pci_dev *dev, int vector[])
 {
        int err;
        struct xen_pci_op op = {
@@ -324,7 +330,13 @@ static int pci_frontend_enable_msi(struct pci_dev *dev, int **vector)
 
        err = do_pci_op(pdev, &op);
        if (likely(!err)) {
-               *(*vector) = op.value;
+               vector[0] = op.value;
+               if (op.value <= 0) {
+                       dev_warn(&dev->dev, "MSI entry is invalid: %d!\n",
+                               op.value);
+                       err = -EINVAL;
+                       vector[0] = -1;
+               }
        } else {
                dev_err(&dev->dev, "pci frontend enable msi failed for dev "
                                    "%x:%x\n", op.bus, op.devfn);
@@ -733,8 +745,7 @@ static void free_pdev(struct pcifront_device *pdev)
 
        pcifront_free_roots(pdev);
 
-       /*For PCIE_AER error handling job*/
-       flush_scheduled_work();
+       cancel_work_sync(&pdev->op_work);
 
        if (pdev->irq >= 0)
                unbind_from_irqhandler(pdev->irq, pdev);
index 0bdda5b..42fbf1a 100644 (file)
@@ -518,6 +518,8 @@ int pcmcia_enable_device(struct pcmcia_device *p_dev)
                flags |= CONF_ENABLE_IOCARD;
        if (flags & CONF_ENABLE_IOCARD)
                s->socket.flags |= SS_IOCARD;
+       if (flags & CONF_ENABLE_ZVCARD)
+               s->socket.flags |= SS_ZVCARD | SS_IOCARD;
        if (flags & CONF_ENABLE_SPKR) {
                s->socket.flags |= SS_SPKR_ENA;
                status = CCSR_AUDIO_ENA;
index 3755e7c..2c54054 100644 (file)
@@ -215,7 +215,7 @@ pxa2xx_pcmcia_frequency_change(struct soc_pcmcia_socket *skt,
 }
 #endif
 
-static void pxa2xx_configure_sockets(struct device *dev)
+void pxa2xx_configure_sockets(struct device *dev)
 {
        struct pcmcia_low_level *ops = dev->platform_data;
        /*
index bb62ea8..b609b45 100644 (file)
@@ -1,3 +1,4 @@
 int pxa2xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt);
 void pxa2xx_drv_pcmcia_ops(struct pcmcia_low_level *ops);
+void pxa2xx_configure_sockets(struct device *dev);
 
index c3f7219..a520395 100644 (file)
@@ -181,6 +181,9 @@ static int __init colibri_pcmcia_init(void)
 {
        int ret;
 
+       if (!machine_is_colibri() && !machine_is_colibri320())
+               return -ENODEV;
+
        colibri_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
        if (!colibri_pcmcia_device)
                return -ENOMEM;
index b9f8c8f..25afe63 100644 (file)
@@ -226,6 +226,7 @@ int pcmcia_lubbock_init(struct sa1111_dev *sadev)
                lubbock_set_misc_wr((1 << 15) | (1 << 14), 0);
 
                pxa2xx_drv_pcmcia_ops(&lubbock_pcmcia_ops);
+               pxa2xx_configure_sockets(&sadev->dev);
                ret = sa1111_pcmcia_add(sadev, &lubbock_pcmcia_ops,
                                pxa2xx_drv_pcmcia_add_one);
        }
index d163bc2..a59af5b 100644 (file)
@@ -227,7 +227,7 @@ config SONYPI_COMPAT
 config IDEAPAD_LAPTOP
        tristate "Lenovo IdeaPad Laptop Extras"
        depends on ACPI
-       depends on RFKILL
+       depends on RFKILL && INPUT
        select INPUT_SPARSEKMAP
        help
          This is a driver for the rfkill switches on Lenovo IdeaPad netbooks.
index c5c4b8c..38b34a7 100644 (file)
@@ -84,7 +84,7 @@ MODULE_LICENSE("GPL");
  */
 #define AMW0_GUID1             "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
 #define AMW0_GUID2             "431F16ED-0C2B-444C-B267-27DEB140CF9C"
-#define WMID_GUID1             "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
+#define WMID_GUID1             "6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3"
 #define WMID_GUID2             "95764E09-FB56-4e83-B31A-37761F60994A"
 #define WMID_GUID3             "61EF69EA-865C-4BC3-A502-A0DEBA0CB531"
 
@@ -1280,7 +1280,7 @@ static ssize_t set_bool_threeg(struct device *dev,
                        return -EINVAL;
        return count;
 }
-static DEVICE_ATTR(threeg, S_IWUGO | S_IRUGO | S_IWUSR, show_bool_threeg,
+static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg,
        set_bool_threeg);
 
 static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
index 4633fd8..fe49593 100644 (file)
@@ -1081,14 +1081,8 @@ static int asus_hotk_add_fs(struct acpi_device *device)
        struct proc_dir_entry *proc;
        mode_t mode;
 
-       /*
-        * If parameter uid or gid is not changed, keep the default setting for
-        * our proc entries (-rw-rw-rw-) else, it means we care about security,
-        * and then set to -rw-rw----
-        */
-
        if ((asus_uid == 0) && (asus_gid == 0)) {
-               mode = S_IFREG | S_IRUGO | S_IWUGO;
+               mode = S_IFREG | S_IRUGO | S_IWUSR | S_IWGRP;
        } else {
                mode = S_IFREG | S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP;
                printk(KERN_WARNING "  asus_uid and asus_gid parameters are "
index 34657f9..ad24ef3 100644 (file)
@@ -290,9 +290,12 @@ static int dell_rfkill_set(void *data, bool blocked)
        dell_send_request(buffer, 17, 11);
 
        /* If the hardware switch controls this radio, and the hardware
-          switch is disabled, don't allow changing the software state */
+          switch is disabled, don't allow changing the software state.
+          If the hardware switch is reported as not supported, always
+          fire the SMI to toggle the killswitch. */
        if ((hwswitch_state & BIT(hwswitch_bit)) &&
-           !(buffer->output[1] & BIT(16))) {
+           !(buffer->output[1] & BIT(16)) &&
+           (buffer->output[1] & BIT(0))) {
                ret = -EINVAL;
                goto out;
        }
@@ -398,6 +401,23 @@ static const struct file_operations dell_debugfs_fops = {
 
 static void dell_update_rfkill(struct work_struct *ignored)
 {
+       int status;
+
+       get_buffer();
+       dell_send_request(buffer, 17, 11);
+       status = buffer->output[1];
+       release_buffer();
+
+       /* if hardware rfkill is not supported, set it explicitly */
+       if (!(status & BIT(0))) {
+               if (wifi_rfkill)
+                       dell_rfkill_set((void *)1, !((status & BIT(17)) >> 17));
+               if (bluetooth_rfkill)
+                       dell_rfkill_set((void *)2, !((status & BIT(18)) >> 18));
+               if (wwan_rfkill)
+                       dell_rfkill_set((void *)3, !((status & BIT(19)) >> 19));
+       }
+
        if (wifi_rfkill)
                dell_rfkill_query(wifi_rfkill, (void *)1);
        if (bluetooth_rfkill)
index 930e627..61433d4 100644 (file)
@@ -60,69 +60,20 @@ enum pmic_gpio_register {
 #define GPOSW_DOU 0x08
 #define GPOSW_RDRV 0x30
 
+#define GPIO_UPDATE_TYPE       0x80000000
 
 #define NUM_GPIO 24
 
-struct pmic_gpio_irq {
-       spinlock_t lock;
-       u32 trigger[NUM_GPIO];
-       u32 dirty;
-       struct work_struct work;
-};
-
-
 struct pmic_gpio {
+       struct mutex            buslock;
        struct gpio_chip        chip;
-       struct pmic_gpio_irq    irqtypes;
        void                    *gpiointr;
        int                     irq;
        unsigned                irq_base;
+       unsigned int            update_type;
+       u32                     trigger_type;
 };
 
-static void pmic_program_irqtype(int gpio, int type)
-{
-       if (type & IRQ_TYPE_EDGE_RISING)
-               intel_scu_ipc_update_register(GPIO0 + gpio, 0x20, 0x20);
-       else
-               intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x20);
-
-       if (type & IRQ_TYPE_EDGE_FALLING)
-               intel_scu_ipc_update_register(GPIO0 + gpio, 0x10, 0x10);
-       else
-               intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x10);
-};
-
-static void pmic_irqtype_work(struct work_struct *work)
-{
-       struct pmic_gpio_irq *t =
-               container_of(work, struct pmic_gpio_irq, work);
-       unsigned long flags;
-       int i;
-       u16 type;
-
-       spin_lock_irqsave(&t->lock, flags);
-       /* As we drop the lock, we may need multiple scans if we race the
-          pmic_irq_type function */
-       while (t->dirty) {
-               /*
-                *      For each pin that has the dirty bit set send an IPC
-                *      message to configure the hardware via the PMIC
-                */
-               for (i = 0; i < NUM_GPIO; i++) {
-                       if (!(t->dirty & (1 << i)))
-                               continue;
-                       t->dirty &= ~(1 << i);
-                       /* We can't trust the array entry or dirty
-                          once the lock is dropped */
-                       type = t->trigger[i];
-                       spin_unlock_irqrestore(&t->lock, flags);
-                       pmic_program_irqtype(i, type);
-                       spin_lock_irqsave(&t->lock, flags);
-               }
-       }
-       spin_unlock_irqrestore(&t->lock, flags);
-}
-
 static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
        if (offset > 8) {
@@ -190,25 +141,24 @@ static void pmic_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
                        1 << (offset - 16));
 }
 
-static int pmic_irq_type(unsigned irq, unsigned type)
+/*
+ * This is called from genirq with pg->buslock locked and
+ * irq_desc->lock held. We can not access the scu bus here, so we
+ * store the change and update in the bus_sync_unlock() function below
+ */
+static int pmic_irq_type(struct irq_data *data, unsigned type)
 {
-       struct pmic_gpio *pg = get_irq_chip_data(irq);
-       u32 gpio = irq - pg->irq_base;
-       unsigned long flags;
+       struct pmic_gpio *pg = irq_data_get_irq_chip_data(data);
+       u32 gpio = data->irq - pg->irq_base;
 
        if (gpio >= pg->chip.ngpio)
                return -EINVAL;
 
-       spin_lock_irqsave(&pg->irqtypes.lock, flags);
-       pg->irqtypes.trigger[gpio] = type;
-       pg->irqtypes.dirty |=  (1 << gpio);
-       spin_unlock_irqrestore(&pg->irqtypes.lock, flags);
-       schedule_work(&pg->irqtypes.work);
+       pg->trigger_type = type;
+       pg->update_type = gpio | GPIO_UPDATE_TYPE;
        return 0;
 }
 
-
-
 static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
        struct pmic_gpio *pg = container_of(chip, struct pmic_gpio, chip);
@@ -217,38 +167,32 @@ static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 }
 
 /* the gpiointr register is read-clear, so just do nothing. */
-static void pmic_irq_unmask(unsigned irq)
-{
-};
+static void pmic_irq_unmask(struct irq_data *data) { }
 
-static void pmic_irq_mask(unsigned irq)
-{
-};
+static void pmic_irq_mask(struct irq_data *data) { }
 
 static struct irq_chip pmic_irqchip = {
        .name           = "PMIC-GPIO",
-       .mask           = pmic_irq_mask,
-       .unmask         = pmic_irq_unmask,
-       .set_type       = pmic_irq_type,
+       .irq_mask       = pmic_irq_mask,
+       .irq_unmask     = pmic_irq_unmask,
+       .irq_set_type   = pmic_irq_type,
 };
 
-static void pmic_irq_handler(unsigned irq, struct irq_desc *desc)
+static irqreturn_t pmic_irq_handler(int irq, void *data)
 {
-       struct pmic_gpio *pg = (struct pmic_gpio *)get_irq_data(irq);
+       struct pmic_gpio *pg = data;
        u8 intsts = *((u8 *)pg->gpiointr + 4);
        int gpio;
+       irqreturn_t ret = IRQ_NONE;
 
        for (gpio = 0; gpio < 8; gpio++) {
                if (intsts & (1 << gpio)) {
                        pr_debug("pmic pin %d triggered\n", gpio);
                        generic_handle_irq(pg->irq_base + gpio);
+                       ret = IRQ_HANDLED;
                }
        }
-
-       if (desc->chip->irq_eoi)
-               desc->chip->irq_eoi(irq_get_irq_data(irq));
-       else
-               dev_warn(pg->chip.dev, "missing EOI handler for irq %d\n", irq);
+       return ret;
 }
 
 static int __devinit platform_pmic_gpio_probe(struct platform_device *pdev)
@@ -297,8 +241,7 @@ static int __devinit platform_pmic_gpio_probe(struct platform_device *pdev)
        pg->chip.can_sleep = 1;
        pg->chip.dev = dev;
 
-       INIT_WORK(&pg->irqtypes.work, pmic_irqtype_work);
-       spin_lock_init(&pg->irqtypes.lock);
+       mutex_init(&pg->buslock);
 
        pg->chip.dev = dev;
        retval = gpiochip_add(&pg->chip);
@@ -306,8 +249,13 @@ static int __devinit platform_pmic_gpio_probe(struct platform_device *pdev)
                printk(KERN_ERR "%s: Can not add pmic gpio chip.\n", __func__);
                goto err;
        }
-       set_irq_data(pg->irq, pg);
-       set_irq_chained_handler(pg->irq, pmic_irq_handler);
+
+       retval = request_irq(pg->irq, pmic_irq_handler, 0, "pmic", pg);
+       if (retval) {
+               printk(KERN_WARNING "pmic: Interrupt request failed\n");
+               goto err;
+       }
+
        for (i = 0; i < 8; i++) {
                set_irq_chip_and_handler_name(i + pg->irq_base, &pmic_irqchip,
                                        handle_simple_irq, "demux");
index 1752ef0..a91d510 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/sfi.h>
 #include <asm/mrst.h>
 #include <asm/intel_scu_ipc.h>
-#include <asm/mrst.h>
 
 /* IPC defines the following message types */
 #define IPCMSG_WATCHDOG_TIMER 0xF8 /* Set Kernel Watchdog Threshold */
@@ -161,7 +160,7 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
 {
        int i, nc, bytes, d;
        u32 offset = 0;
-       u32 err = 0;
+       int err;
        u8 cbuf[IPC_WWBUF_SIZE] = { };
        u32 *wbuf = (u32 *)&cbuf;
 
@@ -404,7 +403,7 @@ EXPORT_SYMBOL(intel_scu_ipc_update_register);
  */
 int intel_scu_ipc_simple_command(int cmd, int sub)
 {
-       u32 err = 0;
+       int err;
 
        mutex_lock(&ipclock);
        if (ipcdev.pdev == NULL) {
@@ -434,8 +433,7 @@ EXPORT_SYMBOL(intel_scu_ipc_simple_command);
 int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
                                                        u32 *out, int outlen)
 {
-       u32 err = 0;
-       int i = 0;
+       int i, err;
 
        mutex_lock(&ipclock);
        if (ipcdev.pdev == NULL) {
index ba3231d..b93a032 100644 (file)
@@ -128,6 +128,6 @@ static void __exit ipc_module_exit(void)
 module_init(ipc_module_init);
 module_exit(ipc_module_exit);
 
-MODULE_LICENSE("GPL V2");
+MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Utility driver for intel scu ipc");
 MODULE_AUTHOR("Sreedhara <sreedhara.ds@intel.com>");
index 1fe0f1f..865ef78 100644 (file)
@@ -162,7 +162,7 @@ set_bool_##value(struct device *dev, struct device_attribute *attr, \
                        return -EINVAL; \
        return count; \
 } \
-static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
+static DEVICE_ATTR(value, S_IRUGO | S_IWUSR, \
        show_bool_##value, set_bool_##value);
 
 show_set_bool(wireless, TC1100_INSTANCE_WIRELESS);
index dd59958..eb99223 100644 (file)
@@ -2275,16 +2275,12 @@ static void tpacpi_input_send_key(const unsigned int scancode)
        if (keycode != KEY_RESERVED) {
                mutex_lock(&tpacpi_inputdev_send_mutex);
 
+               input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, scancode);
                input_report_key(tpacpi_inputdev, keycode, 1);
-               if (keycode == KEY_UNKNOWN)
-                       input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
-                                   scancode);
                input_sync(tpacpi_inputdev);
 
+               input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, scancode);
                input_report_key(tpacpi_inputdev, keycode, 0);
-               if (keycode == KEY_UNKNOWN)
-                       input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
-                                   scancode);
                input_sync(tpacpi_inputdev);
 
                mutex_unlock(&tpacpi_inputdev_send_mutex);
index 2728469..82583b0 100644 (file)
@@ -46,8 +46,6 @@ static void pps_ktimer_event(unsigned long ptr)
        /* First of all we get the time stamp... */
        pps_get_ts(&ts);
 
-       dev_info(pps->dev, "PPS event at %lu\n", jiffies);
-
        pps_event(pps, &ts, PPS_CAPTUREASSERT, NULL);
 
        mod_timer(&ktimer, jiffies + HZ);
index 32221ef..c571d6d 100644 (file)
@@ -163,7 +163,7 @@ static void parport_attach(struct parport *port)
        }
 
        device->pardev = parport_register_device(port, KBUILD_MODNAME,
-                       NULL, NULL, parport_irq, 0, device);
+                       NULL, NULL, parport_irq, PARPORT_FLAG_EXCL, device);
        if (!device->pardev) {
                pr_err("couldn't register with %s\n", port->name);
                goto err_free;
index f3a73dd..e4c4f3d 100644 (file)
@@ -6,7 +6,7 @@ comment "PPS generators support"
 
 config PPS_GENERATOR_PARPORT
        tristate "Parallel port PPS signal generator"
-       depends on PARPORT
+       depends on PARPORT && BROKEN
        help
          If you say yes here you get support for a PPS signal generator which
          utilizes STROBE pin of a parallel port to send PPS signals. It uses
index 5c32f8d..b93af3e 100644 (file)
@@ -198,7 +198,7 @@ static void parport_attach(struct parport *port)
        }
 
        device.pardev = parport_register_device(port, KBUILD_MODNAME,
-                       NULL, NULL, NULL, 0, &device);
+                       NULL, NULL, NULL, PARPORT_FLAG_EXCL, &device);
        if (!device.pardev) {
                pr_err("couldn't register with %s\n", port->name);
                return;
index cba1b43..a4e8eb9 100644 (file)
@@ -168,7 +168,7 @@ void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
 {
        unsigned long flags;
        int captured = 0;
-       struct pps_ktime ts_real;
+       struct pps_ktime ts_real = { .sec = 0, .nsec = 0, .flags = 0 };
 
        /* check event type */
        BUG_ON((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0);
index 76b4185..1269fbd 100644 (file)
@@ -77,9 +77,9 @@ rio_read_config(struct file *filp, struct kobject *kobj,
 
        /* Several chips lock up trying to read undefined config space */
        if (capable(CAP_SYS_ADMIN))
-               size = 0x200000;
+               size = RIO_MAINT_SPACE_SZ;
 
-       if (off > size)
+       if (off >= size)
                return 0;
        if (off + count > size) {
                size -= off;
@@ -147,10 +147,10 @@ rio_write_config(struct file *filp, struct kobject *kobj,
        loff_t init_off = off;
        u8 *data = (u8 *) buf;
 
-       if (off > 0x200000)
+       if (off >= RIO_MAINT_SPACE_SZ)
                return 0;
-       if (off + count > 0x200000) {
-               size = 0x200000 - off;
+       if (off + count > RIO_MAINT_SPACE_SZ) {
+               size = RIO_MAINT_SPACE_SZ - off;
                count = size;
        }
 
@@ -200,7 +200,7 @@ static struct bin_attribute rio_config_attr = {
                 .name = "config",
                 .mode = S_IRUGO | S_IWUSR,
                 },
-       .size = 0x200000,
+       .size = RIO_MAINT_SPACE_SZ,
        .read = rio_read_config,
        .write = rio_write_config,
 };
index f53d31b..2bb5de1 100644 (file)
@@ -174,7 +174,7 @@ static int mc13xxx_regulator_get_voltage(struct regulator_dev *rdev)
 
        dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
 
-       BUG_ON(val < 0 || val > mc13xxx_regulators[id].desc.n_voltages);
+       BUG_ON(val > mc13xxx_regulators[id].desc.n_voltages);
 
        return mc13xxx_regulators[id].voltages[val];
 }
index 8b0d2c4..06df898 100644 (file)
@@ -120,6 +120,7 @@ static unsigned int wm831x_dcdc_get_mode(struct regulator_dev *rdev)
                return REGULATOR_MODE_IDLE;
        default:
                BUG();
+               return -EINVAL;
        }
 }
 
index cdd9719..4941cad 100644 (file)
@@ -97,6 +97,18 @@ config RTC_INTF_DEV
 
          If unsure, say Y.
 
+config RTC_INTF_DEV_UIE_EMUL
+       bool "RTC UIE emulation on dev interface"
+       depends on RTC_INTF_DEV
+       help
+         Provides an emulation for RTC_UIE if the underlying rtc chip
+         driver does not expose RTC_UIE ioctls. Those requests generate
+         once-per-second update interrupts, used for synchronization.
+
+         The emulation code will read the time from the hardware
+         clock several times per second, please enable this option
+         only if you know that you really need it.
+
 config RTC_DRV_TEST
        tristate "Test driver/device"
        help
index 9583cbc..09b4437 100644 (file)
@@ -117,6 +117,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
                                        struct module *owner)
 {
        struct rtc_device *rtc;
+       struct rtc_wkalrm alrm;
        int id, err;
 
        if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) {
@@ -143,6 +144,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
        rtc->id = id;
        rtc->ops = ops;
        rtc->owner = owner;
+       rtc->irq_freq = 1;
        rtc->max_user_freq = 64;
        rtc->dev.parent = dev;
        rtc->dev.class = rtc_class;
@@ -165,6 +167,12 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
        rtc->pie_timer.function = rtc_pie_update_irq;
        rtc->pie_enabled = 0;
 
+       /* Check to see if there is an ALARM already set in hw */
+       err = __rtc_read_alarm(rtc, &alrm);
+
+       if (!err && !rtc_valid_tm(&alrm.time))
+               rtc_set_alarm(rtc, &alrm);
+
        strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
        dev_set_name(&rtc->dev, "rtc%d", id);
 
index 925006d..8ec6b06 100644 (file)
@@ -116,6 +116,186 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs)
 }
 EXPORT_SYMBOL_GPL(rtc_set_mmss);
 
+static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
+{
+       int err;
+
+       err = mutex_lock_interruptible(&rtc->ops_lock);
+       if (err)
+               return err;
+
+       if (rtc->ops == NULL)
+               err = -ENODEV;
+       else if (!rtc->ops->read_alarm)
+               err = -EINVAL;
+       else {
+               memset(alarm, 0, sizeof(struct rtc_wkalrm));
+               err = rtc->ops->read_alarm(rtc->dev.parent, alarm);
+       }
+
+       mutex_unlock(&rtc->ops_lock);
+       return err;
+}
+
+int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
+{
+       int err;
+       struct rtc_time before, now;
+       int first_time = 1;
+       unsigned long t_now, t_alm;
+       enum { none, day, month, year } missing = none;
+       unsigned days;
+
+       /* The lower level RTC driver may return -1 in some fields,
+        * creating invalid alarm->time values, for reasons like:
+        *
+        *   - The hardware may not be capable of filling them in;
+        *     many alarms match only on time-of-day fields, not
+        *     day/month/year calendar data.
+        *
+        *   - Some hardware uses illegal values as "wildcard" match
+        *     values, which non-Linux firmware (like a BIOS) may try
+        *     to set up as e.g. "alarm 15 minutes after each hour".
+        *     Linux uses only oneshot alarms.
+        *
+        * When we see that here, we deal with it by using values from
+        * a current RTC timestamp for any missing (-1) values.  The
+        * RTC driver prevents "periodic alarm" modes.
+        *
+        * But this can be racey, because some fields of the RTC timestamp
+        * may have wrapped in the interval since we read the RTC alarm,
+        * which would lead to us inserting inconsistent values in place
+        * of the -1 fields.
+        *
+        * Reading the alarm and timestamp in the reverse sequence
+        * would have the same race condition, and not solve the issue.
+        *
+        * So, we must first read the RTC timestamp,
+        * then read the RTC alarm value,
+        * and then read a second RTC timestamp.
+        *
+        * If any fields of the second timestamp have changed
+        * when compared with the first timestamp, then we know
+        * our timestamp may be inconsistent with that used by
+        * the low-level rtc_read_alarm_internal() function.
+        *
+        * So, when the two timestamps disagree, we just loop and do
+        * the process again to get a fully consistent set of values.
+        *
+        * This could all instead be done in the lower level driver,
+        * but since more than one lower level RTC implementation needs it,
+        * then it's probably best best to do it here instead of there..
+        */
+
+       /* Get the "before" timestamp */
+       err = rtc_read_time(rtc, &before);
+       if (err < 0)
+               return err;
+       do {
+               if (!first_time)
+                       memcpy(&before, &now, sizeof(struct rtc_time));
+               first_time = 0;
+
+               /* get the RTC alarm values, which may be incomplete */
+               err = rtc_read_alarm_internal(rtc, alarm);
+               if (err)
+                       return err;
+
+               /* full-function RTCs won't have such missing fields */
+               if (rtc_valid_tm(&alarm->time) == 0)
+                       return 0;
+
+               /* get the "after" timestamp, to detect wrapped fields */
+               err = rtc_read_time(rtc, &now);
+               if (err < 0)
+                       return err;
+
+               /* note that tm_sec is a "don't care" value here: */
+       } while (   before.tm_min   != now.tm_min
+                || before.tm_hour  != now.tm_hour
+                || before.tm_mon   != now.tm_mon
+                || before.tm_year  != now.tm_year);
+
+       /* Fill in the missing alarm fields using the timestamp; we
+        * know there's at least one since alarm->time is invalid.
+        */
+       if (alarm->time.tm_sec == -1)
+               alarm->time.tm_sec = now.tm_sec;
+       if (alarm->time.tm_min == -1)
+               alarm->time.tm_min = now.tm_min;
+       if (alarm->time.tm_hour == -1)
+               alarm->time.tm_hour = now.tm_hour;
+
+       /* For simplicity, only support date rollover for now */
+       if (alarm->time.tm_mday == -1) {
+               alarm->time.tm_mday = now.tm_mday;
+               missing = day;
+       }
+       if (alarm->time.tm_mon == -1) {
+               alarm->time.tm_mon = now.tm_mon;
+               if (missing == none)
+                       missing = month;
+       }
+       if (alarm->time.tm_year == -1) {
+               alarm->time.tm_year = now.tm_year;
+               if (missing == none)
+                       missing = year;
+       }
+
+       /* with luck, no rollover is needed */
+       rtc_tm_to_time(&now, &t_now);
+       rtc_tm_to_time(&alarm->time, &t_alm);
+       if (t_now < t_alm)
+               goto done;
+
+       switch (missing) {
+
+       /* 24 hour rollover ... if it's now 10am Monday, an alarm that
+        * that will trigger at 5am will do so at 5am Tuesday, which
+        * could also be in the next month or year.  This is a common
+        * case, especially for PCs.
+        */
+       case day:
+               dev_dbg(&rtc->dev, "alarm rollover: %s\n", "day");
+               t_alm += 24 * 60 * 60;
+               rtc_time_to_tm(t_alm, &alarm->time);
+               break;
+
+       /* Month rollover ... if it's the 31th, an alarm on the 3rd will
+        * be next month.  An alarm matching on the 30th, 29th, or 28th
+        * may end up in the month after that!  Many newer PCs support
+        * this type of alarm.
+        */
+       case month:
+               dev_dbg(&rtc->dev, "alarm rollover: %s\n", "month");
+               do {
+                       if (alarm->time.tm_mon < 11)
+                               alarm->time.tm_mon++;
+                       else {
+                               alarm->time.tm_mon = 0;
+                               alarm->time.tm_year++;
+                       }
+                       days = rtc_month_days(alarm->time.tm_mon,
+                                       alarm->time.tm_year);
+               } while (days < alarm->time.tm_mday);
+               break;
+
+       /* Year rollover ... easy except for leap years! */
+       case year:
+               dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year");
+               do {
+                       alarm->time.tm_year++;
+               } while (rtc_valid_tm(&alarm->time) != 0);
+               break;
+
+       default:
+               dev_warn(&rtc->dev, "alarm rollover not handled\n");
+       }
+
+done:
+       return 0;
+}
+
 int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
 {
        int err;
@@ -209,9 +389,8 @@ int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled)
        }
 
        if (err)
-               return err;
-
-       if (!rtc->ops)
+               /* nothing */;
+       else if (!rtc->ops)
                err = -ENODEV;
        else if (!rtc->ops->alarm_irq_enable)
                err = -EINVAL;
@@ -229,6 +408,12 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
        if (err)
                return err;
 
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+       if (enabled == 0 && rtc->uie_irq_active) {
+               mutex_unlock(&rtc->ops_lock);
+               return rtc_dev_update_irq_enable_emul(rtc, 0);
+       }
+#endif
        /* make sure we're changing state */
        if (rtc->uie_rtctimer.enabled == enabled)
                goto out;
@@ -248,6 +433,16 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
 
 out:
        mutex_unlock(&rtc->ops_lock);
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+       /*
+        * Enable emulation if the driver did not provide
+        * the update_irq_enable function pointer or if returned
+        * -EINVAL to signal that it has been configured without
+        * interrupts or that are not available at the moment.
+        */
+       if (err == -EINVAL)
+               err = rtc_dev_update_irq_enable_emul(rtc, enabled);
+#endif
        return err;
 
 }
@@ -263,7 +458,7 @@ EXPORT_SYMBOL_GPL(rtc_update_irq_enable);
  *
  * Triggers the registered irq_task function callback.
  */
-static void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode)
+void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode)
 {
        unsigned long flags;
 
@@ -464,6 +659,9 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
        int err = 0;
        unsigned long flags;
 
+       if (freq <= 0)
+               return -EINVAL;
+
        spin_lock_irqsave(&rtc->irq_task_lock, flags);
        if (rtc->irq_task != NULL && task == NULL)
                err = -EBUSY;
index b2752b6..e725d51 100644 (file)
@@ -134,36 +134,29 @@ static int at32_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
        return ret;
 }
 
-static int at32_rtc_ioctl(struct device *dev, unsigned int cmd,
-                       unsigned long arg)
+static int at32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct rtc_at32ap700x *rtc = dev_get_drvdata(dev);
        int ret = 0;
 
        spin_lock_irq(&rtc->lock);
 
-       switch (cmd) {
-       case RTC_AIE_ON:
+       if(enabled) {
                if (rtc_readl(rtc, VAL) > rtc->alarm_time) {
                        ret = -EINVAL;
-                       break;
+                       goto out;
                }
                rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL)
                                | RTC_BIT(CTRL_TOPEN));
                rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI));
                rtc_writel(rtc, IER, RTC_BIT(IER_TOPI));
-               break;
-       case RTC_AIE_OFF:
+       } else {
                rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL)
                                & ~RTC_BIT(CTRL_TOPEN));
                rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI));
                rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI));
-               break;
-       default:
-               ret = -ENOIOCTLCMD;
-               break;
        }
-
+out:
        spin_unlock_irq(&rtc->lock);
 
        return ret;
@@ -195,11 +188,11 @@ static irqreturn_t at32_rtc_interrupt(int irq, void *dev_id)
 }
 
 static struct rtc_class_ops at32_rtc_ops = {
-       .ioctl          = at32_rtc_ioctl,
        .read_time      = at32_rtc_readtime,
        .set_time       = at32_rtc_settime,
        .read_alarm     = at32_rtc_readalarm,
        .set_alarm      = at32_rtc_setalarm,
+       .alarm_irq_enable = at32_rtc_alarm_irq_enable,
 };
 
 static int __init at32_rtc_probe(struct platform_device *pdev)
index bc8bbca..518a76e 100644 (file)
@@ -183,40 +183,18 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
        return 0;
 }
 
-/*
- * Handle commands from user-space
- */
-static int at91_rtc_ioctl(struct device *dev, unsigned int cmd,
-                       unsigned long arg)
+static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
-       int ret = 0;
+       pr_debug("%s(): cmd=%08x\n", __func__, enabled);
 
-       pr_debug("%s(): cmd=%08x, arg=%08lx.\n", __func__, cmd, arg);
-
-       /* important:  scrub old status before enabling IRQs */
-       switch (cmd) {
-       case RTC_AIE_OFF:       /* alarm off */
-               at91_sys_write(AT91_RTC_IDR, AT91_RTC_ALARM);
-               break;
-       case RTC_AIE_ON:        /* alarm on */
+       if (enabled) {
                at91_sys_write(AT91_RTC_SCCR, AT91_RTC_ALARM);
                at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM);
-               break;
-       case RTC_UIE_OFF:       /* update off */
-               at91_sys_write(AT91_RTC_IDR, AT91_RTC_SECEV);
-               break;
-       case RTC_UIE_ON:        /* update on */
-               at91_sys_write(AT91_RTC_SCCR, AT91_RTC_SECEV);
-               at91_sys_write(AT91_RTC_IER, AT91_RTC_SECEV);
-               break;
-       default:
-               ret = -ENOIOCTLCMD;
-               break;
-       }
+       } else
+               at91_sys_write(AT91_RTC_IDR, AT91_RTC_ALARM);
 
-       return ret;
+       return 0;
 }
-
 /*
  * Provide additional RTC information in /proc/driver/rtc
  */
@@ -264,12 +242,12 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
 }
 
 static const struct rtc_class_ops at91_rtc_ops = {
-       .ioctl          = at91_rtc_ioctl,
        .read_time      = at91_rtc_readtime,
        .set_time       = at91_rtc_settime,
        .read_alarm     = at91_rtc_readalarm,
        .set_alarm      = at91_rtc_setalarm,
        .proc           = at91_rtc_proc,
+       .alarm_irq_enable = at91_rtc_alarm_irq_enable,
 };
 
 /*
index f677e07..a3ad957 100644 (file)
@@ -216,37 +216,17 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
        return 0;
 }
 
-/*
- * Handle commands from user-space
- */
-static int at91_rtc_ioctl(struct device *dev, unsigned int cmd,
-                       unsigned long arg)
+static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct sam9_rtc *rtc = dev_get_drvdata(dev);
-       int ret = 0;
        u32 mr = rtt_readl(rtc, MR);
 
-       dev_dbg(dev, "ioctl: cmd=%08x, arg=%08lx, mr %08x\n", cmd, arg, mr);
-
-       switch (cmd) {
-       case RTC_AIE_OFF:               /* alarm off */
-               rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN);
-               break;
-       case RTC_AIE_ON:                /* alarm on */
+       dev_dbg(dev, "alarm_irq_enable: enabled=%08x, mr %08x\n", enabled, mr);
+       if (enabled)
                rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN);
-               break;
-       case RTC_UIE_OFF:               /* update off */
-               rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN);
-               break;
-       case RTC_UIE_ON:                /* update on */
-               rtt_writel(rtc, MR, mr | AT91_RTT_RTTINCIEN);
-               break;
-       default:
-               ret = -ENOIOCTLCMD;
-               break;
-       }
-
-       return ret;
+       else
+               rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN);
+       return 0;
 }
 
 /*
@@ -296,12 +276,12 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc)
 }
 
 static const struct rtc_class_ops at91_rtc_ops = {
-       .ioctl          = at91_rtc_ioctl,
        .read_time      = at91_rtc_readtime,
        .set_time       = at91_rtc_settime,
        .read_alarm     = at91_rtc_readalarm,
        .set_alarm      = at91_rtc_setalarm,
        .proc           = at91_rtc_proc,
+       .alarm_irq_enable = at91_rtc_alarm_irq_enable,
 };
 
 /*
index b4b6087..ca9cff8 100644 (file)
@@ -240,40 +240,16 @@ static void bfin_rtc_int_set_alarm(struct bfin_rtc *rtc)
         */
        bfin_rtc_int_set(rtc->rtc_alarm.tm_yday == -1 ? RTC_ISTAT_ALARM : RTC_ISTAT_ALARM_DAY);
 }
-static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+
+static int bfin_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct bfin_rtc *rtc = dev_get_drvdata(dev);
-       int ret = 0;
 
        dev_dbg_stamp(dev);
-
-       bfin_rtc_sync_pending(dev);
-
-       switch (cmd) {
-       case RTC_UIE_ON:
-               dev_dbg_stamp(dev);
-               bfin_rtc_int_set(RTC_ISTAT_SEC);
-               break;
-       case RTC_UIE_OFF:
-               dev_dbg_stamp(dev);
-               bfin_rtc_int_clear(~RTC_ISTAT_SEC);
-               break;
-
-       case RTC_AIE_ON:
-               dev_dbg_stamp(dev);
+       if (enabled)
                bfin_rtc_int_set_alarm(rtc);
-               break;
-       case RTC_AIE_OFF:
-               dev_dbg_stamp(dev);
+       else
                bfin_rtc_int_clear(~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
-               break;
-
-       default:
-               dev_dbg_stamp(dev);
-               ret = -ENOIOCTLCMD;
-       }
-
-       return ret;
 }
 
 static int bfin_rtc_read_time(struct device *dev, struct rtc_time *tm)
@@ -356,12 +332,12 @@ static int bfin_rtc_proc(struct device *dev, struct seq_file *seq)
 }
 
 static struct rtc_class_ops bfin_rtc_ops = {
-       .ioctl         = bfin_rtc_ioctl,
        .read_time     = bfin_rtc_read_time,
        .set_time      = bfin_rtc_set_time,
        .read_alarm    = bfin_rtc_read_alarm,
        .set_alarm     = bfin_rtc_set_alarm,
        .proc          = bfin_rtc_proc,
+       .alarm_irq_enable = bfin_rtc_alarm_irq_enable,
 };
 
 static int __devinit bfin_rtc_probe(struct platform_device *pdev)
index c7ff8df..911e75c 100644 (file)
@@ -37,6 +37,8 @@
 #include <linux/mod_devicetable.h>
 #include <linux/log2.h>
 #include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
 
 /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
 #include <asm-generic/rtc.h>
@@ -375,50 +377,6 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
        return 0;
 }
 
-static int cmos_irq_set_freq(struct device *dev, int freq)
-{
-       struct cmos_rtc *cmos = dev_get_drvdata(dev);
-       int             f;
-       unsigned long   flags;
-
-       if (!is_valid_irq(cmos->irq))
-               return -ENXIO;
-
-       if (!is_power_of_2(freq))
-               return -EINVAL;
-       /* 0 = no irqs; 1 = 2^15 Hz ... 15 = 2^0 Hz */
-       f = ffs(freq);
-       if (f-- > 16)
-               return -EINVAL;
-       f = 16 - f;
-
-       spin_lock_irqsave(&rtc_lock, flags);
-       hpet_set_periodic_freq(freq);
-       CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT);
-       spin_unlock_irqrestore(&rtc_lock, flags);
-
-       return 0;
-}
-
-static int cmos_irq_set_state(struct device *dev, int enabled)
-{
-       struct cmos_rtc *cmos = dev_get_drvdata(dev);
-       unsigned long   flags;
-
-       if (!is_valid_irq(cmos->irq))
-               return -ENXIO;
-
-       spin_lock_irqsave(&rtc_lock, flags);
-
-       if (enabled)
-               cmos_irq_enable(cmos, RTC_PIE);
-       else
-               cmos_irq_disable(cmos, RTC_PIE);
-
-       spin_unlock_irqrestore(&rtc_lock, flags);
-       return 0;
-}
-
 static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct cmos_rtc *cmos = dev_get_drvdata(dev);
@@ -438,25 +396,6 @@ static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled)
        return 0;
 }
 
-static int cmos_update_irq_enable(struct device *dev, unsigned int enabled)
-{
-       struct cmos_rtc *cmos = dev_get_drvdata(dev);
-       unsigned long   flags;
-
-       if (!is_valid_irq(cmos->irq))
-               return -EINVAL;
-
-       spin_lock_irqsave(&rtc_lock, flags);
-
-       if (enabled)
-               cmos_irq_enable(cmos, RTC_UIE);
-       else
-               cmos_irq_disable(cmos, RTC_UIE);
-
-       spin_unlock_irqrestore(&rtc_lock, flags);
-       return 0;
-}
-
 #if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE)
 
 static int cmos_procfs(struct device *dev, struct seq_file *seq)
@@ -501,10 +440,7 @@ static const struct rtc_class_ops cmos_rtc_ops = {
        .read_alarm             = cmos_read_alarm,
        .set_alarm              = cmos_set_alarm,
        .proc                   = cmos_procfs,
-       .irq_set_freq           = cmos_irq_set_freq,
-       .irq_set_state          = cmos_irq_set_state,
        .alarm_irq_enable       = cmos_alarm_irq_enable,
-       .update_irq_enable      = cmos_update_irq_enable,
 };
 
 /*----------------------------------------------------------------*/
@@ -1123,6 +1059,47 @@ static struct pnp_driver cmos_pnp_driver = {
 
 #endif /* CONFIG_PNP */
 
+#ifdef CONFIG_OF
+static const struct of_device_id of_cmos_match[] = {
+       {
+               .compatible = "motorola,mc146818",
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, of_cmos_match);
+
+static __init void cmos_of_init(struct platform_device *pdev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       struct rtc_time time;
+       int ret;
+       const __be32 *val;
+
+       if (!node)
+               return;
+
+       val = of_get_property(node, "ctrl-reg", NULL);
+       if (val)
+               CMOS_WRITE(be32_to_cpup(val), RTC_CONTROL);
+
+       val = of_get_property(node, "freq-reg", NULL);
+       if (val)
+               CMOS_WRITE(be32_to_cpup(val), RTC_FREQ_SELECT);
+
+       get_rtc_time(&time);
+       ret = rtc_valid_tm(&time);
+       if (ret) {
+               struct rtc_time def_time = {
+                       .tm_year = 1,
+                       .tm_mday = 1,
+               };
+               set_rtc_time(&def_time);
+       }
+}
+#else
+static inline void cmos_of_init(struct platform_device *pdev) {}
+#define of_cmos_match NULL
+#endif
 /*----------------------------------------------------------------*/
 
 /* Platform setup should have set up an RTC device, when PNP is
@@ -1131,6 +1108,7 @@ static struct pnp_driver cmos_pnp_driver = {
 
 static int __init cmos_platform_probe(struct platform_device *pdev)
 {
+       cmos_of_init(pdev);
        cmos_wake_setup(&pdev->dev);
        return cmos_do_probe(&pdev->dev,
                        platform_get_resource(pdev, IORESOURCE_IO, 0),
@@ -1162,6 +1140,7 @@ static struct platform_driver cmos_platform_driver = {
 #ifdef CONFIG_PM
                .pm             = &cmos_pm_ops,
 #endif
+               .of_match_table = of_cmos_match,
        }
 };
 
index 34647fc..8d46838 100644 (file)
@@ -231,10 +231,6 @@ davinci_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
        case RTC_WIE_OFF:
                rtc_ctrl &= ~PRTCSS_RTC_CTRL_WEN;
                break;
-       case RTC_UIE_OFF:
-       case RTC_UIE_ON:
-               ret = -ENOTTY;
-               break;
        default:
                ret = -ENOIOCTLCMD;
        }
@@ -473,55 +469,6 @@ static int davinci_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
        return 0;
 }
 
-static int davinci_rtc_irq_set_state(struct device *dev, int enabled)
-{
-       struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev);
-       unsigned long flags;
-       u8 rtc_ctrl;
-
-       spin_lock_irqsave(&davinci_rtc_lock, flags);
-
-       rtc_ctrl = rtcss_read(davinci_rtc, PRTCSS_RTC_CTRL);
-
-       if (enabled) {
-               while (rtcss_read(davinci_rtc, PRTCSS_RTC_CTRL)
-                      & PRTCSS_RTC_CTRL_WDTBUS)
-                       cpu_relax();
-
-               rtc_ctrl |= PRTCSS_RTC_CTRL_TE;
-               rtcss_write(davinci_rtc, rtc_ctrl, PRTCSS_RTC_CTRL);
-
-               rtcss_write(davinci_rtc, 0x0, PRTCSS_RTC_CLKC_CNT);
-
-               rtc_ctrl |= PRTCSS_RTC_CTRL_TIEN |
-                           PRTCSS_RTC_CTRL_TMMD |
-                           PRTCSS_RTC_CTRL_TMRFLG;
-       } else
-               rtc_ctrl &= ~PRTCSS_RTC_CTRL_TIEN;
-
-       rtcss_write(davinci_rtc, rtc_ctrl, PRTCSS_RTC_CTRL);
-
-       spin_unlock_irqrestore(&davinci_rtc_lock, flags);
-
-       return 0;
-}
-
-static int davinci_rtc_irq_set_freq(struct device *dev, int freq)
-{
-       struct davinci_rtc *davinci_rtc = dev_get_drvdata(dev);
-       unsigned long flags;
-       u16 tmr_counter = (0x8000 >> (ffs(freq) - 1));
-
-       spin_lock_irqsave(&davinci_rtc_lock, flags);
-
-       rtcss_write(davinci_rtc, tmr_counter & 0xFF, PRTCSS_RTC_TMR0);
-       rtcss_write(davinci_rtc, (tmr_counter & 0xFF00) >> 8, PRTCSS_RTC_TMR1);
-
-       spin_unlock_irqrestore(&davinci_rtc_lock, flags);
-
-       return 0;
-}
-
 static struct rtc_class_ops davinci_rtc_ops = {
        .ioctl                  = davinci_rtc_ioctl,
        .read_time              = davinci_rtc_read_time,
@@ -529,8 +476,6 @@ static struct rtc_class_ops davinci_rtc_ops = {
        .alarm_irq_enable       = davinci_rtc_alarm_irq_enable,
        .read_alarm             = davinci_rtc_read_alarm,
        .set_alarm              = davinci_rtc_set_alarm,
-       .irq_set_state          = davinci_rtc_irq_set_state,
-       .irq_set_freq           = davinci_rtc_irq_set_freq,
 };
 
 static int __init davinci_rtc_probe(struct platform_device *pdev)
index 212b16e..d0e06ed 100644 (file)
@@ -46,6 +46,105 @@ static int rtc_dev_open(struct inode *inode, struct file *file)
        return err;
 }
 
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+/*
+ * Routine to poll RTC seconds field for change as often as possible,
+ * after first RTC_UIE use timer to reduce polling
+ */
+static void rtc_uie_task(struct work_struct *work)
+{
+       struct rtc_device *rtc =
+               container_of(work, struct rtc_device, uie_task);
+       struct rtc_time tm;
+       int num = 0;
+       int err;
+
+       err = rtc_read_time(rtc, &tm);
+
+       spin_lock_irq(&rtc->irq_lock);
+       if (rtc->stop_uie_polling || err) {
+               rtc->uie_task_active = 0;
+       } else if (rtc->oldsecs != tm.tm_sec) {
+               num = (tm.tm_sec + 60 - rtc->oldsecs) % 60;
+               rtc->oldsecs = tm.tm_sec;
+               rtc->uie_timer.expires = jiffies + HZ - (HZ/10);
+               rtc->uie_timer_active = 1;
+               rtc->uie_task_active = 0;
+               add_timer(&rtc->uie_timer);
+       } else if (schedule_work(&rtc->uie_task) == 0) {
+               rtc->uie_task_active = 0;
+       }
+       spin_unlock_irq(&rtc->irq_lock);
+       if (num)
+               rtc_handle_legacy_irq(rtc, num, RTC_UF);
+}
+static void rtc_uie_timer(unsigned long data)
+{
+       struct rtc_device *rtc = (struct rtc_device *)data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&rtc->irq_lock, flags);
+       rtc->uie_timer_active = 0;
+       rtc->uie_task_active = 1;
+       if ((schedule_work(&rtc->uie_task) == 0))
+               rtc->uie_task_active = 0;
+       spin_unlock_irqrestore(&rtc->irq_lock, flags);
+}
+
+static int clear_uie(struct rtc_device *rtc)
+{
+       spin_lock_irq(&rtc->irq_lock);
+       if (rtc->uie_irq_active) {
+               rtc->stop_uie_polling = 1;
+               if (rtc->uie_timer_active) {
+                       spin_unlock_irq(&rtc->irq_lock);
+                       del_timer_sync(&rtc->uie_timer);
+                       spin_lock_irq(&rtc->irq_lock);
+                       rtc->uie_timer_active = 0;
+               }
+               if (rtc->uie_task_active) {
+                       spin_unlock_irq(&rtc->irq_lock);
+                       flush_scheduled_work();
+                       spin_lock_irq(&rtc->irq_lock);
+               }
+               rtc->uie_irq_active = 0;
+       }
+       spin_unlock_irq(&rtc->irq_lock);
+       return 0;
+}
+
+static int set_uie(struct rtc_device *rtc)
+{
+       struct rtc_time tm;
+       int err;
+
+       err = rtc_read_time(rtc, &tm);
+       if (err)
+               return err;
+       spin_lock_irq(&rtc->irq_lock);
+       if (!rtc->uie_irq_active) {
+               rtc->uie_irq_active = 1;
+               rtc->stop_uie_polling = 0;
+               rtc->oldsecs = tm.tm_sec;
+               rtc->uie_task_active = 1;
+               if (schedule_work(&rtc->uie_task) == 0)
+                       rtc->uie_task_active = 0;
+       }
+       rtc->irq_data = 0;
+       spin_unlock_irq(&rtc->irq_lock);
+       return 0;
+}
+
+int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, unsigned int enabled)
+{
+       if (enabled)
+               return set_uie(rtc);
+       else
+               return clear_uie(rtc);
+}
+EXPORT_SYMBOL(rtc_dev_update_irq_enable_emul);
+
+#endif /* CONFIG_RTC_INTF_DEV_UIE_EMUL */
 
 static ssize_t
 rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
@@ -154,19 +253,7 @@ static long rtc_dev_ioctl(struct file *file,
        if (err)
                goto done;
 
-       /* try the driver's ioctl interface */
-       if (ops->ioctl) {
-               err = ops->ioctl(rtc->dev.parent, cmd, arg);
-               if (err != -ENOIOCTLCMD) {
-                       mutex_unlock(&rtc->ops_lock);
-                       return err;
-               }
-       }
-
-       /* if the driver does not provide the ioctl interface
-        * or if that particular ioctl was not implemented
-        * (-ENOIOCTLCMD), we will try to emulate here.
-        *
+       /*
         * Drivers *SHOULD NOT* provide ioctl implementations
         * for these requests.  Instead, provide methods to
         * support the following code, so that the RTC's main
@@ -329,7 +416,12 @@ static long rtc_dev_ioctl(struct file *file,
                return err;
 
        default:
-               err = -ENOTTY;
+               /* Finally try the driver's ioctl interface */
+               if (ops->ioctl) {
+                       err = ops->ioctl(rtc->dev.parent, cmd, arg);
+                       if (err == -ENOIOCTLCMD)
+                               err = -ENOTTY;
+               }
                break;
        }
 
@@ -394,6 +486,11 @@ void rtc_dev_prepare(struct rtc_device *rtc)
 
        rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id);
 
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+       INIT_WORK(&rtc->uie_task, rtc_uie_task);
+       setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc);
+#endif
+
        cdev_init(&rtc->char_dev, &rtc_dev_fops);
        rtc->char_dev.owner = rtc->owner;
 }
index bf430f9..60ce696 100644 (file)
@@ -40,6 +40,26 @@ static inline void ds1286_rtc_write(struct ds1286_priv *priv, u8 data, int reg)
        __raw_writel(data, &priv->rtcregs[reg]);
 }
 
+
+static int ds1286_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct ds1286_priv *priv = dev_get_drvdata(dev);
+       unsigned long flags;
+       unsigned char val;
+
+       /* Allow or mask alarm interrupts */
+       spin_lock_irqsave(&priv->lock, flags);
+       val = ds1286_rtc_read(priv, RTC_CMD);
+       if (enabled)
+               val &=  ~RTC_TDM;
+       else
+               val |=  RTC_TDM;
+       ds1286_rtc_write(priv, val, RTC_CMD);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
 #ifdef CONFIG_RTC_INTF_DEV
 
 static int ds1286_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
@@ -49,22 +69,6 @@ static int ds1286_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
        unsigned char val;
 
        switch (cmd) {
-       case RTC_AIE_OFF:
-               /* Mask alarm int. enab. bit    */
-               spin_lock_irqsave(&priv->lock, flags);
-               val = ds1286_rtc_read(priv, RTC_CMD);
-               val |=  RTC_TDM;
-               ds1286_rtc_write(priv, val, RTC_CMD);
-               spin_unlock_irqrestore(&priv->lock, flags);
-               break;
-       case RTC_AIE_ON:
-               /* Allow alarm interrupts.      */
-               spin_lock_irqsave(&priv->lock, flags);
-               val = ds1286_rtc_read(priv, RTC_CMD);
-               val &=  ~RTC_TDM;
-               ds1286_rtc_write(priv, val, RTC_CMD);
-               spin_unlock_irqrestore(&priv->lock, flags);
-               break;
        case RTC_WIE_OFF:
                /* Mask watchdog int. enab. bit */
                spin_lock_irqsave(&priv->lock, flags);
@@ -316,12 +320,13 @@ static int ds1286_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
 }
 
 static const struct rtc_class_ops ds1286_ops = {
-       .ioctl          = ds1286_ioctl,
-       .proc           = ds1286_proc,
+       .ioctl          = ds1286_ioctl,
+       .proc           = ds1286_proc,
        .read_time      = ds1286_read_time,
        .set_time       = ds1286_set_time,
        .read_alarm     = ds1286_read_alarm,
        .set_alarm      = ds1286_set_alarm,
+       .alarm_irq_enable = ds1286_alarm_irq_enable,
 };
 
 static int __devinit ds1286_probe(struct platform_device *pdev)
index 077af1d..57fbcc1 100644 (file)
@@ -139,49 +139,32 @@ static u8 hour2bcd(bool hr12, int hour)
  * Interface to RTC framework
  */
 
-#ifdef CONFIG_RTC_INTF_DEV
-
-/*
- * Context: caller holds rtc->ops_lock (to protect ds1305->ctrl)
- */
-static int ds1305_ioctl(struct device *dev, unsigned cmd, unsigned long arg)
+static int ds1305_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct ds1305   *ds1305 = dev_get_drvdata(dev);
        u8              buf[2];
-       int             status = -ENOIOCTLCMD;
+       long            err = -EINVAL;
 
        buf[0] = DS1305_WRITE | DS1305_CONTROL;
        buf[1] = ds1305->ctrl[0];
 
-       switch (cmd) {
-       case RTC_AIE_OFF:
-               status = 0;
-               if (!(buf[1] & DS1305_AEI0))
-                       goto done;
-               buf[1] &= ~DS1305_AEI0;
-               break;
-
-       case RTC_AIE_ON:
-               status = 0;
+       if (enabled) {
                if (ds1305->ctrl[0] & DS1305_AEI0)
                        goto done;
                buf[1] |= DS1305_AEI0;
-               break;
-       }
-       if (status == 0) {
-               status = spi_write_then_read(ds1305->spi, buf, sizeof buf,
-                               NULL, 0);
-               if (status >= 0)
-                       ds1305->ctrl[0] = buf[1];
+       } else {
+               if (!(buf[1] & DS1305_AEI0))
+                       goto done;
+               buf[1] &= ~DS1305_AEI0;
        }
-
+       err = spi_write_then_read(ds1305->spi, buf, sizeof buf, NULL, 0);
+       if (err >= 0)
+               ds1305->ctrl[0] = buf[1];
 done:
-       return status;
+       return err;
+
 }
 
-#else
-#define ds1305_ioctl   NULL
-#endif
 
 /*
  * Get/set of date and time is pretty normal.
@@ -460,12 +443,12 @@ done:
 #endif
 
 static const struct rtc_class_ops ds1305_ops = {
-       .ioctl          = ds1305_ioctl,
        .read_time      = ds1305_get_time,
        .set_time       = ds1305_set_time,
        .read_alarm     = ds1305_get_alarm,
        .set_alarm      = ds1305_set_alarm,
        .proc           = ds1305_proc,
+       .alarm_irq_enable = ds1305_alarm_irq_enable,
 };
 
 static void ds1305_work(struct work_struct *work)
index 0d559b6..4724ba3 100644 (file)
@@ -495,50 +495,27 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
        return 0;
 }
 
-static int ds1307_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+static int ds1307_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct i2c_client       *client = to_i2c_client(dev);
        struct ds1307           *ds1307 = i2c_get_clientdata(client);
        int                     ret;
 
-       switch (cmd) {
-       case RTC_AIE_OFF:
-               if (!test_bit(HAS_ALARM, &ds1307->flags))
-                       return -ENOTTY;
-
-               ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
-               if (ret < 0)
-                       return ret;
-
-               ret &= ~DS1337_BIT_A1IE;
-
-               ret = i2c_smbus_write_byte_data(client,
-                                               DS1337_REG_CONTROL, ret);
-               if (ret < 0)
-                       return ret;
-
-               break;
-
-       case RTC_AIE_ON:
-               if (!test_bit(HAS_ALARM, &ds1307->flags))
-                       return -ENOTTY;
+       if (!test_bit(HAS_ALARM, &ds1307->flags))
+               return -ENOTTY;
 
-               ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
-               if (ret < 0)
-                       return ret;
+       ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
+       if (ret < 0)
+               return ret;
 
+       if (enabled)
                ret |= DS1337_BIT_A1IE;
+       else
+               ret &= ~DS1337_BIT_A1IE;
 
-               ret = i2c_smbus_write_byte_data(client,
-                                               DS1337_REG_CONTROL, ret);
-               if (ret < 0)
-                       return ret;
-
-               break;
-
-       default:
-               return -ENOIOCTLCMD;
-       }
+       ret = i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, ret);
+       if (ret < 0)
+               return ret;
 
        return 0;
 }
@@ -548,7 +525,7 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {
        .set_time       = ds1307_set_time,
        .read_alarm     = ds1337_read_alarm,
        .set_alarm      = ds1337_set_alarm,
-       .ioctl          = ds1307_ioctl,
+       .alarm_irq_enable = ds1307_alarm_irq_enable,
 };
 
 /*----------------------------------------------------------------------*/
index 47fb635..d834a63 100644 (file)
@@ -307,42 +307,25 @@ unlock:
        mutex_unlock(&ds1374->mutex);
 }
 
-static int ds1374_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+static int ds1374_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct ds1374 *ds1374 = i2c_get_clientdata(client);
-       int ret = -ENOIOCTLCMD;
+       int ret;
 
        mutex_lock(&ds1374->mutex);
 
-       switch (cmd) {
-       case RTC_AIE_OFF:
-               ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR);
-               if (ret < 0)
-                       goto out;
-
-               ret &= ~DS1374_REG_CR_WACE;
-
-               ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret);
-               if (ret < 0)
-                       goto out;
-
-               break;
-
-       case RTC_AIE_ON:
-               ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR);
-               if (ret < 0)
-                       goto out;
+       ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR);
+       if (ret < 0)
+               goto out;
 
+       if (enabled) {
                ret |= DS1374_REG_CR_WACE | DS1374_REG_CR_AIE;
                ret &= ~DS1374_REG_CR_WDALM;
-
-               ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret);
-               if (ret < 0)
-                       goto out;
-
-               break;
+       } else {
+               ret &= ~DS1374_REG_CR_WACE;
        }
+       ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret);
 
 out:
        mutex_unlock(&ds1374->mutex);
@@ -354,7 +337,7 @@ static const struct rtc_class_ops ds1374_rtc_ops = {
        .set_time = ds1374_set_time,
        .read_alarm = ds1374_read_alarm,
        .set_alarm = ds1374_set_alarm,
-       .ioctl = ds1374_ioctl,
+       .alarm_irq_enable = ds1374_alarm_irq_enable,
 };
 
 static int ds1374_probe(struct i2c_client *client,
index 37268e9..3fffd70 100644 (file)
@@ -397,29 +397,12 @@ static int ds1511_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
        return 0;
 }
 
-static int ds1511_rtc_update_irq_enable(struct device *dev,
-       unsigned int enabled)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
-
-       if (pdata->irq <= 0)
-               return -EINVAL;
-       if (enabled)
-               pdata->irqen |= RTC_UF;
-       else
-               pdata->irqen &= ~RTC_UF;
-       ds1511_rtc_update_alarm(pdata);
-       return 0;
-}
-
 static const struct rtc_class_ops ds1511_rtc_ops = {
        .read_time              = ds1511_rtc_read_time,
        .set_time               = ds1511_rtc_set_time,
        .read_alarm             = ds1511_rtc_read_alarm,
        .set_alarm              = ds1511_rtc_set_alarm,
        .alarm_irq_enable       = ds1511_rtc_alarm_irq_enable,
-       .update_irq_enable      = ds1511_rtc_update_irq_enable,
 };
 
  static ssize_t
index ff432e2..fee41b9 100644 (file)
@@ -227,29 +227,12 @@ static int ds1553_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
        return 0;
 }
 
-static int ds1553_rtc_update_irq_enable(struct device *dev,
-       unsigned int enabled)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
-
-       if (pdata->irq <= 0)
-               return -EINVAL;
-       if (enabled)
-               pdata->irqen |= RTC_UF;
-       else
-               pdata->irqen &= ~RTC_UF;
-       ds1553_rtc_update_alarm(pdata);
-       return 0;
-}
-
 static const struct rtc_class_ops ds1553_rtc_ops = {
        .read_time              = ds1553_rtc_read_time,
        .set_time               = ds1553_rtc_set_time,
        .read_alarm             = ds1553_rtc_read_alarm,
        .set_alarm              = ds1553_rtc_set_alarm,
        .alarm_irq_enable       = ds1553_rtc_alarm_irq_enable,
-       .update_irq_enable      = ds1553_rtc_update_irq_enable,
 };
 
 static ssize_t ds1553_nvram_read(struct file *filp, struct kobject *kobj,
index 23a9ee1..27b7bf6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * RTC client/driver for the Maxim/Dallas DS3232 Real-Time Clock over I2C
  *
- * Copyright (C) 2009-2010 Freescale Semiconductor.
+ * Copyright (C) 2009-2011 Freescale Semiconductor.
  * Author: Jack Lan <jack.lan@freescale.com>
  *
  * This program is free software; you can redistribute  it and/or modify it
@@ -141,9 +141,11 @@ static int ds3232_read_time(struct device *dev, struct rtc_time *time)
                time->tm_hour = bcd2bin(hour);
        }
 
-       time->tm_wday = bcd2bin(week);
+       /* Day of the week in linux range is 0~6 while 1~7 in RTC chip */
+       time->tm_wday = bcd2bin(week) - 1;
        time->tm_mday = bcd2bin(day);
-       time->tm_mon = bcd2bin(month & 0x7F);
+       /* linux tm_mon range:0~11, while month range is 1~12 in RTC chip */
+       time->tm_mon = bcd2bin(month & 0x7F) - 1;
        if (century)
                add_century = 100;
 
@@ -162,9 +164,11 @@ static int ds3232_set_time(struct device *dev, struct rtc_time *time)
        buf[0] = bin2bcd(time->tm_sec);
        buf[1] = bin2bcd(time->tm_min);
        buf[2] = bin2bcd(time->tm_hour);
-       buf[3] = bin2bcd(time->tm_wday); /* Day of the week */
+       /* Day of the week in linux range is 0~6 while 1~7 in RTC chip */
+       buf[3] = bin2bcd(time->tm_wday + 1);
        buf[4] = bin2bcd(time->tm_mday); /* Date */
-       buf[5] = bin2bcd(time->tm_mon);
+       /* linux tm_mon range:0~11, while month range is 1~12 in RTC chip */
+       buf[5] = bin2bcd(time->tm_mon + 1);
        if (time->tm_year >= 100) {
                buf[5] |= 0x80;
                buf[6] = bin2bcd(time->tm_year - 100);
@@ -335,23 +339,6 @@ static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled)
        return 0;
 }
 
-static int ds3232_update_irq_enable(struct device *dev, unsigned int enabled)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct ds3232 *ds3232 = i2c_get_clientdata(client);
-
-       if (client->irq <= 0)
-               return -EINVAL;
-
-       if (enabled)
-               ds3232->rtc->irq_data |= RTC_UF;
-       else
-               ds3232->rtc->irq_data &= ~RTC_UF;
-
-       ds3232_update_alarm(client);
-       return 0;
-}
-
 static irqreturn_t ds3232_irq(int irq, void *dev_id)
 {
        struct i2c_client *client = dev_id;
@@ -402,7 +389,6 @@ static const struct rtc_class_ops ds3232_rtc_ops = {
        .read_alarm = ds3232_read_alarm,
        .set_alarm = ds3232_set_alarm,
        .alarm_irq_enable = ds3232_alarm_irq_enable,
-       .update_irq_enable = ds3232_update_irq_enable,
 };
 
 static int __devinit ds3232_probe(struct i2c_client *client,
index 2e16f72..b647363 100644 (file)
@@ -168,12 +168,6 @@ static int jz4740_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
        return ret;
 }
 
-static int jz4740_rtc_update_irq_enable(struct device *dev, unsigned int enable)
-{
-       struct jz4740_rtc *rtc = dev_get_drvdata(dev);
-       return jz4740_rtc_ctrl_set_bits(rtc, JZ_RTC_CTRL_1HZ_IRQ, enable);
-}
-
 static int jz4740_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
 {
        struct jz4740_rtc *rtc = dev_get_drvdata(dev);
@@ -185,7 +179,6 @@ static struct rtc_class_ops jz4740_rtc_ops = {
        .set_mmss       = jz4740_rtc_set_mmss,
        .read_alarm     = jz4740_rtc_read_alarm,
        .set_alarm      = jz4740_rtc_set_alarm,
-       .update_irq_enable = jz4740_rtc_update_irq_enable,
        .alarm_irq_enable = jz4740_rtc_alarm_irq_enable,
 };
 
index 5a8daa3..69fe664 100644 (file)
@@ -213,41 +213,27 @@ static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm)
        return m41t80_set_datetime(to_i2c_client(dev), tm);
 }
 
-#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE)
-static int
-m41t80_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+static int m41t80_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct i2c_client *client = to_i2c_client(dev);
        int rc;
 
-       switch (cmd) {
-       case RTC_AIE_OFF:
-       case RTC_AIE_ON:
-               break;
-       default:
-               return -ENOIOCTLCMD;
-       }
-
        rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
        if (rc < 0)
                goto err;
-       switch (cmd) {
-       case RTC_AIE_OFF:
-               rc &= ~M41T80_ALMON_AFE;
-               break;
-       case RTC_AIE_ON:
+
+       if (enabled)
                rc |= M41T80_ALMON_AFE;
-               break;
-       }
+       else
+               rc &= ~M41T80_ALMON_AFE;
+
        if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, rc) < 0)
                goto err;
+
        return 0;
 err:
        return -EIO;
 }
-#else
-#define        m41t80_rtc_ioctl NULL
-#endif
 
 static int m41t80_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 {
@@ -374,7 +360,7 @@ static struct rtc_class_ops m41t80_rtc_ops = {
        .read_alarm = m41t80_rtc_read_alarm,
        .set_alarm = m41t80_rtc_set_alarm,
        .proc = m41t80_rtc_proc,
-       .ioctl = m41t80_rtc_ioctl,
+       .alarm_irq_enable = m41t80_rtc_alarm_irq_enable,
 };
 
 #if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE)
index a99a0b5..3978f4c 100644 (file)
@@ -263,30 +263,21 @@ static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
 /*
  * Handle commands from user-space
  */
-static int m48t59_rtc_ioctl(struct device *dev, unsigned int cmd,
-                       unsigned long arg)
+static int m48t59_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct m48t59_plat_data *pdata = pdev->dev.platform_data;
        struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
        unsigned long flags;
-       int ret = 0;
 
        spin_lock_irqsave(&m48t59->lock, flags);
-       switch (cmd) {
-       case RTC_AIE_OFF:       /* alarm interrupt off */
-               M48T59_WRITE(0x00, M48T59_INTR);
-               break;
-       case RTC_AIE_ON:        /* alarm interrupt on */
+       if (enabled)
                M48T59_WRITE(M48T59_INTR_AFE, M48T59_INTR);
-               break;
-       default:
-               ret = -ENOIOCTLCMD;
-               break;
-       }
+       else
+               M48T59_WRITE(0x00, M48T59_INTR);
        spin_unlock_irqrestore(&m48t59->lock, flags);
 
-       return ret;
+       return 0;
 }
 
 static int m48t59_rtc_proc(struct device *dev, struct seq_file *seq)
@@ -330,12 +321,12 @@ static irqreturn_t m48t59_rtc_interrupt(int irq, void *dev_id)
 }
 
 static const struct rtc_class_ops m48t59_rtc_ops = {
-       .ioctl          = m48t59_rtc_ioctl,
        .read_time      = m48t59_rtc_read_time,
        .set_time       = m48t59_rtc_set_time,
        .read_alarm     = m48t59_rtc_readalarm,
        .set_alarm      = m48t59_rtc_setalarm,
        .proc           = m48t59_rtc_proc,
+       .alarm_irq_enable = m48t59_rtc_alarm_irq_enable,
 };
 
 static const struct rtc_class_ops m48t02_rtc_ops = {
index 5314b15..c420064 100644 (file)
@@ -282,12 +282,6 @@ static irqreturn_t mc13xxx_rtc_update_handler(int irq, void *dev)
        return IRQ_HANDLED;
 }
 
-static int mc13xxx_rtc_update_irq_enable(struct device *dev,
-               unsigned int enabled)
-{
-       return mc13xxx_rtc_irq_enable(dev, enabled, MC13XXX_IRQ_1HZ);
-}
-
 static int mc13xxx_rtc_alarm_irq_enable(struct device *dev,
                unsigned int enabled)
 {
@@ -300,7 +294,6 @@ static const struct rtc_class_ops mc13xxx_rtc_ops = {
        .read_alarm = mc13xxx_rtc_read_alarm,
        .set_alarm = mc13xxx_rtc_set_alarm,
        .alarm_irq_enable = mc13xxx_rtc_alarm_irq_enable,
-       .update_irq_enable = mc13xxx_rtc_update_irq_enable,
 };
 
 static irqreturn_t mc13xxx_rtc_reset_handler(int irq, void *dev)
index dfcdf09..b40c1ff 100644 (file)
@@ -240,32 +240,12 @@ static int mpc5121_rtc_alarm_irq_enable(struct device *dev,
        return 0;
 }
 
-static int mpc5121_rtc_update_irq_enable(struct device *dev,
-                                        unsigned int enabled)
-{
-       struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
-       struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
-       int val;
-
-       val = in_8(&regs->int_enable);
-
-       if (enabled)
-               val = (val & ~0x8) | 0x1;
-       else
-               val &= ~0x1;
-
-       out_8(&regs->int_enable, val);
-
-       return 0;
-}
-
 static const struct rtc_class_ops mpc5121_rtc_ops = {
        .read_time = mpc5121_rtc_read_time,
        .set_time = mpc5121_rtc_set_time,
        .read_alarm = mpc5121_rtc_read_alarm,
        .set_alarm = mpc5121_rtc_set_alarm,
        .alarm_irq_enable = mpc5121_rtc_alarm_irq_enable,
-       .update_irq_enable = mpc5121_rtc_update_irq_enable,
 };
 
 static int __devinit mpc5121_rtc_probe(struct platform_device *op,
index bcd0cf6..b86bc32 100644 (file)
@@ -62,6 +62,17 @@ static inline int is_intr(u8 rtc_intr)
        return rtc_intr & RTC_IRQMASK;
 }
 
+static inline unsigned char vrtc_is_updating(void)
+{
+       unsigned char uip;
+       unsigned long flags;
+
+       spin_lock_irqsave(&rtc_lock, flags);
+       uip = (vrtc_cmos_read(RTC_FREQ_SELECT) & RTC_UIP);
+       spin_unlock_irqrestore(&rtc_lock, flags);
+       return uip;
+}
+
 /*
  * rtc_time's year contains the increment over 1900, but vRTC's YEAR
  * register can't be programmed to value larger than 0x64, so vRTC
@@ -76,7 +87,7 @@ static int mrst_read_time(struct device *dev, struct rtc_time *time)
 {
        unsigned long flags;
 
-       if (rtc_is_updating())
+       if (vrtc_is_updating())
                mdelay(20);
 
        spin_lock_irqsave(&rtc_lock, flags);
@@ -236,61 +247,21 @@ static int mrst_set_alarm(struct device *dev, struct rtc_wkalrm *t)
        return 0;
 }
 
-static int mrst_irq_set_state(struct device *dev, int enabled)
+/* Currently, the vRTC doesn't support UIE ON/OFF */
+static int mrst_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct mrst_rtc *mrst = dev_get_drvdata(dev);
        unsigned long   flags;
 
-       if (!mrst->irq)
-               return -ENXIO;
-
        spin_lock_irqsave(&rtc_lock, flags);
-
        if (enabled)
-               mrst_irq_enable(mrst, RTC_PIE);
+               mrst_irq_enable(mrst, RTC_AIE);
        else
-               mrst_irq_disable(mrst, RTC_PIE);
-
-       spin_unlock_irqrestore(&rtc_lock, flags);
-       return 0;
-}
-
-#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE)
-
-/* Currently, the vRTC doesn't support UIE ON/OFF */
-static int
-mrst_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
-{
-       struct mrst_rtc *mrst = dev_get_drvdata(dev);
-       unsigned long   flags;
-
-       switch (cmd) {
-       case RTC_AIE_OFF:
-       case RTC_AIE_ON:
-               if (!mrst->irq)
-                       return -EINVAL;
-               break;
-       default:
-               /* PIE ON/OFF is handled by mrst_irq_set_state() */
-               return -ENOIOCTLCMD;
-       }
-
-       spin_lock_irqsave(&rtc_lock, flags);
-       switch (cmd) {
-       case RTC_AIE_OFF:       /* alarm off */
                mrst_irq_disable(mrst, RTC_AIE);
-               break;
-       case RTC_AIE_ON:        /* alarm on */
-               mrst_irq_enable(mrst, RTC_AIE);
-               break;
-       }
        spin_unlock_irqrestore(&rtc_lock, flags);
        return 0;
 }
 
-#else
-#define        mrst_rtc_ioctl  NULL
-#endif
 
 #if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE)
 
@@ -317,13 +288,12 @@ static int mrst_procfs(struct device *dev, struct seq_file *seq)
 #endif
 
 static const struct rtc_class_ops mrst_rtc_ops = {
-       .ioctl          = mrst_rtc_ioctl,
        .read_time      = mrst_read_time,
        .set_time       = mrst_set_time,
        .read_alarm     = mrst_read_alarm,
        .set_alarm      = mrst_set_alarm,
        .proc           = mrst_procfs,
-       .irq_set_state  = mrst_irq_set_state,
+       .alarm_irq_enable = mrst_rtc_alarm_irq_enable,
 };
 
 static struct mrst_rtc mrst_rtc;
index b2fff0c..6782062 100644 (file)
@@ -82,7 +82,7 @@ static inline unsigned int msm6242_read(struct msm6242_priv *priv,
 static inline void msm6242_write(struct msm6242_priv *priv, unsigned int val,
                                unsigned int reg)
 {
-       return __raw_writel(val, &priv->regs[reg]);
+       __raw_writel(val, &priv->regs[reg]);
 }
 
 static inline void msm6242_set(struct msm6242_priv *priv, unsigned int val,
index bcca472..60627a7 100644 (file)
@@ -169,25 +169,19 @@ static int mv_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
        return 0;
 }
 
-static int mv_rtc_ioctl(struct device *dev, unsigned int cmd,
-                       unsigned long arg)
+static int mv_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
        void __iomem *ioaddr = pdata->ioaddr;
 
        if (pdata->irq < 0)
-               return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */
-       switch (cmd) {
-       case RTC_AIE_OFF:
-               writel(0, ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS);
-               break;
-       case RTC_AIE_ON:
+               return -EINVAL; /* fall back into rtc-dev's emulation */
+
+       if (enabled)
                writel(1, ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS);
-               break;
-       default:
-               return -ENOIOCTLCMD;
-       }
+       else
+               writel(0, ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS);
        return 0;
 }
 
@@ -216,7 +210,7 @@ static const struct rtc_class_ops mv_rtc_alarm_ops = {
        .set_time       = mv_rtc_set_time,
        .read_alarm     = mv_rtc_read_alarm,
        .set_alarm      = mv_rtc_set_alarm,
-       .ioctl          = mv_rtc_ioctl,
+       .alarm_irq_enable = mv_rtc_alarm_irq_enable,
 };
 
 static int __devinit mv_rtc_probe(struct platform_device *pdev)
index 0b06c1e..826ab64 100644 (file)
@@ -274,12 +274,6 @@ static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
        return 0;
 }
 
-static int mxc_rtc_update_irq_enable(struct device *dev, unsigned int enabled)
-{
-       mxc_rtc_irq_enable(dev, RTC_1HZ_BIT, enabled);
-       return 0;
-}
-
 /*
  * This function reads the current RTC time into tm in Gregorian date.
  */
@@ -368,7 +362,6 @@ static struct rtc_class_ops mxc_rtc_ops = {
        .read_alarm             = mxc_rtc_read_alarm,
        .set_alarm              = mxc_rtc_set_alarm,
        .alarm_irq_enable       = mxc_rtc_alarm_irq_enable,
-       .update_irq_enable      = mxc_rtc_update_irq_enable,
 };
 
 static int __init mxc_rtc_probe(struct platform_device *pdev)
index ddb0857..781068d 100644 (file)
@@ -134,20 +134,6 @@ static void nuc900_rtc_bin2bcd(struct device *dev, struct rtc_time *settm,
        gettm->bcd_hour = bin2bcd(settm->tm_hour) << 16;
 }
 
-static int nuc900_update_irq_enable(struct device *dev, unsigned int enabled)
-{
-       struct nuc900_rtc *rtc = dev_get_drvdata(dev);
-
-       if (enabled)
-               __raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)|
-                               (TICKINTENB), rtc->rtc_reg + REG_RTC_RIER);
-       else
-               __raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)&
-                               (~TICKINTENB), rtc->rtc_reg + REG_RTC_RIER);
-
-       return 0;
-}
-
 static int nuc900_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct nuc900_rtc *rtc = dev_get_drvdata(dev);
@@ -234,7 +220,6 @@ static struct rtc_class_ops nuc900_rtc_ops = {
        .read_alarm = nuc900_rtc_read_alarm,
        .set_alarm = nuc900_rtc_set_alarm,
        .alarm_irq_enable = nuc900_alarm_irq_enable,
-       .update_irq_enable = nuc900_update_irq_enable,
 };
 
 static int __devinit nuc900_rtc_probe(struct platform_device *pdev)
index e72b523..de0dd7b 100644 (file)
@@ -135,42 +135,17 @@ static irqreturn_t rtc_irq(int irq, void *rtc)
        return IRQ_HANDLED;
 }
 
-#ifdef CONFIG_RTC_INTF_DEV
-
-static int
-omap_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+static int omap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        u8 reg;
 
-       switch (cmd) {
-       case RTC_AIE_OFF:
-       case RTC_AIE_ON:
-       case RTC_UIE_OFF:
-       case RTC_UIE_ON:
-               break;
-       default:
-               return -ENOIOCTLCMD;
-       }
-
        local_irq_disable();
        rtc_wait_not_busy();
        reg = rtc_read(OMAP_RTC_INTERRUPTS_REG);
-       switch (cmd) {
-       /* AIE = Alarm Interrupt Enable */
-       case RTC_AIE_OFF:
-               reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;
-               break;
-       case RTC_AIE_ON:
+       if (enabled)
                reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;
-               break;
-       /* UIE = Update Interrupt Enable (1/second) */
-       case RTC_UIE_OFF:
-               reg &= ~OMAP_RTC_INTERRUPTS_IT_TIMER;
-               break;
-       case RTC_UIE_ON:
-               reg |= OMAP_RTC_INTERRUPTS_IT_TIMER;
-               break;
-       }
+       else
+               reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;
        rtc_wait_not_busy();
        rtc_write(reg, OMAP_RTC_INTERRUPTS_REG);
        local_irq_enable();
@@ -178,10 +153,6 @@ omap_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
        return 0;
 }
 
-#else
-#define        omap_rtc_ioctl  NULL
-#endif
-
 /* this hardware doesn't support "don't care" alarm fields */
 static int tm2bcd(struct rtc_time *tm)
 {
@@ -304,11 +275,11 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
 }
 
 static struct rtc_class_ops omap_rtc_ops = {
-       .ioctl          = omap_rtc_ioctl,
        .read_time      = omap_rtc_read_time,
        .set_time       = omap_rtc_set_time,
        .read_alarm     = omap_rtc_read_alarm,
        .set_alarm      = omap_rtc_set_alarm,
+       .alarm_irq_enable = omap_rtc_alarm_irq_enable,
 };
 
 static int omap_rtc_alarm;
index 25c0b3f..a633abc 100644 (file)
@@ -131,18 +131,12 @@ static int pcap_rtc_alarm_irq_enable(struct device *dev, unsigned int en)
        return pcap_rtc_irq_enable(dev, PCAP_IRQ_TODA, en);
 }
 
-static int pcap_rtc_update_irq_enable(struct device *dev, unsigned int en)
-{
-       return pcap_rtc_irq_enable(dev, PCAP_IRQ_1HZ, en);
-}
-
 static const struct rtc_class_ops pcap_rtc_ops = {
        .read_time = pcap_rtc_read_time,
        .read_alarm = pcap_rtc_read_alarm,
        .set_alarm = pcap_rtc_set_alarm,
        .set_mmss = pcap_rtc_set_mmss,
        .alarm_irq_enable = pcap_rtc_alarm_irq_enable,
-       .update_irq_enable = pcap_rtc_update_irq_enable,
 };
 
 static int __devinit pcap_rtc_probe(struct platform_device *pdev)
index 16edf94..f90c574 100644 (file)
@@ -106,25 +106,6 @@ pcf50633_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
        return 0;
 }
 
-static int
-pcf50633_rtc_update_irq_enable(struct device *dev, unsigned int enabled)
-{
-       struct pcf50633_rtc *rtc = dev_get_drvdata(dev);
-       int err;
-
-       if (enabled)
-               err = pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_SECOND);
-       else
-               err = pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_SECOND);
-
-       if (err < 0)
-               return err;
-
-       rtc->second_enabled = enabled;
-
-       return 0;
-}
-
 static int pcf50633_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
        struct pcf50633_rtc *rtc;
@@ -262,8 +243,7 @@ static struct rtc_class_ops pcf50633_rtc_ops = {
        .set_time               = pcf50633_rtc_set_time,
        .read_alarm             = pcf50633_rtc_read_alarm,
        .set_alarm              = pcf50633_rtc_set_alarm,
-       .alarm_irq_enable       = pcf50633_rtc_alarm_irq_enable,
-       .update_irq_enable      = pcf50633_rtc_update_irq_enable,
+       .alarm_irq_enable       = pcf50633_rtc_alarm_irq_enable,
 };
 
 static void pcf50633_rtc_irq(int irq, void *data)
index bbdb2f0..d554368 100644 (file)
@@ -35,11 +35,6 @@ static irqreturn_t pl030_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int pl030_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
-{
-       return -ENOIOCTLCMD;
-}
-
 static int pl030_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
        struct pl030_rtc *rtc = dev_get_drvdata(dev);
@@ -96,7 +91,6 @@ static int pl030_set_time(struct device *dev, struct rtc_time *tm)
 }
 
 static const struct rtc_class_ops pl030_ops = {
-       .ioctl          = pl030_ioctl,
        .read_time      = pl030_read_time,
        .set_time       = pl030_set_time,
        .read_alarm     = pl030_read_alarm,
index b7a6690..d829ea6 100644 (file)
@@ -293,57 +293,6 @@ static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
        return ret;
 }
 
-/* Periodic interrupt is only available in ST variants. */
-static int pl031_irq_set_state(struct device *dev, int enabled)
-{
-       struct pl031_local *ldata = dev_get_drvdata(dev);
-
-       if (enabled == 1) {
-               /* Clear any pending timer interrupt. */
-               writel(RTC_BIT_PI, ldata->base + RTC_ICR);
-
-               writel(readl(ldata->base + RTC_IMSC) | RTC_BIT_PI,
-                       ldata->base + RTC_IMSC);
-
-               /* Now start the timer */
-               writel(readl(ldata->base + RTC_TCR) | RTC_TCR_EN,
-                       ldata->base + RTC_TCR);
-
-       } else {
-               writel(readl(ldata->base + RTC_IMSC) & (~RTC_BIT_PI),
-                       ldata->base + RTC_IMSC);
-
-               /* Also stop the timer */
-               writel(readl(ldata->base + RTC_TCR) & (~RTC_TCR_EN),
-                       ldata->base + RTC_TCR);
-       }
-       /* Wait at least 1 RTC32 clock cycle to ensure next access
-        * to RTC_TCR will succeed.
-        */
-       udelay(40);
-
-       return 0;
-}
-
-static int pl031_irq_set_freq(struct device *dev, int freq)
-{
-       struct pl031_local *ldata = dev_get_drvdata(dev);
-
-       /* Cant set timer if it is already enabled */
-       if (readl(ldata->base + RTC_TCR) & RTC_TCR_EN) {
-               dev_err(dev, "can't change frequency while timer enabled\n");
-               return -EINVAL;
-       }
-
-       /* If self start bit in RTC_TCR is set timer will start here,
-        * but we never set that bit. Instead we start the timer when
-        * set_state is called with enabled == 1.
-        */
-       writel(RTC_TIMER_FREQ / freq, ldata->base + RTC_TLR);
-
-       return 0;
-}
-
 static int pl031_remove(struct amba_device *adev)
 {
        struct pl031_local *ldata = dev_get_drvdata(&adev->dev);
@@ -440,8 +389,6 @@ static struct rtc_class_ops stv1_pl031_ops = {
        .read_alarm = pl031_read_alarm,
        .set_alarm = pl031_set_alarm,
        .alarm_irq_enable = pl031_alarm_irq_enable,
-       .irq_set_state = pl031_irq_set_state,
-       .irq_set_freq = pl031_irq_set_freq,
 };
 
 /* And the second ST derivative */
@@ -451,8 +398,6 @@ static struct rtc_class_ops stv2_pl031_ops = {
        .read_alarm = pl031_stv2_read_alarm,
        .set_alarm = pl031_stv2_set_alarm,
        .alarm_irq_enable = pl031_alarm_irq_enable,
-       .irq_set_state = pl031_irq_set_state,
-       .irq_set_freq = pl031_irq_set_freq,
 };
 
 static struct amba_id pl031_ids[] = {
index c086fc3..0a59fda 100644 (file)
@@ -69,6 +69,14 @@ static int rtc_proc_show(struct seq_file *seq, void *offset)
                                alrm.enabled ? "yes" : "no");
                seq_printf(seq, "alrm_pending\t: %s\n",
                                alrm.pending ? "yes" : "no");
+               seq_printf(seq, "update IRQ enabled\t: %s\n",
+                       (rtc->uie_rtctimer.enabled) ? "yes" : "no");
+               seq_printf(seq, "periodic IRQ enabled\t: %s\n",
+                       (rtc->pie_enabled) ? "yes" : "no");
+               seq_printf(seq, "periodic IRQ frequency\t: %d\n",
+                       rtc->irq_freq);
+               seq_printf(seq, "max user IRQ frequency\t: %d\n",
+                       rtc->max_user_freq);
        }
 
        seq_printf(seq, "24hr\t\t: yes\n");
@@ -81,12 +89,16 @@ static int rtc_proc_show(struct seq_file *seq, void *offset)
 
 static int rtc_proc_open(struct inode *inode, struct file *file)
 {
+       int ret;
        struct rtc_device *rtc = PDE(inode)->data;
 
        if (!try_module_get(THIS_MODULE))
                return -ENODEV;
 
-       return single_open(file, rtc_proc_show, rtc);
+       ret = single_open(file, rtc_proc_show, rtc);
+       if (ret)
+               module_put(THIS_MODULE);
+       return ret;
 }
 
 static int rtc_proc_release(struct inode *inode, struct file *file)
index 29e867a..fc9f499 100644 (file)
@@ -209,32 +209,6 @@ static void pxa_rtc_release(struct device *dev)
        free_irq(pxa_rtc->irq_1Hz, dev);
 }
 
-static int pxa_periodic_irq_set_freq(struct device *dev, int freq)
-{
-       struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev);
-       int period_ms;
-
-       if (freq < 1 || freq > MAXFREQ_PERIODIC)
-               return -EINVAL;
-
-       period_ms = 1000 / freq;
-       rtc_writel(pxa_rtc, PIAR, period_ms);
-
-       return 0;
-}
-
-static int pxa_periodic_irq_set_state(struct device *dev, int enabled)
-{
-       struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev);
-
-       if (enabled)
-               rtsr_set_bits(pxa_rtc, RTSR_PIALE | RTSR_PICE);
-       else
-               rtsr_clear_bits(pxa_rtc, RTSR_PIALE | RTSR_PICE);
-
-       return 0;
-}
-
 static int pxa_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev);
@@ -250,21 +224,6 @@ static int pxa_alarm_irq_enable(struct device *dev, unsigned int enabled)
        return 0;
 }
 
-static int pxa_update_irq_enable(struct device *dev, unsigned int enabled)
-{
-       struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev);
-
-       spin_lock_irq(&pxa_rtc->lock);
-
-       if (enabled)
-               rtsr_set_bits(pxa_rtc, RTSR_HZE);
-       else
-               rtsr_clear_bits(pxa_rtc, RTSR_HZE);
-
-       spin_unlock_irq(&pxa_rtc->lock);
-       return 0;
-}
-
 static int pxa_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
        struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev);
@@ -346,10 +305,7 @@ static const struct rtc_class_ops pxa_rtc_ops = {
        .read_alarm = pxa_rtc_read_alarm,
        .set_alarm = pxa_rtc_set_alarm,
        .alarm_irq_enable = pxa_alarm_irq_enable,
-       .update_irq_enable = pxa_update_irq_enable,
        .proc = pxa_rtc_proc,
-       .irq_set_state = pxa_periodic_irq_set_state,
-       .irq_set_freq = pxa_periodic_irq_set_freq,
 };
 
 static int __init pxa_rtc_probe(struct platform_device *pdev)
index 36eb661..694da39 100644 (file)
@@ -76,7 +76,7 @@ static inline unsigned int rp5c01_read(struct rp5c01_priv *priv,
 static inline void rp5c01_write(struct rp5c01_priv *priv, unsigned int val,
                                unsigned int reg)
 {
-       return __raw_writel(val, &priv->regs[reg]);
+       __raw_writel(val, &priv->regs[reg]);
 }
 
 static void rp5c01_lock(struct rp5c01_priv *priv)
index dd14e20..85c1b84 100644 (file)
@@ -281,10 +281,8 @@ static int rs5c372_rtc_set_time(struct device *dev, struct rtc_time *tm)
        return rs5c372_set_datetime(to_i2c_client(dev), tm);
 }
 
-#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE)
 
-static int
-rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+static int rs5c_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct i2c_client       *client = to_i2c_client(dev);
        struct rs5c372          *rs5c = i2c_get_clientdata(client);
@@ -292,45 +290,19 @@ rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
        int                     status, addr;
 
        buf = rs5c->regs[RS5C_REG_CTRL1];
-       switch (cmd) {
-       case RTC_UIE_OFF:
-       case RTC_UIE_ON:
-               /* some 327a modes use a different IRQ pin for 1Hz irqs */
-               if (rs5c->type == rtc_rs5c372a
-                               && (buf & RS5C372A_CTRL1_SL1))
-                       return -ENOIOCTLCMD;
-       case RTC_AIE_OFF:
-       case RTC_AIE_ON:
-               /* these irq management calls only make sense for chips
-                * which are wired up to an IRQ.
-                */
-               if (!rs5c->has_irq)
-                       return -ENOIOCTLCMD;
-               break;
-       default:
-               return -ENOIOCTLCMD;
-       }
+
+       if (!rs5c->has_irq)
+               return -EINVAL;
 
        status = rs5c_get_regs(rs5c);
        if (status < 0)
                return status;
 
        addr = RS5C_ADDR(RS5C_REG_CTRL1);
-       switch (cmd) {
-       case RTC_AIE_OFF:       /* alarm off */
-               buf &= ~RS5C_CTRL1_AALE;
-               break;
-       case RTC_AIE_ON:        /* alarm on */
+       if (enabled)
                buf |= RS5C_CTRL1_AALE;
-               break;
-       case RTC_UIE_OFF:       /* update off */
-               buf &= ~RS5C_CTRL1_CT_MASK;
-               break;
-       case RTC_UIE_ON:        /* update on */
-               buf &= ~RS5C_CTRL1_CT_MASK;
-               buf |= RS5C_CTRL1_CT4;
-               break;
-       }
+       else
+               buf &= ~RS5C_CTRL1_AALE;
 
        if (i2c_smbus_write_byte_data(client, addr, buf) < 0) {
                printk(KERN_WARNING "%s: can't update alarm\n",
@@ -342,10 +314,6 @@ rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
        return status;
 }
 
-#else
-#define        rs5c_rtc_ioctl  NULL
-#endif
-
 
 /* NOTE:  Since RTC_WKALM_{RD,SET} were originally defined for EFI,
  * which only exposes a polled programming interface; and since
@@ -461,11 +429,11 @@ static int rs5c372_rtc_proc(struct device *dev, struct seq_file *seq)
 
 static const struct rtc_class_ops rs5c372_rtc_ops = {
        .proc           = rs5c372_rtc_proc,
-       .ioctl          = rs5c_rtc_ioctl,
        .read_time      = rs5c372_rtc_read_time,
        .set_time       = rs5c372_rtc_set_time,
        .read_alarm     = rs5c_read_alarm,
        .set_alarm      = rs5c_set_alarm,
+       .alarm_irq_enable = rs5c_rtc_alarm_irq_enable,
 };
 
 #if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE)
index af32a62..fde172f 100644 (file)
@@ -424,37 +424,12 @@ static int rx8025_alarm_irq_enable(struct device *dev, unsigned int enabled)
        return 0;
 }
 
-static int rx8025_irq_set_state(struct device *dev, int enabled)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct rx8025_data *rx8025 = i2c_get_clientdata(client);
-       int ctrl1;
-       int err;
-
-       if (client->irq <= 0)
-               return -ENXIO;
-
-       ctrl1 = rx8025->ctrl1 & ~RX8025_BIT_CTRL1_CT;
-       if (enabled)
-               ctrl1 |= RX8025_BIT_CTRL1_CT_1HZ;
-       if (ctrl1 != rx8025->ctrl1) {
-               rx8025->ctrl1 = ctrl1;
-               err = rx8025_write_reg(rx8025->client, RX8025_REG_CTRL1,
-                                      rx8025->ctrl1);
-               if (err)
-                       return err;
-       }
-
-       return 0;
-}
-
 static struct rtc_class_ops rx8025_rtc_ops = {
        .read_time = rx8025_get_time,
        .set_time = rx8025_set_time,
        .read_alarm = rx8025_read_alarm,
        .set_alarm = rx8025_set_alarm,
        .alarm_irq_enable = rx8025_alarm_irq_enable,
-       .irq_set_state  = rx8025_irq_set_state,
 };
 
 /*
index cf953ec..7149649 100644 (file)
@@ -77,47 +77,18 @@ static irqreturn_t s3c_rtc_tickirq(int irq, void *id)
 }
 
 /* Update control registers */
-static void s3c_rtc_setaie(int to)
+static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
 {
        unsigned int tmp;
 
-       pr_debug("%s: aie=%d\n", __func__, to);
+       pr_debug("%s: aie=%d\n", __func__, enabled);
 
        tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
 
-       if (to)
+       if (enabled)
                tmp |= S3C2410_RTCALM_ALMEN;
 
        writeb(tmp, s3c_rtc_base + S3C2410_RTCALM);
-}
-
-static int s3c_rtc_setpie(struct device *dev, int enabled)
-{
-       unsigned int tmp;
-
-       pr_debug("%s: pie=%d\n", __func__, enabled);
-
-       spin_lock_irq(&s3c_rtc_pie_lock);
-
-       if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
-               tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
-               tmp &= ~S3C64XX_RTCCON_TICEN;
-
-               if (enabled)
-                       tmp |= S3C64XX_RTCCON_TICEN;
-
-               writew(tmp, s3c_rtc_base + S3C2410_RTCCON);
-       } else {
-               tmp = readb(s3c_rtc_base + S3C2410_TICNT);
-               tmp &= ~S3C2410_TICNT_ENABLE;
-
-               if (enabled)
-                       tmp |= S3C2410_TICNT_ENABLE;
-
-               writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
-       }
-
-       spin_unlock_irq(&s3c_rtc_pie_lock);
 
        return 0;
 }
@@ -308,7 +279,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
 
        writeb(alrm_en, base + S3C2410_RTCALM);
 
-       s3c_rtc_setaie(alrm->enabled);
+       s3c_rtc_setaie(dev, alrm->enabled);
 
        return 0;
 }
@@ -377,8 +348,6 @@ static const struct rtc_class_ops s3c_rtcops = {
        .set_time       = s3c_rtc_settime,
        .read_alarm     = s3c_rtc_getalarm,
        .set_alarm      = s3c_rtc_setalarm,
-       .irq_set_freq   = s3c_rtc_setfreq,
-       .irq_set_state  = s3c_rtc_setpie,
        .proc           = s3c_rtc_proc,
        .alarm_irq_enable = s3c_rtc_setaie,
 };
@@ -440,7 +409,7 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev)
        rtc_device_unregister(rtc);
 
        s3c_rtc_setpie(&dev->dev, 0);
-       s3c_rtc_setaie(0);
+       s3c_rtc_setaie(&dev->dev, 0);
 
        clk_disable(rtc_clk);
        clk_put(rtc_clk);
index 88ea52b..0b40bb8 100644 (file)
@@ -43,7 +43,6 @@
 #define RTC_DEF_TRIM           0
 
 static const unsigned long RTC_FREQ = 1024;
-static unsigned long timer_freq;
 static struct rtc_time rtc_alarm;
 static DEFINE_SPINLOCK(sa1100_rtc_lock);
 
@@ -156,114 +155,11 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int sa1100_irq_set_freq(struct device *dev, int freq)
-{
-       if (freq < 1 || freq > timer_freq) {
-               return -EINVAL;
-       } else {
-               struct rtc_device *rtc = (struct rtc_device *)dev;
-
-               rtc->irq_freq = freq;
-
-               return 0;
-       }
-}
-
-static int rtc_timer1_count;
-
-static int sa1100_irq_set_state(struct device *dev, int enabled)
-{
-       spin_lock_irq(&sa1100_rtc_lock);
-       if (enabled) {
-               struct rtc_device *rtc = (struct rtc_device *)dev;
-
-               OSMR1 = timer_freq / rtc->irq_freq + OSCR;
-               OIER |= OIER_E1;
-               rtc_timer1_count = 1;
-       } else {
-               OIER &= ~OIER_E1;
-       }
-       spin_unlock_irq(&sa1100_rtc_lock);
-
-       return 0;
-}
-
-static inline int sa1100_timer1_retrigger(struct rtc_device *rtc)
-{
-       unsigned long diff;
-       unsigned long period = timer_freq / rtc->irq_freq;
-
-       spin_lock_irq(&sa1100_rtc_lock);
-
-       do {
-               OSMR1 += period;
-               diff = OSMR1 - OSCR;
-               /* If OSCR > OSMR1, diff is a very large number (unsigned
-                * math). This means we have a lost interrupt. */
-       } while (diff > period);
-       OIER |= OIER_E1;
-
-       spin_unlock_irq(&sa1100_rtc_lock);
-
-       return 0;
-}
-
-static irqreturn_t timer1_interrupt(int irq, void *dev_id)
-{
-       struct platform_device *pdev = to_platform_device(dev_id);
-       struct rtc_device *rtc = platform_get_drvdata(pdev);
-
-       /*
-        * If we match for the first time, rtc_timer1_count will be 1.
-        * Otherwise, we wrapped around (very unlikely but
-        * still possible) so compute the amount of missed periods.
-        * The match reg is updated only when the data is actually retrieved
-        * to avoid unnecessary interrupts.
-        */
-       OSSR = OSSR_M1; /* clear match on timer1 */
-
-       rtc_update_irq(rtc, rtc_timer1_count, RTC_PF | RTC_IRQF);
-
-       if (rtc_timer1_count == 1)
-               rtc_timer1_count =
-                       (rtc->irq_freq * ((1 << 30) / (timer_freq >> 2)));
-
-       /* retrigger. */
-       sa1100_timer1_retrigger(rtc);
-
-       return IRQ_HANDLED;
-}
-
-static int sa1100_rtc_read_callback(struct device *dev, int data)
-{
-       if (data & RTC_PF) {
-               struct rtc_device *rtc = (struct rtc_device *)dev;
-
-               /* interpolate missed periods and set match for the next */
-               unsigned long period = timer_freq / rtc->irq_freq;
-               unsigned long oscr = OSCR;
-               unsigned long osmr1 = OSMR1;
-               unsigned long missed = (oscr - osmr1)/period;
-               data += missed << 8;
-               OSSR = OSSR_M1; /* clear match on timer 1 */
-               OSMR1 = osmr1 + (missed + 1)*period;
-               /* Ensure we didn't miss another match in the mean time.
-                * Here we compare (match - OSCR) 8 instead of 0 --
-                * see comment in pxa_timer_interrupt() for explanation.
-                */
-               while ((signed long)((osmr1 = OSMR1) - OSCR) <= 8) {
-                       data += 0x100;
-                       OSSR = OSSR_M1; /* clear match on timer 1 */
-                       OSMR1 = osmr1 + period;
-               }
-       }
-       return data;
-}
-
 static int sa1100_rtc_open(struct device *dev)
 {
        int ret;
-       struct rtc_device *rtc = (struct rtc_device *)dev;
+       struct platform_device *plat_dev = to_platform_device(dev);
+       struct rtc_device *rtc = platform_get_drvdata(plat_dev);
 
        ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, IRQF_DISABLED,
                "rtc 1Hz", dev);
@@ -277,19 +173,11 @@ static int sa1100_rtc_open(struct device *dev)
                dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm);
                goto fail_ai;
        }
-       ret = request_irq(IRQ_OST1, timer1_interrupt, IRQF_DISABLED,
-               "rtc timer", dev);
-       if (ret) {
-               dev_err(dev, "IRQ %d already in use.\n", IRQ_OST1);
-               goto fail_pi;
-       }
        rtc->max_user_freq = RTC_FREQ;
-       sa1100_irq_set_freq(dev, RTC_FREQ);
+       rtc_irq_set_freq(rtc, NULL, RTC_FREQ);
 
        return 0;
 
- fail_pi:
-       free_irq(IRQ_RTCAlrm, dev);
  fail_ai:
        free_irq(IRQ_RTC1Hz, dev);
  fail_ui:
@@ -304,38 +192,19 @@ static void sa1100_rtc_release(struct device *dev)
        OSSR = OSSR_M1;
        spin_unlock_irq(&sa1100_rtc_lock);
 
-       free_irq(IRQ_OST1, dev);
        free_irq(IRQ_RTCAlrm, dev);
        free_irq(IRQ_RTC1Hz, dev);
 }
 
-
-static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd,
-               unsigned long arg)
+static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
-       switch (cmd) {
-       case RTC_AIE_OFF:
-               spin_lock_irq(&sa1100_rtc_lock);
-               RTSR &= ~RTSR_ALE;
-               spin_unlock_irq(&sa1100_rtc_lock);
-               return 0;
-       case RTC_AIE_ON:
-               spin_lock_irq(&sa1100_rtc_lock);
+       spin_lock_irq(&sa1100_rtc_lock);
+       if (enabled)
                RTSR |= RTSR_ALE;
-               spin_unlock_irq(&sa1100_rtc_lock);
-               return 0;
-       case RTC_UIE_OFF:
-               spin_lock_irq(&sa1100_rtc_lock);
-               RTSR &= ~RTSR_HZE;
-               spin_unlock_irq(&sa1100_rtc_lock);
-               return 0;
-       case RTC_UIE_ON:
-               spin_lock_irq(&sa1100_rtc_lock);
-               RTSR |= RTSR_HZE;
-               spin_unlock_irq(&sa1100_rtc_lock);
-               return 0;
-       }
-       return -ENOIOCTLCMD;
+       else
+               RTSR &= ~RTSR_ALE;
+       spin_unlock_irq(&sa1100_rtc_lock);
+       return 0;
 }
 
 static int sa1100_rtc_read_time(struct device *dev, struct rtc_time *tm)
@@ -385,39 +254,27 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 
 static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq)
 {
-       struct rtc_device *rtc = (struct rtc_device *)dev;
-
-       seq_printf(seq, "trim/divider\t: 0x%08x\n", (u32) RTTR);
-       seq_printf(seq, "update_IRQ\t: %s\n",
-                       (RTSR & RTSR_HZE) ? "yes" : "no");
-       seq_printf(seq, "periodic_IRQ\t: %s\n",
-                       (OIER & OIER_E1) ? "yes" : "no");
-       seq_printf(seq, "periodic_freq\t: %d\n", rtc->irq_freq);
-       seq_printf(seq, "RTSR\t\t: 0x%08x\n", (u32)RTSR);
+       seq_printf(seq, "trim/divider\t\t: 0x%08x\n", (u32) RTTR);
+       seq_printf(seq, "RTSR\t\t\t: 0x%08x\n", (u32)RTSR);
 
        return 0;
 }
 
 static const struct rtc_class_ops sa1100_rtc_ops = {
        .open = sa1100_rtc_open,
-       .read_callback = sa1100_rtc_read_callback,
        .release = sa1100_rtc_release,
-       .ioctl = sa1100_rtc_ioctl,
        .read_time = sa1100_rtc_read_time,
        .set_time = sa1100_rtc_set_time,
        .read_alarm = sa1100_rtc_read_alarm,
        .set_alarm = sa1100_rtc_set_alarm,
        .proc = sa1100_rtc_proc,
-       .irq_set_freq = sa1100_irq_set_freq,
-       .irq_set_state = sa1100_irq_set_state,
+       .alarm_irq_enable = sa1100_rtc_alarm_irq_enable,
 };
 
 static int sa1100_rtc_probe(struct platform_device *pdev)
 {
        struct rtc_device *rtc;
 
-       timer_freq = get_clock_tick_rate();
-
        /*
         * According to the manual we should be able to let RTTR be zero
         * and then a default diviser for a 32.768KHz clock is used.
@@ -443,11 +300,6 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, rtc);
 
-       /* Set the irq_freq */
-       /*TODO: Find out who is messing with this value after we initialize
-        * it here.*/
-       rtc->irq_freq = RTC_FREQ;
-
        /* Fix for a nasty initialization problem the in SA11xx RTSR register.
         * See also the comments in sa1100_rtc_interrupt().
         *
index 06e41ed..e55dc1a 100644 (file)
@@ -344,29 +344,10 @@ static inline void sh_rtc_setcie(struct device *dev, unsigned int enable)
        spin_unlock_irq(&rtc->lock);
 }
 
-static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+static int sh_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
-       struct sh_rtc *rtc = dev_get_drvdata(dev);
-       unsigned int ret = 0;
-
-       switch (cmd) {
-       case RTC_AIE_OFF:
-       case RTC_AIE_ON:
-               sh_rtc_setaie(dev, cmd == RTC_AIE_ON);
-               break;
-       case RTC_UIE_OFF:
-               rtc->periodic_freq &= ~PF_OXS;
-               sh_rtc_setcie(dev, 0);
-               break;
-       case RTC_UIE_ON:
-               rtc->periodic_freq |= PF_OXS;
-               sh_rtc_setcie(dev, 1);
-               break;
-       default:
-               ret = -ENOIOCTLCMD;
-       }
-
-       return ret;
+       sh_rtc_setaie(dev, enabled);
+       return 0;
 }
 
 static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
@@ -596,14 +577,12 @@ static int sh_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
 }
 
 static struct rtc_class_ops sh_rtc_ops = {
-       .ioctl          = sh_rtc_ioctl,
        .read_time      = sh_rtc_read_time,
        .set_time       = sh_rtc_set_time,
        .read_alarm     = sh_rtc_read_alarm,
        .set_alarm      = sh_rtc_set_alarm,
-       .irq_set_state  = sh_rtc_irq_set_state,
-       .irq_set_freq   = sh_rtc_irq_set_freq,
        .proc           = sh_rtc_proc,
+       .alarm_irq_enable = sh_rtc_alarm_irq_enable,
 };
 
 static int __init sh_rtc_probe(struct platform_device *pdev)
index 7e7d0c8..572e953 100644 (file)
@@ -115,19 +115,6 @@ static int stmp3xxx_alarm_irq_enable(struct device *dev, unsigned int enabled)
        return 0;
 }
 
-static int stmp3xxx_update_irq_enable(struct device *dev, unsigned int enabled)
-{
-       struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev);
-
-       if (enabled)
-               stmp3xxx_setl(BM_RTC_CTRL_ONEMSEC_IRQ_EN,
-                               rtc_data->io + HW_RTC_CTRL);
-       else
-               stmp3xxx_clearl(BM_RTC_CTRL_ONEMSEC_IRQ_EN,
-                               rtc_data->io + HW_RTC_CTRL);
-       return 0;
-}
-
 static int stmp3xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
 {
        struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev);
@@ -149,8 +136,6 @@ static int stmp3xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
 static struct rtc_class_ops stmp3xxx_rtc_ops = {
        .alarm_irq_enable =
                          stmp3xxx_alarm_irq_enable,
-       .update_irq_enable =
-                         stmp3xxx_update_irq_enable,
        .read_time      = stmp3xxx_rtc_gettime,
        .set_mmss       = stmp3xxx_rtc_set_mmss,
        .read_alarm     = stmp3xxx_rtc_read_alarm,
index 51725f7..7e96254 100644 (file)
@@ -50,24 +50,9 @@ static int test_rtc_proc(struct device *dev, struct seq_file *seq)
        return 0;
 }
 
-static int test_rtc_ioctl(struct device *dev, unsigned int cmd,
-       unsigned long arg)
+static int test_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
 {
-       /* We do support interrupts, they're generated
-        * using the sysfs interface.
-        */
-       switch (cmd) {
-       case RTC_PIE_ON:
-       case RTC_PIE_OFF:
-       case RTC_UIE_ON:
-       case RTC_UIE_OFF:
-       case RTC_AIE_ON:
-       case RTC_AIE_OFF:
-               return 0;
-
-       default:
-               return -ENOIOCTLCMD;
-       }
+       return 0;
 }
 
 static const struct rtc_class_ops test_rtc_ops = {
@@ -76,7 +61,7 @@ static const struct rtc_class_ops test_rtc_ops = {
        .read_alarm = test_rtc_read_alarm,
        .set_alarm = test_rtc_set_alarm,
        .set_mmss = test_rtc_set_mmss,
-       .ioctl = test_rtc_ioctl,
+       .alarm_irq_enable = test_rtc_alarm_irq_enable,
 };
 
 static ssize_t test_irq_show(struct device *dev,
@@ -93,11 +78,16 @@ static ssize_t test_irq_store(struct device *dev,
        struct rtc_device *rtc = platform_get_drvdata(plat_dev);
 
        retval = count;
-       if (strncmp(buf, "tick", 4) == 0)
+       if (strncmp(buf, "tick", 4) == 0 && rtc->pie_enabled)
                rtc_update_irq(rtc, 1, RTC_PF | RTC_IRQF);
-       else if (strncmp(buf, "alarm", 5) == 0)
-               rtc_update_irq(rtc, 1, RTC_AF | RTC_IRQF);
-       else if (strncmp(buf, "update", 6) == 0)
+       else if (strncmp(buf, "alarm", 5) == 0) {
+               struct rtc_wkalrm alrm;
+               int err = rtc_read_alarm(rtc, &alrm);
+
+               if (!err && alrm.enabled)
+                       rtc_update_irq(rtc, 1, RTC_AF | RTC_IRQF);
+
+       } else if (strncmp(buf, "update", 6) == 0 && rtc->uie_rtctimer.enabled)
                rtc_update_irq(rtc, 1, RTC_UF | RTC_IRQF);
        else
                retval = -EINVAL;
index ed1b868..f9a2799 100644 (file)
@@ -213,18 +213,6 @@ static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
        return ret;
 }
 
-static int twl_rtc_update_irq_enable(struct device *dev, unsigned enabled)
-{
-       int ret;
-
-       if (enabled)
-               ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
-       else
-               ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
-
-       return ret;
-}
-
 /*
  * Gets current TWL RTC time and date parameters.
  *
@@ -433,7 +421,6 @@ static struct rtc_class_ops twl_rtc_ops = {
        .read_alarm     = twl_rtc_read_alarm,
        .set_alarm      = twl_rtc_set_alarm,
        .alarm_irq_enable = twl_rtc_alarm_irq_enable,
-       .update_irq_enable = twl_rtc_update_irq_enable,
 };
 
 /*----------------------------------------------------------------------*/
index c324424..c5698cd 100644 (file)
@@ -207,59 +207,9 @@ static int vr41xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
        return 0;
 }
 
-static int vr41xx_rtc_irq_set_freq(struct device *dev, int freq)
-{
-       u64 count;
-
-       if (!is_power_of_2(freq))
-               return -EINVAL;
-       count = RTC_FREQUENCY;
-       do_div(count, freq);
-
-       spin_lock_irq(&rtc_lock);
-
-       periodic_count = count;
-       rtc1_write(RTCL1LREG, periodic_count);
-       rtc1_write(RTCL1HREG, periodic_count >> 16);
-
-       spin_unlock_irq(&rtc_lock);
-
-       return 0;
-}
-
-static int vr41xx_rtc_irq_set_state(struct device *dev, int enabled)
-{
-       if (enabled)
-               enable_irq(pie_irq);
-       else
-               disable_irq(pie_irq);
-
-       return 0;
-}
-
 static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
 {
        switch (cmd) {
-       case RTC_AIE_ON:
-               spin_lock_irq(&rtc_lock);
-
-               if (!alarm_enabled) {
-                       enable_irq(aie_irq);
-                       alarm_enabled = 1;
-               }
-
-               spin_unlock_irq(&rtc_lock);
-               break;
-       case RTC_AIE_OFF:
-               spin_lock_irq(&rtc_lock);
-
-               if (alarm_enabled) {
-                       disable_irq(aie_irq);
-                       alarm_enabled = 0;
-               }
-
-               spin_unlock_irq(&rtc_lock);
-               break;
        case RTC_EPOCH_READ:
                return put_user(epoch, (unsigned long __user *)arg);
        case RTC_EPOCH_SET:
@@ -275,6 +225,24 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
        return 0;
 }
 
+static int vr41xx_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       spin_lock_irq(&rtc_lock);
+       if (enabled) {
+               if (!alarm_enabled) {
+                       enable_irq(aie_irq);
+                       alarm_enabled = 1;
+               }
+       } else {
+               if (alarm_enabled) {
+                       disable_irq(aie_irq);
+                       alarm_enabled = 0;
+               }
+       }
+       spin_unlock_irq(&rtc_lock);
+       return 0;
+}
+
 static irqreturn_t elapsedtime_interrupt(int irq, void *dev_id)
 {
        struct platform_device *pdev = (struct platform_device *)dev_id;
@@ -310,8 +278,6 @@ static const struct rtc_class_ops vr41xx_rtc_ops = {
        .set_time       = vr41xx_rtc_set_time,
        .read_alarm     = vr41xx_rtc_read_alarm,
        .set_alarm      = vr41xx_rtc_set_alarm,
-       .irq_set_freq   = vr41xx_rtc_irq_set_freq,
-       .irq_set_state  = vr41xx_rtc_irq_set_state,
 };
 
 static int __devinit rtc_probe(struct platform_device *pdev)
index 82931dc..bdc909b 100644 (file)
@@ -315,21 +315,6 @@ static int wm831x_rtc_alarm_irq_enable(struct device *dev,
                return wm831x_rtc_stop_alarm(wm831x_rtc);
 }
 
-static int wm831x_rtc_update_irq_enable(struct device *dev,
-                                       unsigned int enabled)
-{
-       struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev);
-       int val;
-
-       if (enabled)
-               val = 1 << WM831X_RTC_PINT_FREQ_SHIFT;
-       else
-               val = 0;
-
-       return wm831x_set_bits(wm831x_rtc->wm831x, WM831X_RTC_CONTROL,
-                              WM831X_RTC_PINT_FREQ_MASK, val);
-}
-
 static irqreturn_t wm831x_alm_irq(int irq, void *data)
 {
        struct wm831x_rtc *wm831x_rtc = data;
@@ -354,7 +339,6 @@ static const struct rtc_class_ops wm831x_rtc_ops = {
        .read_alarm = wm831x_rtc_readalarm,
        .set_alarm = wm831x_rtc_setalarm,
        .alarm_irq_enable = wm831x_rtc_alarm_irq_enable,
-       .update_irq_enable = wm831x_rtc_update_irq_enable,
 };
 
 #ifdef CONFIG_PM
index 3d0dc76..6642142 100644 (file)
@@ -302,26 +302,6 @@ static int wm8350_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
        return ret;
 }
 
-static int wm8350_rtc_update_irq_enable(struct device *dev,
-                                       unsigned int enabled)
-{
-       struct wm8350 *wm8350 = dev_get_drvdata(dev);
-
-       /* Suppress duplicate changes since genirq nests enable and
-        * disable calls. */
-       if (enabled == wm8350->rtc.update_enabled)
-               return 0;
-
-       if (enabled)
-               wm8350_unmask_irq(wm8350, WM8350_IRQ_RTC_SEC);
-       else
-               wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC);
-
-       wm8350->rtc.update_enabled = enabled;
-
-       return 0;
-}
-
 static irqreturn_t wm8350_rtc_alarm_handler(int irq, void *data)
 {
        struct wm8350 *wm8350 = data;
@@ -357,7 +337,6 @@ static const struct rtc_class_ops wm8350_rtc_ops = {
        .read_alarm = wm8350_rtc_readalarm,
        .set_alarm = wm8350_rtc_setalarm,
        .alarm_irq_enable = wm8350_rtc_alarm_irq_enable,
-       .update_irq_enable = wm8350_rtc_update_irq_enable,
 };
 
 #ifdef CONFIG_PM
index 4155805..2b771f1 100644 (file)
@@ -319,6 +319,9 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device)
 
        private = (struct dasd_eckd_private *) device->private;
        lcu = private->lcu;
+       /* nothing to do if already disconnected */
+       if (!lcu)
+               return;
        device->discipline->get_uid(device, &uid);
        spin_lock_irqsave(&lcu->lock, flags);
        list_del_init(&device->alias_list);
@@ -680,6 +683,9 @@ int dasd_alias_remove_device(struct dasd_device *device)
 
        private = (struct dasd_eckd_private *) device->private;
        lcu = private->lcu;
+       /* nothing to do if already removed */
+       if (!lcu)
+               return 0;
        spin_lock_irqsave(&lcu->lock, flags);
        _remove_device_from_lcu(lcu, device);
        spin_unlock_irqrestore(&lcu->lock, flags);
index 318672d..a9fe23d 100644 (file)
@@ -72,7 +72,7 @@ static struct dasd_discipline dasd_eckd_discipline;
 static struct ccw_device_id dasd_eckd_ids[] = {
        { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3390, 0), .driver_info = 0x1},
        { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3390, 0), .driver_info = 0x2},
-       { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3390, 0), .driver_info = 0x3},
+       { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3380, 0), .driver_info = 0x3},
        { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3380, 0), .driver_info = 0x4},
        { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3380, 0), .driver_info = 0x5},
        { CCW_DEVICE_DEVTYPE (0x9343, 0, 0x9345, 0), .driver_info = 0x6},
index c881a14..1f6a4d8 100644 (file)
@@ -62,8 +62,8 @@ static int xpram_devs;
 /*
  * Parameter parsing functions.
  */
-static int __initdata devs = XPRAM_DEVS;
-static char __initdata *sizes[XPRAM_MAX_DEVS];
+static int devs = XPRAM_DEVS;
+static char *sizes[XPRAM_MAX_DEVS];
 
 module_param(devs, int, 0);
 module_param_array(sizes, charp, NULL, 0);
index 8cd58e4..5ad44da 100644 (file)
@@ -460,7 +460,8 @@ kbd_ioctl(struct kbd_data *kbd, struct file *file,
          unsigned int cmd, unsigned long arg)
 {
        void __user *argp;
-       int ct, perm;
+       unsigned int ct;
+       int perm;
 
        argp = (void __user *)arg;
 
index 7a242f0..267b54e 100644 (file)
@@ -280,6 +280,14 @@ tape_do_io_free(struct tape_device *device, struct tape_request *request)
        return rc;
 }
 
+static inline void
+tape_do_io_async_free(struct tape_device *device, struct tape_request *request)
+{
+       request->callback = (void *) tape_free_request;
+       request->callback_data = NULL;
+       tape_do_io_async(device, request);
+}
+
 extern int tape_oper_handler(int irq, int status);
 extern void tape_noper_handler(int irq, int status);
 extern int tape_open(struct tape_device *);
index c17f35b..c265111 100644 (file)
@@ -53,23 +53,11 @@ static void tape_34xx_delete_sbid_from(struct tape_device *, int);
  * Medium sense for 34xx tapes. There is no 'real' medium sense call.
  * So we just do a normal sense.
  */
-static int
-tape_34xx_medium_sense(struct tape_device *device)
+static void __tape_34xx_medium_sense(struct tape_request *request)
 {
-       struct tape_request *request;
-       unsigned char       *sense;
-       int                  rc;
-
-       request = tape_alloc_request(1, 32);
-       if (IS_ERR(request)) {
-               DBF_EXCEPTION(6, "MSEN fail\n");
-               return PTR_ERR(request);
-       }
-
-       request->op = TO_MSEN;
-       tape_ccw_end(request->cpaddr, SENSE, 32, request->cpdata);
+       struct tape_device *device = request->device;
+       unsigned char *sense;
 
-       rc = tape_do_io_interruptible(device, request);
        if (request->rc == 0) {
                sense = request->cpdata;
 
@@ -88,15 +76,47 @@ tape_34xx_medium_sense(struct tape_device *device)
                        device->tape_generic_status |= GMT_WR_PROT(~0);
                else
                        device->tape_generic_status &= ~GMT_WR_PROT(~0);
-       } else {
+       } else
                DBF_EVENT(4, "tape_34xx: medium sense failed with rc=%d\n",
                        request->rc);
-       }
        tape_free_request(request);
+}
+
+static int tape_34xx_medium_sense(struct tape_device *device)
+{
+       struct tape_request *request;
+       int rc;
+
+       request = tape_alloc_request(1, 32);
+       if (IS_ERR(request)) {
+               DBF_EXCEPTION(6, "MSEN fail\n");
+               return PTR_ERR(request);
+       }
 
+       request->op = TO_MSEN;
+       tape_ccw_end(request->cpaddr, SENSE, 32, request->cpdata);
+       rc = tape_do_io_interruptible(device, request);
+       __tape_34xx_medium_sense(request);
        return rc;
 }
 
+static void tape_34xx_medium_sense_async(struct tape_device *device)
+{
+       struct tape_request *request;
+
+       request = tape_alloc_request(1, 32);
+       if (IS_ERR(request)) {
+               DBF_EXCEPTION(6, "MSEN fail\n");
+               return;
+       }
+
+       request->op = TO_MSEN;
+       tape_ccw_end(request->cpaddr, SENSE, 32, request->cpdata);
+       request->callback = (void *) __tape_34xx_medium_sense;
+       request->callback_data = NULL;
+       tape_do_io_async(device, request);
+}
+
 struct tape_34xx_work {
        struct tape_device      *device;
        enum tape_op             op;
@@ -109,6 +129,9 @@ struct tape_34xx_work {
  * is inserted but cannot call tape_do_io* from an interrupt context.
  * Maybe that's useful for other actions we want to start from the
  * interrupt handler.
+ * Note: the work handler is called by the system work queue. The tape
+ * commands started by the handler need to be asynchrounous, otherwise
+ * a deadlock can occur e.g. in case of a deferred cc=1 (see __tape_do_irq).
  */
 static void
 tape_34xx_work_handler(struct work_struct *work)
@@ -119,7 +142,7 @@ tape_34xx_work_handler(struct work_struct *work)
 
        switch(p->op) {
                case TO_MSEN:
-                       tape_34xx_medium_sense(device);
+                       tape_34xx_medium_sense_async(device);
                        break;
                default:
                        DBF_EVENT(3, "T34XX: internal error: unknown work\n");
index fbe361f..de2e99e 100644 (file)
@@ -329,17 +329,17 @@ out:
 /*
  * Enable encryption
  */
-static int tape_3592_enable_crypt(struct tape_device *device)
+static struct tape_request *__tape_3592_enable_crypt(struct tape_device *device)
 {
        struct tape_request *request;
        char *data;
 
        DBF_EVENT(6, "tape_3592_enable_crypt\n");
        if (!crypt_supported(device))
-               return -ENOSYS;
+               return ERR_PTR(-ENOSYS);
        request = tape_alloc_request(2, 72);
        if (IS_ERR(request))
-               return PTR_ERR(request);
+               return request;
        data = request->cpdata;
        memset(data,0,72);
 
@@ -354,23 +354,42 @@ static int tape_3592_enable_crypt(struct tape_device *device)
        request->op = TO_CRYPT_ON;
        tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data);
        tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36);
+       return request;
+}
+
+static int tape_3592_enable_crypt(struct tape_device *device)
+{
+       struct tape_request *request;
+
+       request = __tape_3592_enable_crypt(device);
+       if (IS_ERR(request))
+               return PTR_ERR(request);
        return tape_do_io_free(device, request);
 }
 
+static void tape_3592_enable_crypt_async(struct tape_device *device)
+{
+       struct tape_request *request;
+
+       request = __tape_3592_enable_crypt(device);
+       if (!IS_ERR(request))
+               tape_do_io_async_free(device, request);
+}
+
 /*
  * Disable encryption
  */
-static int tape_3592_disable_crypt(struct tape_device *device)
+static struct tape_request *__tape_3592_disable_crypt(struct tape_device *device)
 {
        struct tape_request *request;
        char *data;
 
        DBF_EVENT(6, "tape_3592_disable_crypt\n");
        if (!crypt_supported(device))
-               return -ENOSYS;
+               return ERR_PTR(-ENOSYS);
        request = tape_alloc_request(2, 72);
        if (IS_ERR(request))
-               return PTR_ERR(request);
+               return request;
        data = request->cpdata;
        memset(data,0,72);
 
@@ -383,9 +402,28 @@ static int tape_3592_disable_crypt(struct tape_device *device)
        tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data);
        tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36);
 
+       return request;
+}
+
+static int tape_3592_disable_crypt(struct tape_device *device)
+{
+       struct tape_request *request;
+
+       request = __tape_3592_disable_crypt(device);
+       if (IS_ERR(request))
+               return PTR_ERR(request);
        return tape_do_io_free(device, request);
 }
 
+static void tape_3592_disable_crypt_async(struct tape_device *device)
+{
+       struct tape_request *request;
+
+       request = __tape_3592_disable_crypt(device);
+       if (!IS_ERR(request))
+               tape_do_io_async_free(device, request);
+}
+
 /*
  * IOCTL: Set encryption status
  */
@@ -457,8 +495,7 @@ tape_3590_ioctl(struct tape_device *device, unsigned int cmd, unsigned long arg)
 /*
  * SENSE Medium: Get Sense data about medium state
  */
-static int
-tape_3590_sense_medium(struct tape_device *device)
+static int tape_3590_sense_medium(struct tape_device *device)
 {
        struct tape_request *request;
 
@@ -470,6 +507,18 @@ tape_3590_sense_medium(struct tape_device *device)
        return tape_do_io_free(device, request);
 }
 
+static void tape_3590_sense_medium_async(struct tape_device *device)
+{
+       struct tape_request *request;
+
+       request = tape_alloc_request(1, 128);
+       if (IS_ERR(request))
+               return;
+       request->op = TO_MSEN;
+       tape_ccw_end(request->cpaddr, MEDIUM_SENSE, 128, request->cpdata);
+       tape_do_io_async_free(device, request);
+}
+
 /*
  * MTTELL: Tell block. Return the number of block relative to current file.
  */
@@ -546,15 +595,14 @@ tape_3590_read_opposite(struct tape_device *device,
  * 2. The attention msg is written to the "read subsystem data" buffer.
  * In this case we probably should print it to the console.
  */
-static int
-tape_3590_read_attmsg(struct tape_device *device)
+static void tape_3590_read_attmsg_async(struct tape_device *device)
 {
        struct tape_request *request;
        char *buf;
 
        request = tape_alloc_request(3, 4096);
        if (IS_ERR(request))
-               return PTR_ERR(request);
+               return;
        request->op = TO_READ_ATTMSG;
        buf = request->cpdata;
        buf[0] = PREP_RD_SS_DATA;
@@ -562,12 +610,15 @@ tape_3590_read_attmsg(struct tape_device *device)
        tape_ccw_cc(request->cpaddr, PERFORM_SS_FUNC, 12, buf);
        tape_ccw_cc(request->cpaddr + 1, READ_SS_DATA, 4096 - 12, buf + 12);
        tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL);
-       return tape_do_io_free(device, request);
+       tape_do_io_async_free(device, request);
 }
 
 /*
  * These functions are used to schedule follow-up actions from within an
  * interrupt context (like unsolicited interrupts).
+ * Note: the work handler is called by the system work queue. The tape
+ * commands started by the handler need to be asynchrounous, otherwise
+ * a deadlock can occur e.g. in case of a deferred cc=1 (see __tape_do_irq).
  */
 struct work_handler_data {
        struct tape_device *device;
@@ -583,16 +634,16 @@ tape_3590_work_handler(struct work_struct *work)
 
        switch (p->op) {
        case TO_MSEN:
-               tape_3590_sense_medium(p->device);
+               tape_3590_sense_medium_async(p->device);
                break;
        case TO_READ_ATTMSG:
-               tape_3590_read_attmsg(p->device);
+               tape_3590_read_attmsg_async(p->device);
                break;
        case TO_CRYPT_ON:
-               tape_3592_enable_crypt(p->device);
+               tape_3592_enable_crypt_async(p->device);
                break;
        case TO_CRYPT_OFF:
-               tape_3592_disable_crypt(p->device);
+               tape_3592_disable_crypt_async(p->device);
                break;
        default:
                DBF_EVENT(3, "T3590: work handler undefined for "
index e9fff2b..5640c89 100644 (file)
@@ -476,7 +476,7 @@ static inline void inbound_primed(struct qdio_q *q, int count)
 static int get_inbound_buffer_frontier(struct qdio_q *q)
 {
        int count, stop;
-       unsigned char state;
+       unsigned char state = 0;
 
        /*
         * Don't check 128 buffers, as otherwise qdio_inbound_q_moved
@@ -643,7 +643,7 @@ void qdio_inbound_processing(unsigned long data)
 static int get_outbound_buffer_frontier(struct qdio_q *q)
 {
        int count, stop;
-       unsigned char state;
+       unsigned char state = 0;
 
        if (need_siga_sync(q))
                if (((queue_type(q) != QDIO_IQDIO_QFMT) &&
index 65ebee0..b6a6356 100644 (file)
@@ -565,7 +565,7 @@ static int netiucv_callback_connreq(struct iucv_path *path,
        struct iucv_event ev;
        int rc;
 
-       if (memcmp(iucvMagic, ipuser, sizeof(ipuser)))
+       if (memcmp(iucvMagic, ipuser, 16))
                /* ipuser must match iucvMagic. */
                return -EINVAL;
        rc = -EINVAL;
index 29f848b..019ae58 100644 (file)
@@ -988,16 +988,30 @@ static void qeth_get_channel_path_desc(struct qeth_card *card)
        chp_dsc = (struct channelPath_dsc *)ccw_device_get_chp_desc(ccwdev, 0);
        if (chp_dsc != NULL) {
                /* CHPP field bit 6 == 1 -> single queue */
-               if ((chp_dsc->chpp & 0x02) == 0x02)
+               if ((chp_dsc->chpp & 0x02) == 0x02) {
+                       if ((atomic_read(&card->qdio.state) !=
+                               QETH_QDIO_UNINITIALIZED) &&
+                           (card->qdio.no_out_queues == 4))
+                               /* change from 4 to 1 outbound queues */
+                               qeth_free_qdio_buffers(card);
                        card->qdio.no_out_queues = 1;
+                       if (card->qdio.default_out_queue != 0)
+                               dev_info(&card->gdev->dev,
+                                       "Priority Queueing not supported\n");
+                       card->qdio.default_out_queue = 0;
+               } else {
+                       if ((atomic_read(&card->qdio.state) !=
+                               QETH_QDIO_UNINITIALIZED) &&
+                           (card->qdio.no_out_queues == 1)) {
+                               /* change from 1 to 4 outbound queues */
+                               qeth_free_qdio_buffers(card);
+                               card->qdio.default_out_queue = 2;
+                       }
+                       card->qdio.no_out_queues = 4;
+               }
                card->info.func_level = 0x4100 + chp_dsc->desc;
                kfree(chp_dsc);
        }
-       if (card->qdio.no_out_queues == 1) {
-               card->qdio.default_out_queue = 0;
-               dev_info(&card->gdev->dev,
-                       "Priority Queueing not supported\n");
-       }
        QETH_DBF_TEXT_(SETUP, 2, "nr:%x", card->qdio.no_out_queues);
        QETH_DBF_TEXT_(SETUP, 2, "lvl:%02x", card->info.func_level);
        return;
@@ -1832,33 +1846,6 @@ static inline int qeth_get_initial_mtu_for_card(struct qeth_card *card)
        }
 }
 
-static inline int qeth_get_max_mtu_for_card(int cardtype)
-{
-       switch (cardtype) {
-
-       case QETH_CARD_TYPE_UNKNOWN:
-       case QETH_CARD_TYPE_OSD:
-       case QETH_CARD_TYPE_OSN:
-       case QETH_CARD_TYPE_OSM:
-       case QETH_CARD_TYPE_OSX:
-               return 61440;
-       case QETH_CARD_TYPE_IQD:
-               return 57344;
-       default:
-               return 1500;
-       }
-}
-
-static inline int qeth_get_mtu_out_of_mpc(int cardtype)
-{
-       switch (cardtype) {
-       case QETH_CARD_TYPE_IQD:
-               return 1;
-       default:
-               return 0;
-       }
-}
-
 static inline int qeth_get_mtu_outof_framesize(int framesize)
 {
        switch (framesize) {
@@ -1881,10 +1868,9 @@ static inline int qeth_mtu_is_valid(struct qeth_card *card, int mtu)
        case QETH_CARD_TYPE_OSD:
        case QETH_CARD_TYPE_OSM:
        case QETH_CARD_TYPE_OSX:
-               return ((mtu >= 576) && (mtu <= 61440));
        case QETH_CARD_TYPE_IQD:
                return ((mtu >= 576) &&
-                       (mtu <= card->info.max_mtu + 4096 - 32));
+                       (mtu <= card->info.max_mtu));
        case QETH_CARD_TYPE_OSN:
        case QETH_CARD_TYPE_UNKNOWN:
        default:
@@ -1907,7 +1893,7 @@ static int qeth_ulp_enable_cb(struct qeth_card *card, struct qeth_reply *reply,
        memcpy(&card->token.ulp_filter_r,
               QETH_ULP_ENABLE_RESP_FILTER_TOKEN(iob->data),
               QETH_MPC_TOKEN_LENGTH);
-       if (qeth_get_mtu_out_of_mpc(card->info.type)) {
+       if (card->info.type == QETH_CARD_TYPE_IQD) {
                memcpy(&framesize, QETH_ULP_ENABLE_RESP_MAX_MTU(iob->data), 2);
                mtu = qeth_get_mtu_outof_framesize(framesize);
                if (!mtu) {
@@ -1915,12 +1901,21 @@ static int qeth_ulp_enable_cb(struct qeth_card *card, struct qeth_reply *reply,
                        QETH_DBF_TEXT_(SETUP, 2, "  rc%d", iob->rc);
                        return 0;
                }
-               card->info.max_mtu = mtu;
+               if (card->info.initial_mtu && (card->info.initial_mtu != mtu)) {
+                       /* frame size has changed */
+                       if (card->dev &&
+                           ((card->dev->mtu == card->info.initial_mtu) ||
+                            (card->dev->mtu > mtu)))
+                               card->dev->mtu = mtu;
+                       qeth_free_qdio_buffers(card);
+               }
                card->info.initial_mtu = mtu;
+               card->info.max_mtu = mtu;
                card->qdio.in_buf_size = mtu + 2 * PAGE_SIZE;
        } else {
                card->info.initial_mtu = qeth_get_initial_mtu_for_card(card);
-               card->info.max_mtu = qeth_get_max_mtu_for_card(card->info.type);
+               card->info.max_mtu = *(__u16 *)QETH_ULP_ENABLE_RESP_MAX_MTU(
+                       iob->data);
                card->qdio.in_buf_size = QETH_IN_BUF_SIZE_DEFAULT;
        }
 
@@ -3775,6 +3770,47 @@ static inline int qeth_get_qdio_q_format(struct qeth_card *card)
        }
 }
 
+static void qeth_determine_capabilities(struct qeth_card *card)
+{
+       int rc;
+       int length;
+       char *prcd;
+       struct ccw_device *ddev;
+       int ddev_offline = 0;
+
+       QETH_DBF_TEXT(SETUP, 2, "detcapab");
+       ddev = CARD_DDEV(card);
+       if (!ddev->online) {
+               ddev_offline = 1;
+               rc = ccw_device_set_online(ddev);
+               if (rc) {
+                       QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
+                       goto out;
+               }
+       }
+
+       rc = qeth_read_conf_data(card, (void **) &prcd, &length);
+       if (rc) {
+               QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n",
+                       dev_name(&card->gdev->dev), rc);
+               QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
+               goto out_offline;
+       }
+       qeth_configure_unitaddr(card, prcd);
+       qeth_configure_blkt_default(card, prcd);
+       kfree(prcd);
+
+       rc = qdio_get_ssqd_desc(ddev, &card->ssqd);
+       if (rc)
+               QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc);
+
+out_offline:
+       if (ddev_offline == 1)
+               ccw_device_set_offline(ddev);
+out:
+       return;
+}
+
 static int qeth_qdio_establish(struct qeth_card *card)
 {
        struct qdio_initialize init_data;
@@ -3905,6 +3941,7 @@ int qeth_core_hardsetup_card(struct qeth_card *card)
 
        QETH_DBF_TEXT(SETUP, 2, "hrdsetup");
        atomic_set(&card->force_alloc_skb, 0);
+       qeth_get_channel_path_desc(card);
 retry:
        if (retries)
                QETH_DBF_MESSAGE(2, "%s Retrying to do IDX activates.\n",
@@ -3933,6 +3970,7 @@ retriable:
                else
                        goto retry;
        }
+       qeth_determine_capabilities(card);
        qeth_init_tokens(card);
        qeth_init_func_level(card);
        rc = qeth_idx_activate_channel(&card->read, qeth_idx_read_cb);
@@ -4202,41 +4240,6 @@ void qeth_core_free_discipline(struct qeth_card *card)
        card->discipline.ccwgdriver = NULL;
 }
 
-static void qeth_determine_capabilities(struct qeth_card *card)
-{
-       int rc;
-       int length;
-       char *prcd;
-
-       QETH_DBF_TEXT(SETUP, 2, "detcapab");
-       rc = ccw_device_set_online(CARD_DDEV(card));
-       if (rc) {
-               QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
-               goto out;
-       }
-
-
-       rc = qeth_read_conf_data(card, (void **) &prcd, &length);
-       if (rc) {
-               QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n",
-                       dev_name(&card->gdev->dev), rc);
-               QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
-               goto out_offline;
-       }
-       qeth_configure_unitaddr(card, prcd);
-       qeth_configure_blkt_default(card, prcd);
-       kfree(prcd);
-
-       rc = qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd);
-       if (rc)
-               QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc);
-
-out_offline:
-       ccw_device_set_offline(CARD_DDEV(card));
-out:
-       return;
-}
-
 static int qeth_core_probe_device(struct ccwgroup_device *gdev)
 {
        struct qeth_card *card;
index 2ac8f6a..ada0fe7 100644 (file)
@@ -573,13 +573,13 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card,
                case IPA_RC_L2_DUP_LAYER3_MAC:
                        dev_warn(&card->gdev->dev,
                                "MAC address %pM already exists\n",
-                               card->dev->dev_addr);
+                               cmd->data.setdelmac.mac);
                        break;
                case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP:
                case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP:
                        dev_warn(&card->gdev->dev,
                                "MAC address %pM is not authorized\n",
-                               card->dev->dev_addr);
+                               cmd->data.setdelmac.mac);
                        break;
                default:
                        break;
index 65e1cf1..207b7d7 100644 (file)
@@ -60,7 +60,7 @@ static struct iucv_handler smsg_handler = {
 static int smsg_path_pending(struct iucv_path *path, u8 ipvmid[8],
                             u8 ipuser[16])
 {
-       if (strncmp(ipvmid, "*MSG    ", sizeof(ipvmid)) != 0)
+       if (strncmp(ipvmid, "*MSG    ", 8) != 0)
                return -EINVAL;
        /* Path pending from *MSG. */
        return iucv_path_accept(path, &smsg_handler, "SMSGIUCV        ", NULL);
index 475c31a..77b26f5 100644 (file)
@@ -2,7 +2,7 @@
 *******************************************************************************
 **        O.S   : Linux
 **   FILE NAME  : arcmsr.h
-**        BY    : Erich Chen
+**        BY    : Nick Cheng
 **   Description: SCSI RAID Device Driver for
 **                ARECA RAID Host adapter
 *******************************************************************************
 struct device_attribute;
 /*The limit of outstanding scsi command that firmware can handle*/
 #define ARCMSR_MAX_OUTSTANDING_CMD                                             256
-#define ARCMSR_MAX_FREECCB_NUM                                                 320
-#define ARCMSR_DRIVER_VERSION               "Driver Version 1.20.00.15 2010/02/02"
+#ifdef CONFIG_XEN
+       #define ARCMSR_MAX_FREECCB_NUM  160
+#else
+       #define ARCMSR_MAX_FREECCB_NUM  320
+#endif
+#define ARCMSR_DRIVER_VERSION               "Driver Version 1.20.00.15 2010/08/05"
 #define ARCMSR_SCSI_INITIATOR_ID                                               255
 #define ARCMSR_MAX_XFER_SECTORS                                                        512
 #define ARCMSR_MAX_XFER_SECTORS_B                                              4096
@@ -60,7 +64,6 @@ struct device_attribute;
 #define ARCMSR_MAX_HBB_POSTQUEUE                                               264
 #define ARCMSR_MAX_XFER_LEN                                                    0x26000 /* 152K */
 #define ARCMSR_CDB_SG_PAGE_LENGTH                                              256 
-#define SCSI_CMD_ARECA_SPECIFIC                                                0xE1
 #ifndef PCI_DEVICE_ID_ARECA_1880
 #define PCI_DEVICE_ID_ARECA_1880 0x1880
  #endif
index a4e04c5..acdae33 100644 (file)
@@ -2,7 +2,7 @@
 *******************************************************************************
 **        O.S   : Linux
 **   FILE NAME  : arcmsr_attr.c
-**        BY    : Erich Chen
+**        BY    : Nick Cheng
 **   Description: attributes exported to sysfs and device host
 *******************************************************************************
 ** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved
index 1cadcd6..984bd52 100644 (file)
@@ -2,7 +2,7 @@
 *******************************************************************************
 **        O.S   : Linux
 **   FILE NAME  : arcmsr_hba.c
-**        BY    : Erich Chen
+**        BY    : Nick Cheng
 **   Description: SCSI RAID Device Driver for
 **                ARECA RAID Host adapter
 *******************************************************************************
@@ -76,7 +76,7 @@ MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/16xx/1880) SATA/SAS RAID Host Bus Adapte
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_VERSION(ARCMSR_DRIVER_VERSION);
 static int sleeptime = 10;
-static int retrycount = 30;
+static int retrycount = 12;
 wait_queue_head_t wait_q;
 static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
                                        struct scsi_cmnd *cmd);
@@ -187,7 +187,6 @@ int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd)
                if (isleep > 0) {
                        msleep(isleep*1000);
                }
-               printk(KERN_NOTICE "wake-up\n");
                return 0;
 }
 
@@ -921,7 +920,6 @@ static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb,
 }
 
 static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct CommandControlBlock *pCCB, bool error)
-
 {
        int id, lun;
        if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) {
@@ -948,7 +946,7 @@ static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct Comma
                                , pCCB->startdone
                                , atomic_read(&acb->ccboutstandingcount));
                  return;
-               }
+       }
        arcmsr_report_ccb_state(acb, pCCB, error);
 }
 
@@ -981,7 +979,7 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
        case ACB_ADAPTER_TYPE_B: {
                struct MessageUnit_B *reg = acb->pmuB;
                /*clear all outbound posted Q*/
-               writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, &reg->iop2drv_doorbell); /* clear doorbell interrupt */
+               writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); /* clear doorbell interrupt */
                for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) {
                        if ((flag_ccb = readl(&reg->done_qbuffer[i])) != 0) {
                                writel(0, &reg->done_qbuffer[i]);
@@ -1511,7 +1509,6 @@ static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb)
                arcmsr_drain_donequeue(acb, pCCB, error);
        }
 }
-
 static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb)
 {
        uint32_t index;
@@ -2106,10 +2103,6 @@ static int arcmsr_queue_command_lck(struct scsi_cmnd *cmd,
        if (atomic_read(&acb->ccboutstandingcount) >=
                        ARCMSR_MAX_OUTSTANDING_CMD)
                return SCSI_MLQUEUE_HOST_BUSY;
-       if ((scsicmd == SCSI_CMD_ARECA_SPECIFIC)) {
-               printk(KERN_NOTICE "Receiveing SCSI_CMD_ARECA_SPECIFIC command..\n");
-               return 0;
-       }
        ccb = arcmsr_get_freeccb(acb);
        if (!ccb)
                return SCSI_MLQUEUE_HOST_BUSY;
@@ -2393,6 +2386,7 @@ static int arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb,
        int index, rtn;
        bool error;
        polling_hbb_ccb_retry:
+
        poll_count++;
        /* clear doorbell interrupt */
        writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
@@ -2663,6 +2657,7 @@ static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb)
 {
        struct MessageUnit_A __iomem *reg = acb->pmuA;
        if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0 ) || ((acb->acb_flags & ACB_F_ABORT) != 0 )){
+               mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
                return;
        } else {
                acb->fw_flag = FW_NORMAL;
@@ -2670,8 +2665,10 @@ static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb)
                        atomic_set(&acb->rq_map_token, 16);
                }
                atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
-               if (atomic_dec_and_test(&acb->rq_map_token))
+               if (atomic_dec_and_test(&acb->rq_map_token)) {
+                       mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
                        return;
+               }
                writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
                mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
        }
@@ -2682,15 +2679,18 @@ static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb)
 {
        struct MessageUnit_B __iomem *reg = acb->pmuB;
        if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0 ) || ((acb->acb_flags & ACB_F_ABORT) != 0 )){
+               mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
                return;
        } else {
                acb->fw_flag = FW_NORMAL;
                if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) {
-                       atomic_set(&acb->rq_map_token,16);
+                       atomic_set(&acb->rq_map_token, 16);
                }
                atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
-               if(atomic_dec_and_test(&acb->rq_map_token))
+               if (atomic_dec_and_test(&acb->rq_map_token)) {
+                       mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
                        return;
+               }
                writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell);
                mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
        }
@@ -2701,6 +2701,7 @@ static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb)
 {
        struct MessageUnit_C __iomem *reg = acb->pmuC;
        if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || ((acb->acb_flags & ACB_F_ABORT) != 0)) {
+               mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
                return;
        } else {
                acb->fw_flag = FW_NORMAL;
@@ -2708,8 +2709,10 @@ static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb)
                        atomic_set(&acb->rq_map_token, 16);
                }
                atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
-               if (atomic_dec_and_test(&acb->rq_map_token))
+               if (atomic_dec_and_test(&acb->rq_map_token)) {
+                       mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
                        return;
+               }
                writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
                writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
                mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
@@ -2897,6 +2900,8 @@ static uint8_t arcmsr_iop_reset(struct AdapterControlBlock *acb)
        uint32_t intmask_org;
        uint8_t rtnval = 0x00;
        int i = 0;
+       unsigned long flags;
+
        if (atomic_read(&acb->ccboutstandingcount) != 0) {
                /* disable all outbound interrupt */
                intmask_org = arcmsr_disable_outbound_ints(acb);
@@ -2907,7 +2912,12 @@ static uint8_t arcmsr_iop_reset(struct AdapterControlBlock *acb)
                for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
                        ccb = acb->pccb_pool[i];
                        if (ccb->startdone == ARCMSR_CCB_START) {
-                               arcmsr_ccb_complete(ccb);
+                               scsi_dma_unmap(ccb->pcmd);
+                               ccb->startdone = ARCMSR_CCB_DONE;
+                               ccb->ccb_flags = 0;
+                               spin_lock_irqsave(&acb->ccblist_lock, flags);
+                               list_add_tail(&ccb->list, &acb->ccb_free_list);
+                               spin_unlock_irqrestore(&acb->ccblist_lock, flags);
                        }
                }
                atomic_set(&acb->ccboutstandingcount, 0);
@@ -2920,8 +2930,7 @@ static uint8_t arcmsr_iop_reset(struct AdapterControlBlock *acb)
 
 static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
 {
-       struct AdapterControlBlock *acb =
-               (struct AdapterControlBlock *)cmd->device->host->hostdata;
+       struct AdapterControlBlock *acb;
        uint32_t intmask_org, outbound_doorbell;
        int retry_count = 0;
        int rtn = FAILED;
@@ -2971,31 +2980,16 @@ sleep_again:
                                atomic_set(&acb->rq_map_token, 16);
                                atomic_set(&acb->ante_token_value, 16);
                                acb->fw_flag = FW_NORMAL;
-                               init_timer(&acb->eternal_timer);
-                               acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ);
-                               acb->eternal_timer.data = (unsigned long) acb;
-                               acb->eternal_timer.function = &arcmsr_request_device_map;
-                               add_timer(&acb->eternal_timer);
+                               mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
                                acb->acb_flags &= ~ACB_F_BUS_RESET;
                                rtn = SUCCESS;
                                printk(KERN_ERR "arcmsr: scsi  bus reset eh returns with success\n");
                        } else {
                                acb->acb_flags &= ~ACB_F_BUS_RESET;
-                               if (atomic_read(&acb->rq_map_token) == 0) {
-                                       atomic_set(&acb->rq_map_token, 16);
-                                       atomic_set(&acb->ante_token_value, 16);
-                                       acb->fw_flag = FW_NORMAL;
-                                       init_timer(&acb->eternal_timer);
-                                               acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ);
-                                       acb->eternal_timer.data = (unsigned long) acb;
-                                       acb->eternal_timer.function = &arcmsr_request_device_map;
-                                       add_timer(&acb->eternal_timer);
-                               } else {
-                                       atomic_set(&acb->rq_map_token, 16);
-                                       atomic_set(&acb->ante_token_value, 16);
-                                       acb->fw_flag = FW_NORMAL;
-                                       mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
-                               }
+                               atomic_set(&acb->rq_map_token, 16);
+                               atomic_set(&acb->ante_token_value, 16);
+                               acb->fw_flag = FW_NORMAL;
+                               mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
                                rtn = SUCCESS;
                        }
                        break;
@@ -3007,21 +3001,10 @@ sleep_again:
                                rtn = FAILED;
                        } else {
                                acb->acb_flags &= ~ACB_F_BUS_RESET;
-                               if (atomic_read(&acb->rq_map_token) == 0) {
-                                       atomic_set(&acb->rq_map_token, 16);
-                                       atomic_set(&acb->ante_token_value, 16);
-                                       acb->fw_flag = FW_NORMAL;
-                                       init_timer(&acb->eternal_timer);
-                                               acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ);
-                                       acb->eternal_timer.data = (unsigned long) acb;
-                                       acb->eternal_timer.function = &arcmsr_request_device_map;
-                                       add_timer(&acb->eternal_timer);
-                               } else {
-                                       atomic_set(&acb->rq_map_token, 16);
-                                       atomic_set(&acb->ante_token_value, 16);
-                                       acb->fw_flag = FW_NORMAL;
-                                       mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
-                               }
+                               atomic_set(&acb->rq_map_token, 16);
+                               atomic_set(&acb->ante_token_value, 16);
+                               acb->fw_flag = FW_NORMAL;
+                               mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
                                rtn = SUCCESS;
                        }
                        break;
@@ -3067,31 +3050,16 @@ sleep:
                                atomic_set(&acb->rq_map_token, 16);
                                atomic_set(&acb->ante_token_value, 16);
                                acb->fw_flag = FW_NORMAL;
-                               init_timer(&acb->eternal_timer);
-                               acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6 * HZ);
-                               acb->eternal_timer.data = (unsigned long) acb;
-                               acb->eternal_timer.function = &arcmsr_request_device_map;
-                               add_timer(&acb->eternal_timer);
+                               mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
                                acb->acb_flags &= ~ACB_F_BUS_RESET;
                                rtn = SUCCESS;
                                printk(KERN_ERR "arcmsr: scsi bus reset eh returns with success\n");
                        } else {
                                acb->acb_flags &= ~ACB_F_BUS_RESET;
-                               if (atomic_read(&acb->rq_map_token) == 0) {
-                                       atomic_set(&acb->rq_map_token, 16);
-                                       atomic_set(&acb->ante_token_value, 16);
-                                       acb->fw_flag = FW_NORMAL;
-                                       init_timer(&acb->eternal_timer);
-                                               acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ);
-                                       acb->eternal_timer.data = (unsigned long) acb;
-                                       acb->eternal_timer.function = &arcmsr_request_device_map;
-                                       add_timer(&acb->eternal_timer);
-                               } else {
-                                       atomic_set(&acb->rq_map_token, 16);
-                                       atomic_set(&acb->ante_token_value, 16);
-                                       acb->fw_flag = FW_NORMAL;
-                                       mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
-                               }
+                               atomic_set(&acb->rq_map_token, 16);
+                               atomic_set(&acb->ante_token_value, 16);
+                               acb->fw_flag = FW_NORMAL;
+                               mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
                                rtn = SUCCESS;
                        }
                        break;
index 79cefbe..638c72b 100644 (file)
@@ -4277,7 +4277,7 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
 
        snprintf(phba->wq_name, sizeof(phba->wq_name), "beiscsi_q_irq%u",
                 phba->shost->host_no);
-       phba->wq = create_workqueue(phba->wq_name);
+       phba->wq = alloc_workqueue(phba->wq_name, WQ_MEM_RECLAIM, 1);
        if (!phba->wq) {
                shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
                                "Failed to allocate work queue\n");
index 5815cbe..9a7aaf5 100644 (file)
@@ -646,6 +646,7 @@ void sas_scsi_recover_host(struct Scsi_Host *shost)
 
        spin_lock_irqsave(shost->host_lock, flags);
        list_splice_init(&shost->eh_cmd_q, &eh_work_q);
+       shost->host_eh_scheduled = 0;
        spin_unlock_irqrestore(shost->host_lock, flags);
 
        SAS_DPRINTK("Enter %s\n", __func__);
index b2a8170..9ead039 100644 (file)
@@ -2176,9 +2176,9 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)
                /* adjust hba_queue_depth, reply_free_queue_depth,
                 * and queue_size
                 */
-               ioc->hba_queue_depth -= queue_diff;
-               ioc->reply_free_queue_depth -= queue_diff;
-               queue_size -= queue_diff;
+               ioc->hba_queue_depth -= (queue_diff / 2);
+               ioc->reply_free_queue_depth -= (queue_diff / 2);
+               queue_size = facts->MaxReplyDescriptorPostQueueDepth;
        }
        ioc->reply_post_queue_depth = queue_size;
 
@@ -3941,6 +3941,8 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)
 static void
 _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
 {
+       mpt2sas_scsih_reset_handler(ioc, reset_phase);
+       mpt2sas_ctl_reset_handler(ioc, reset_phase);
        switch (reset_phase) {
        case MPT2_IOC_PRE_RESET:
                dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
@@ -3971,8 +3973,6 @@ _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
                    "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
                break;
        }
-       mpt2sas_scsih_reset_handler(ioc, reset_phase);
-       mpt2sas_ctl_reset_handler(ioc, reset_phase);
 }
 
 /**
@@ -4026,6 +4026,7 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
 {
        int r;
        unsigned long flags;
+       u8 pe_complete = ioc->wait_for_port_enable_to_complete;
 
        dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
            __func__));
@@ -4068,6 +4069,14 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
        if (r)
                goto out;
        _base_reset_handler(ioc, MPT2_IOC_AFTER_RESET);
+
+       /* If this hard reset is called while port enable is active, then
+        * there is no reason to call make_ioc_operational
+        */
+       if (pe_complete) {
+               r = -EFAULT;
+               goto out;
+       }
        r = _base_make_ioc_operational(ioc, sleep_flag);
        if (!r)
                _base_reset_handler(ioc, MPT2_IOC_DONE_RESET);
index eda347c..5ded3db 100644 (file)
@@ -819,7 +819,7 @@ _scsih_is_end_device(u32 device_info)
 }
 
 /**
- * mptscsih_get_scsi_lookup - returns scmd entry
+ * _scsih_scsi_lookup_get - returns scmd entry
  * @ioc: per adapter object
  * @smid: system request message index
  *
@@ -831,6 +831,28 @@ _scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
        return ioc->scsi_lookup[smid - 1].scmd;
 }
 
+/**
+ * _scsih_scsi_lookup_get_clear - returns scmd entry
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Returns the smid stored scmd pointer.
+ * Then will derefrence the stored scmd pointer.
+ */
+static inline struct scsi_cmnd *
+_scsih_scsi_lookup_get_clear(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+       unsigned long flags;
+       struct scsi_cmnd *scmd;
+
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       scmd = ioc->scsi_lookup[smid - 1].scmd;
+       ioc->scsi_lookup[smid - 1].scmd = NULL;
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+
+       return scmd;
+}
+
 /**
  * _scsih_scsi_lookup_find_by_scmd - scmd lookup
  * @ioc: per adapter object
@@ -2981,9 +3003,6 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
        u16 handle;
 
        for (i = 0 ; i < event_data->NumEntries; i++) {
-               if (event_data->PHY[i].PhyStatus &
-                   MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT)
-                       continue;
                handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
                if (!handle)
                        continue;
@@ -3210,7 +3229,7 @@ _scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)
        u16 count = 0;
 
        for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
-               scmd = _scsih_scsi_lookup_get(ioc, smid);
+               scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
                if (!scmd)
                        continue;
                count++;
@@ -3804,7 +3823,7 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
        u32 response_code = 0;
 
        mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
-       scmd = _scsih_scsi_lookup_get(ioc, smid);
+       scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
        if (scmd == NULL)
                return 1;
 
@@ -5005,6 +5024,12 @@ _scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
                     event_data);
 #endif
 
+       /* In MPI Revision K (0xC), the internal device reset complete was
+        * implemented, so avoid setting tm_busy flag for older firmware.
+        */
+       if ((ioc->facts.HeaderVersion >> 8) < 0xC)
+               return;
+
        if (event_data->ReasonCode !=
            MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&
           event_data->ReasonCode !=
@@ -5099,6 +5124,7 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
     struct fw_event_work *fw_event)
 {
        struct scsi_cmnd *scmd;
+       struct scsi_device *sdev;
        u16 smid, handle;
        u32 lun;
        struct MPT2SAS_DEVICE *sas_device_priv_data;
@@ -5109,12 +5135,17 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
        Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data;
 #endif
        u16 ioc_status;
+       unsigned long flags;
+       int r;
+
        dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "broadcast primative: "
            "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum,
            event_data->PortWidth));
        dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
            __func__));
 
+       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+       ioc->broadcast_aen_busy = 0;
        termination_count = 0;
        query_count = 0;
        mpi_reply = ioc->tm_cmds.reply;
@@ -5122,7 +5153,8 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
                scmd = _scsih_scsi_lookup_get(ioc, smid);
                if (!scmd)
                        continue;
-               sas_device_priv_data = scmd->device->hostdata;
+               sdev = scmd->device;
+               sas_device_priv_data = sdev->hostdata;
                if (!sas_device_priv_data || !sas_device_priv_data->sas_target)
                        continue;
                 /* skip hidden raid components */
@@ -5138,6 +5170,7 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
                lun = sas_device_priv_data->lun;
                query_count++;
 
+               spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
                mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun,
                    MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, NULL);
                ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
@@ -5147,14 +5180,20 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
                    (mpi_reply->ResponseCode ==
                     MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
                     mpi_reply->ResponseCode ==
-                    MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
+                    MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC)) {
+                       spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
                        continue;
-
-               mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun,
-                   MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30, NULL);
+               }
+               r = mpt2sas_scsih_issue_tm(ioc, handle, sdev->channel, sdev->id,
+                   sdev->lun, MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30,
+                   scmd);
+               if (r == FAILED)
+                       sdev_printk(KERN_WARNING, sdev, "task abort: FAILED "
+                           "scmd(%p)\n", scmd);
                termination_count += le32_to_cpu(mpi_reply->TerminationCount);
+               spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
        }
-       ioc->broadcast_aen_busy = 0;
+       spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
 
        dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
            "%s - exit, query_count = %d termination_count = %d\n",
@@ -6626,6 +6665,7 @@ _scsih_remove(struct pci_dev *pdev)
                destroy_workqueue(wq);
 
        /* release all the volumes */
+       _scsih_ir_shutdown(ioc);
        list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list,
            list) {
                if (raid_device->starget) {
index 44578b5..d3e58d7 100644 (file)
@@ -1561,6 +1561,7 @@ qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport)
 {
        struct Scsi_Host *host = rport_to_shost(rport);
        fc_port_t *fcport = *(fc_port_t **)rport->dd_data;
+       unsigned long flags;
 
        if (!fcport)
                return;
@@ -1573,10 +1574,10 @@ qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport)
         * Transport has effectively 'deleted' the rport, clear
         * all local references.
         */
-       spin_lock_irq(host->host_lock);
+       spin_lock_irqsave(host->host_lock, flags);
        fcport->rport = fcport->drport = NULL;
        *((fc_port_t **)rport->dd_data) = NULL;
-       spin_unlock_irq(host->host_lock);
+       spin_unlock_irqrestore(host->host_lock, flags);
 
        if (test_bit(ABORT_ISP_ACTIVE, &fcport->vha->dpc_flags))
                return;
index f948e1a..d9479c3 100644 (file)
@@ -2505,11 +2505,12 @@ qla2x00_rport_del(void *data)
 {
        fc_port_t *fcport = data;
        struct fc_rport *rport;
+       unsigned long flags;
 
-       spin_lock_irq(fcport->vha->host->host_lock);
+       spin_lock_irqsave(fcport->vha->host->host_lock, flags);
        rport = fcport->drport ? fcport->drport: fcport->rport;
        fcport->drport = NULL;
-       spin_unlock_irq(fcport->vha->host->host_lock);
+       spin_unlock_irqrestore(fcport->vha->host->host_lock, flags);
        if (rport)
                fc_remote_port_delete(rport);
 }
@@ -2879,6 +2880,7 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
        struct fc_rport_identifiers rport_ids;
        struct fc_rport *rport;
        struct qla_hw_data *ha = vha->hw;
+       unsigned long flags;
 
        qla2x00_rport_del(fcport);
 
@@ -2893,9 +2895,9 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
                    "Unable to allocate fc remote port!\n");
                return;
        }
-       spin_lock_irq(fcport->vha->host->host_lock);
+       spin_lock_irqsave(fcport->vha->host->host_lock, flags);
        *((fc_port_t **)rport->dd_data) = fcport;
-       spin_unlock_irq(fcport->vha->host->host_lock);
+       spin_unlock_irqrestore(fcport->vha->host->host_lock, flags);
 
        rport->supported_classes = fcport->supported_classes;
 
index c194c23..e90f7c1 100644 (file)
@@ -349,7 +349,7 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha)
                                "Can't create request queue\n");
                        goto fail;
                }
-               ha->wq = create_workqueue("qla2xxx_wq");
+               ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 1);
                vha->req = ha->req_q_map[req];
                options |= BIT_1;
                for (ques = 1; ques < ha->max_rsp_queues; ques++) {
@@ -562,7 +562,6 @@ qla2xxx_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)
        }
        if (atomic_read(&fcport->state) != FCS_ONLINE) {
                if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
-                       atomic_read(&fcport->state) == FCS_DEVICE_LOST ||
                        atomic_read(&base_vha->loop_state) == LOOP_DEAD) {
                        cmd->result = DID_NO_CONNECT << 16;
                        goto qc24_fail_command;
@@ -2513,6 +2512,7 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport,
 {
        struct fc_rport *rport;
        scsi_qla_host_t *base_vha;
+       unsigned long flags;
 
        if (!fcport->rport)
                return;
@@ -2520,9 +2520,9 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport,
        rport = fcport->rport;
        if (defer) {
                base_vha = pci_get_drvdata(vha->hw->pdev);
-               spin_lock_irq(vha->host->host_lock);
+               spin_lock_irqsave(vha->host->host_lock, flags);
                fcport->drport = rport;
-               spin_unlock_irq(vha->host->host_lock);
+               spin_unlock_irqrestore(vha->host->host_lock, flags);
                set_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags);
                qla2xxx_wake_dpc(base_vha);
        } else
@@ -3282,10 +3282,10 @@ qla2x00_do_dpc(void *data)
 
        set_user_nice(current, -20);
 
+       set_current_state(TASK_INTERRUPTIBLE);
        while (!kthread_should_stop()) {
                DEBUG3(printk("qla2x00: DPC handler sleeping\n"));
 
-               set_current_state(TASK_INTERRUPTIBLE);
                schedule();
                __set_current_state(TASK_RUNNING);
 
@@ -3454,7 +3454,9 @@ qla2x00_do_dpc(void *data)
                qla2x00_do_dpc_all_vps(base_vha);
 
                ha->dpc_active = 0;
+               set_current_state(TASK_INTERRUPTIBLE);
        } /* End of while(1) */
+       __set_current_state(TASK_RUNNING);
 
        DEBUG(printk("scsi(%ld): DPC handler exiting\n", base_vha->host_no));
 
index 7b31093..a6b2d72 100644 (file)
@@ -1671,7 +1671,7 @@ static int do_device_access(struct scsi_cmnd *scmd,
                            unsigned long long lba, unsigned int num, int write)
 {
        int ret;
-       unsigned int block, rest = 0;
+       unsigned long long block, rest = 0;
        int (*func)(struct scsi_cmnd *, unsigned char *, int);
 
        func = write ? fetch_to_dev_buffer : fill_from_dev_buffer;
index 9045c52..fb2bb35 100644 (file)
@@ -443,7 +443,7 @@ static void scsi_run_queue(struct request_queue *q)
                                        &sdev->request_queue->queue_flags);
                if (flagset)
                        queue_flag_set(QUEUE_FLAG_REENTER, sdev->request_queue);
-               __blk_run_queue(sdev->request_queue);
+               __blk_run_queue(sdev->request_queue, false);
                if (flagset)
                        queue_flag_clear(QUEUE_FLAG_REENTER, sdev->request_queue);
                spin_unlock(sdev->request_queue->queue_lock);
index c399be9..f672820 100644 (file)
@@ -629,7 +629,7 @@ static int __init scsi_tgt_init(void)
        if (!scsi_tgt_cmd_cache)
                return -ENOMEM;
 
-       scsi_tgtd = create_workqueue("scsi_tgtd");
+       scsi_tgtd = alloc_workqueue("scsi_tgtd", 0, 1);
        if (!scsi_tgtd) {
                err = -ENOMEM;
                goto free_kmemcache;
index 998c01b..5c3ccfc 100644 (file)
@@ -3829,7 +3829,7 @@ fc_bsg_goose_queue(struct fc_rport *rport)
                  !test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags);
        if (flagset)
                queue_flag_set(QUEUE_FLAG_REENTER, rport->rqst_q);
-       __blk_run_queue(rport->rqst_q);
+       __blk_run_queue(rport->rqst_q, false);
        if (flagset)
                queue_flag_clear(QUEUE_FLAG_REENTER, rport->rqst_q);
        spin_unlock_irqrestore(rport->rqst_q->queue_lock, flags);
index de885a0..f33e2dd 100644 (file)
@@ -173,7 +173,8 @@ int intc_set_priority(unsigned int irq, unsigned int prio)
        return 0;
 }
 
-#define VALID(x) (x | 0x80)
+#define SENSE_VALID_FLAG 0x80
+#define VALID(x) (x | SENSE_VALID_FLAG)
 
 static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
        [IRQ_TYPE_EDGE_FALLING] = VALID(0),
@@ -201,7 +202,8 @@ static int intc_set_type(struct irq_data *data, unsigned int type)
        ihp = intc_find_irq(d->sense, d->nr_sense, irq);
        if (ihp) {
                addr = INTC_REG(d, _INTC_ADDR_E(ihp->handle), 0);
-               intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle, value);
+               intc_reg_fns[_INTC_FN(ihp->handle)](addr, ihp->handle,
+                                                   value & ~SENSE_VALID_FLAG);
        }
 
        return 0;
index 9592883..a429b01 100644 (file)
@@ -1557,9 +1557,7 @@ static int __devinit pxa2xx_spi_probe(struct platform_device *pdev)
        drv_data->ssp = ssp;
 
        master->dev.parent = &pdev->dev;
-#ifdef CONFIG_OF
        master->dev.of_node = pdev->dev.of_node;
-#endif
        /* the spi->mode bits understood by this driver: */
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
 
index 351d8a3..378e504 100644 (file)
@@ -7,10 +7,9 @@
 #include <linux/of_device.h>
 #include <linux/spi/pxa2xx_spi.h>
 
-struct awesome_struct {
+struct ce4100_info {
        struct ssp_device ssp;
-       struct platform_device spi_pdev;
-       struct pxa2xx_spi_master spi_pdata;
+       struct platform_device *spi_pdev;
 };
 
 static DEFINE_MUTEX(ssp_lock);
@@ -51,23 +50,15 @@ void pxa_ssp_free(struct ssp_device *ssp)
 }
 EXPORT_SYMBOL_GPL(pxa_ssp_free);
 
-static void plat_dev_release(struct device *dev)
-{
-       struct awesome_struct *as = container_of(dev,
-                       struct awesome_struct, spi_pdev.dev);
-
-       of_device_node_put(&as->spi_pdev.dev);
-}
-
 static int __devinit ce4100_spi_probe(struct pci_dev *dev,
                const struct pci_device_id *ent)
 {
        int ret;
        resource_size_t phys_beg;
        resource_size_t phys_len;
-       struct awesome_struct *spi_info;
+       struct ce4100_info *spi_info;
        struct platform_device *pdev;
-       struct pxa2xx_spi_master *spi_pdata;
+       struct pxa2xx_spi_master spi_pdata;
        struct ssp_device *ssp;
 
        ret = pci_enable_device(dev);
@@ -84,33 +75,28 @@ static int __devinit ce4100_spi_probe(struct pci_dev *dev,
                return ret;
        }
 
+       pdev = platform_device_alloc("pxa2xx-spi", dev->devfn);
        spi_info = kzalloc(sizeof(*spi_info), GFP_KERNEL);
-       if (!spi_info) {
+       if (!pdev || !spi_info ) {
                ret = -ENOMEM;
-               goto err_kz;
+               goto err_nomem;
        }
-       ssp = &spi_info->ssp;
-       pdev = &spi_info->spi_pdev;
-       spi_pdata =  &spi_info->spi_pdata;
+       memset(&spi_pdata, 0, sizeof(spi_pdata));
+       spi_pdata.num_chipselect = dev->devfn;
 
-       pdev->name = "pxa2xx-spi";
-       pdev->id = dev->devfn;
-       pdev->dev.parent = &dev->dev;
-       pdev->dev.platform_data = &spi_info->spi_pdata;
+       ret = platform_device_add_data(pdev, &spi_pdata, sizeof(spi_pdata));
+       if (ret)
+               goto err_nomem;
 
-#ifdef CONFIG_OF
+       pdev->dev.parent = &dev->dev;
        pdev->dev.of_node = dev->dev.of_node;
-#endif
-       pdev->dev.release = plat_dev_release;
-
-       spi_pdata->num_chipselect = dev->devfn;
-
+       ssp = &spi_info->ssp;
        ssp->phys_base = pci_resource_start(dev, 0);
        ssp->mmio_base = ioremap(phys_beg, phys_len);
        if (!ssp->mmio_base) {
                dev_err(&pdev->dev, "failed to ioremap() registers\n");
                ret = -EIO;
-               goto err_remap;
+               goto err_nomem;
        }
        ssp->irq = dev->irq;
        ssp->port_id = pdev->id;
@@ -122,7 +108,7 @@ static int __devinit ce4100_spi_probe(struct pci_dev *dev,
 
        pci_set_drvdata(dev, spi_info);
 
-       ret = platform_device_register(pdev);
+       ret = platform_device_add(pdev);
        if (ret)
                goto err_dev_add;
 
@@ -135,27 +121,21 @@ err_dev_add:
        mutex_unlock(&ssp_lock);
        iounmap(ssp->mmio_base);
 
-err_remap:
-       kfree(spi_info);
-
-err_kz:
+err_nomem:
        release_mem_region(phys_beg, phys_len);
-
+       platform_device_put(pdev);
+       kfree(spi_info);
        return ret;
 }
 
 static void __devexit ce4100_spi_remove(struct pci_dev *dev)
 {
-       struct awesome_struct *spi_info;
-       struct platform_device *pdev;
+       struct ce4100_info *spi_info;
        struct ssp_device *ssp;
 
        spi_info = pci_get_drvdata(dev);
-
        ssp = &spi_info->ssp;
-       pdev = &spi_info->spi_pdev;
-
-       platform_device_unregister(pdev);
+       platform_device_unregister(spi_info->spi_pdev);
 
        iounmap(ssp->mmio_base);
        release_mem_region(pci_resource_start(dev, 0),
@@ -171,7 +151,6 @@ static void __devexit ce4100_spi_remove(struct pci_dev *dev)
 }
 
 static struct pci_device_id ce4100_spi_devices[] __devinitdata = {
-
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e6a) },
        { },
 };
index 56f60c8..2c665fc 100644 (file)
@@ -509,9 +509,11 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
        bytes_done = 0;
 
        while (bytes_done < t->len) {
+               void *rx_buf = t->rx_buf ? t->rx_buf + bytes_done : NULL;
+               const void *tx_buf = t->tx_buf ? t->tx_buf + bytes_done : NULL;
                n = sh_msiof_spi_txrx_once(p, tx_fifo, rx_fifo,
-                                          t->tx_buf + bytes_done,
-                                          t->rx_buf + bytes_done,
+                                          tx_buf,
+                                          rx_buf,
                                           words, bits);
                if (n < 0)
                        break;
index 7adaef6..4d2c75d 100644 (file)
@@ -351,14 +351,12 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-#ifdef CONFIG_OF
 static const struct of_device_id xilinx_spi_of_match[] = {
        { .compatible = "xlnx,xps-spi-2.00.a", },
        { .compatible = "xlnx,xps-spi-2.00.b", },
        {}
 };
 MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
-#endif
 
 struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
        u32 irq, s16 bus_num, int num_cs, int little_endian, int bits_per_word)
@@ -394,9 +392,7 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
 
        master->bus_num = bus_num;
        master->num_chipselect = num_cs;
-#ifdef CONFIG_OF
        master->dev.of_node = dev->of_node;
-#endif
 
        xspi->mem = *mem;
        xspi->irq = irq;
@@ -539,9 +535,7 @@ static struct platform_driver xilinx_spi_driver = {
        .driver = {
                .name = XILINX_SPI_NAME,
                .owner = THIS_MODULE,
-#ifdef CONFIG_OF
                .of_match_table = xilinx_spi_of_match,
-#endif
        },
 };
 
index c7345db..f853379 100644 (file)
@@ -733,7 +733,7 @@ int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
 
        /* Fetch the vendor specific tuples. */
        res = pcmcia_loop_tuple(bus->host_pcmcia, SSB_PCMCIA_CIS,
-                               ssb_pcmcia_do_get_invariants, sprom);
+                               ssb_pcmcia_do_get_invariants, iv);
        if ((res == 0) || (res == -ENOSPC))
                return 0;
 
index 0e298db..29b8ab4 100644 (file)
@@ -360,8 +360,8 @@ int PSSendOps(void *arg)
                status = 1;
                goto complete;
        }
-        len = (firmware->size > MAX_BDADDR_FORMAT_LENGTH)? MAX_BDADDR_FORMAT_LENGTH: firmware->size;
-       memcpy(config_bdaddr, firmware->data,len);
+       len = min(firmware->size, MAX_BDADDR_FORMAT_LENGTH - 1);
+       memcpy(config_bdaddr, firmware->data, len);
        config_bdaddr[len] = '\0';
        write_bdaddr(hdev,config_bdaddr,BDADDR_TYPE_STRING);
                A_RELEASE_FIRMWARE(firmware);
index bdd629d..cd8392b 100644 (file)
@@ -209,11 +209,8 @@ static void wl_ops_stop(struct ieee80211_hw *hw)
        struct wl_info *wl = hw->priv;
        ASSERT(wl);
        WL_LOCK(wl);
-       wl_down(wl);
        ieee80211_stop_queues(hw);
        WL_UNLOCK(wl);
-
-       return;
 }
 
 static int
@@ -246,7 +243,14 @@ wl_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 static void
 wl_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
-       return;
+       struct wl_info *wl;
+
+       wl = HW_TO_WL(hw);
+
+       /* put driver in down state */
+       WL_LOCK(wl);
+       wl_down(wl);
+       WL_UNLOCK(wl);
 }
 
 static int
@@ -259,9 +263,7 @@ ieee_set_channel(struct ieee80211_hw *hw, struct ieee80211_channel *chan,
        switch (type) {
        case NL80211_CHAN_HT20:
        case NL80211_CHAN_NO_HT:
-               WL_LOCK(wl);
                err = wlc_set(wl->wlc, WLC_SET_CHANNEL, chan->hw_value);
-               WL_UNLOCK(wl);
                break;
        case NL80211_CHAN_HT40MINUS:
        case NL80211_CHAN_HT40PLUS:
@@ -281,6 +283,7 @@ static int wl_ops_config(struct ieee80211_hw *hw, u32 changed)
        int err = 0;
        int new_int;
 
+       WL_LOCK(wl);
        if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {
                WL_NONE("%s: Setting listen interval to %d\n",
                        __func__, conf->listen_interval);
@@ -337,6 +340,7 @@ static int wl_ops_config(struct ieee80211_hw *hw, u32 changed)
        }
 
  config_out:
+       WL_UNLOCK(wl);
        return err;
 }
 
@@ -455,13 +459,21 @@ wl_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
 
 static void wl_ops_sw_scan_start(struct ieee80211_hw *hw)
 {
+       struct wl_info *wl = hw->priv;
        WL_NONE("Scan Start\n");
+       WL_LOCK(wl);
+       wlc_scan_start(wl->wlc);
+       WL_UNLOCK(wl);
        return;
 }
 
 static void wl_ops_sw_scan_complete(struct ieee80211_hw *hw)
 {
+       struct wl_info *wl = hw->priv;
        WL_NONE("Scan Complete\n");
+       WL_LOCK(wl);
+       wlc_scan_stop(wl->wlc);
+       WL_UNLOCK(wl);
        return;
 }
 
@@ -779,7 +791,7 @@ static struct wl_info *wl_attach(u16 vendor, u16 device, unsigned long regs,
        wl_found++;
        return wl;
 
- fail:
+fail:
        wl_free(wl);
 fail1:
        return NULL;
@@ -1090,7 +1102,6 @@ wl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        return 0;
 }
 
-#ifdef LINUXSTA_PS
 static int wl_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct wl_info *wl;
@@ -1105,11 +1116,12 @@ static int wl_suspend(struct pci_dev *pdev, pm_message_t state)
                return -ENODEV;
        }
 
+       /* only need to flag hw is down for proper resume */
        WL_LOCK(wl);
-       wl_down(wl);
        wl->pub->hw_up = false;
        WL_UNLOCK(wl);
-       pci_save_state(pdev, wl->pci_psstate);
+
+       pci_save_state(pdev);
        pci_disable_device(pdev);
        return pci_set_power_state(pdev, PCI_D3hot);
 }
@@ -1133,7 +1145,7 @@ static int wl_resume(struct pci_dev *pdev)
        if (err)
                return err;
 
-       pci_restore_state(pdev, wl->pci_psstate);
+       pci_restore_state(pdev);
 
        err = pci_enable_device(pdev);
        if (err)
@@ -1145,13 +1157,12 @@ static int wl_resume(struct pci_dev *pdev)
        if ((val & 0x0000ff00) != 0)
                pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
 
-       WL_LOCK(wl);
-       err = wl_up(wl);
-       WL_UNLOCK(wl);
-
+       /*
+       *  done. driver will be put in up state
+       *  in wl_ops_add_interface() call.
+       */
        return err;
 }
-#endif                         /* LINUXSTA_PS */
 
 static void wl_remove(struct pci_dev *pdev)
 {
@@ -1184,14 +1195,12 @@ static void wl_remove(struct pci_dev *pdev)
 }
 
 static struct pci_driver wl_pci_driver = {
- .name  = "brcm80211",
- .probe = wl_pci_probe,
-#ifdef LINUXSTA_PS
- .suspend = wl_suspend,
- .resume  = wl_resume,
-#endif                         /* LINUXSTA_PS */
- .remove   = __devexit_p(wl_remove),
- .id_table = wl_id_table,
+       .name = "brcm80211",
+       .probe = wl_pci_probe,
+       .suspend = wl_suspend,
+       .resume = wl_resume,
+       .remove = __devexit_p(wl_remove),
+       .id_table = wl_id_table,
 };
 
 /**
index 1d5d01a..e37e805 100644 (file)
@@ -5126,7 +5126,6 @@ wlc_sendpkt_mac80211(struct wlc_info *wlc, struct sk_buff *sdu,
        fifo = prio2fifo[prio];
 
        ASSERT((uint) skb_headroom(sdu) >= TXOFF);
-       ASSERT(!(sdu->cloned));
        ASSERT(!(sdu->next));
        ASSERT(!(sdu->prev));
        ASSERT(fifo < NFIFO);
@@ -8462,3 +8461,16 @@ static void wlc_txq_free(struct wlc_info *wlc, struct osl_info *osh,
 
        kfree(qi);
 }
+
+/*
+ * Flag 'scan in progress' to withold dynamic phy calibration
+ */
+void wlc_scan_start(struct wlc_info *wlc)
+{
+       wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, true);
+}
+
+void wlc_scan_stop(struct wlc_info *wlc)
+{
+       wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, false);
+}
index 146a690..aff4130 100644 (file)
@@ -570,6 +570,8 @@ extern void wlc_enable_mac(struct wlc_info *wlc);
 extern u16 wlc_rate_shm_offset(struct wlc_info *wlc, u8 rate);
 extern u32 wlc_get_rspec_history(struct wlc_bsscfg *cfg);
 extern u32 wlc_get_current_highest_rate(struct wlc_bsscfg *cfg);
+extern void wlc_scan_start(struct wlc_info *wlc);
+extern void wlc_scan_stop(struct wlc_info *wlc);
 
 static inline int wlc_iovar_getuint(struct wlc_info *wlc, const char *name,
                                    uint *arg)
index aad4732..1502d80 100644 (file)
@@ -439,6 +439,7 @@ config COMEDI_NI_AT_AO
 config COMEDI_NI_ATMIO
        tristate "NI AT-MIO E series ISA-PNP card support"
        depends on ISAPNP && COMEDI_NI_TIO && COMEDI_NI_COMMON
+       select COMEDI_8255
        default N
        ---help---
          Enable support for National Instruments AT-MIO E series cards
@@ -1040,6 +1041,8 @@ config COMEDI_NI_PCIDIO
 config COMEDI_NI_PCIMIO
        tristate "NI PCI-MIO-E series and M series support"
        depends on COMEDI_NI_TIO && COMEDI_NI_COMMON
+       select COMEDI_8255
+       select COMEDI_FC
        default N
        ---help---
          Enable support for National Instruments PCI-MIO-E series and M series
@@ -1164,6 +1167,7 @@ config COMEDI_NI_LABPC_CS
 config COMEDI_NI_MIO_CS
        tristate "NI DAQCard E series PCMCIA support"
        depends on COMEDI_NI_TIO && COMEDI_NI_COMMON
+       select COMEDI_8255
        select COMEDI_FC
        default N
        ---help---
@@ -1268,7 +1272,6 @@ config COMEDI_MITE
 config COMEDI_NI_TIO
        tristate "NI general purpose counter support"
        depends on COMEDI_MITE
-       select COMEDI_8255
        default N
        ---help---
          Enable support for National Instruments general purpose counters.
index cd25b24..fd274e9 100644 (file)
@@ -61,8 +61,6 @@
 #define PCI_DAQ_SIZE           4096
 #define PCI_DAQ_SIZE_660X       8192
 
-MODULE_LICENSE("GPL");
-
 struct mite_struct *mite_devices;
 EXPORT_SYMBOL(mite_devices);
 
index 14e716e..54741c9 100644 (file)
@@ -527,3 +527,7 @@ static void __exit driver_ni6527_cleanup_module(void)
 
 module_init(driver_ni6527_init_module);
 module_exit(driver_ni6527_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
index 8b8e2aa..403fc09 100644 (file)
@@ -871,3 +871,7 @@ static void __exit driver_ni_65xx_cleanup_module(void)
 
 module_init(driver_ni_65xx_init_module);
 module_exit(driver_ni_65xx_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
index 6612b08..ca2aeaa 100644 (file)
@@ -1421,3 +1421,7 @@ static int ni_660x_dio_insn_config(struct comedi_device *dev,
        };
        return 0;
 }
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
index e9f034e..d8d91f9 100644 (file)
@@ -384,3 +384,7 @@ static int ni_670x_find_device(struct comedi_device *dev, int bus, int slot)
        mite_list_devices();
        return -EIO;
 }
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
index 4d1868d..0728c3c 100644 (file)
@@ -575,7 +575,8 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
        /* grab our IRQ */
        if (irq) {
                isr_flags = 0;
-               if (thisboard->bustype == pci_bustype)
+               if (thisboard->bustype == pci_bustype
+                   || thisboard->bustype == pcmcia_bustype)
                        isr_flags |= IRQF_SHARED;
                if (request_irq(irq, labpc_interrupt, isr_flags,
                                driver_labpc.driver_name, dev)) {
index 84a15c3..005d2fe 100644 (file)
@@ -1354,3 +1354,7 @@ static void __exit driver_pcidio_cleanup_module(void)
 
 module_init(driver_pcidio_init_module);
 module_exit(driver_pcidio_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
index 23a3812..9148abd 100644 (file)
@@ -1853,3 +1853,7 @@ static int pcimio_dio_change(struct comedi_device *dev,
 
        return 0;
 }
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_LICENSE("GPL");
index b3d05fc..4fb8094 100644 (file)
@@ -368,6 +368,7 @@ static int blkvsc_probe(struct device *device)
                blkdev->gd->first_minor = 0;
        blkdev->gd->fops = &block_ops;
        blkdev->gd->private_data = blkdev;
+       blkdev->gd->driverfs_dev = &(blkdev->device_ctx->device);
        sprintf(blkdev->gd->disk_name, "hd%c", 'a' + devnum);
 
        blkvsc_do_inquiry(blkdev);
index df9cd13..0edbe74 100644 (file)
@@ -1279,7 +1279,7 @@ static void netvsc_channel_cb(void *context)
        /* ASSERT(device); */
 
        packet = kzalloc(NETVSC_PACKET_SIZE * sizeof(unsigned char),
-                        GFP_KERNEL);
+                        GFP_ATOMIC);
        if (!packet)
                return;
        buffer = packet;
index 0147b40..b41c964 100644 (file)
@@ -236,6 +236,7 @@ static void netvsc_linkstatus_callback(struct hv_device *device_obj,
        if (status == 1) {
                netif_carrier_on(net);
                netif_wake_queue(net);
+               netif_notify_peers(net);
        } else {
                netif_carrier_off(net);
                netif_stop_queue(net);
@@ -358,7 +359,6 @@ static int netvsc_probe(struct device *device)
 
        /* Set initial state */
        netif_carrier_off(net);
-       netif_stop_queue(net);
 
        net_device_ctx = netdev_priv(net);
        net_device_ctx->device_ctx = device_ctx;
index deb68c8..b8b54da 100644 (file)
@@ -68,7 +68,7 @@ static ssize_t ad7476_show_scale(struct device *dev,
        /* Corresponds to Vref / 2^(bits) */
        unsigned int scale_uv = (st->int_vref_mv * 1000) >> st->chip_info->bits;
 
-       return sprintf(buf, "%d.%d\n", scale_uv / 1000, scale_uv % 1000);
+       return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000);
 }
 static IIO_DEVICE_ATTR(in_scale, S_IRUGO, ad7476_show_scale, NULL, 0);
 
index 6859089..5d85efa 100644 (file)
@@ -68,7 +68,7 @@ static ssize_t ad7887_show_scale(struct device *dev,
        /* Corresponds to Vref / 2^(bits) */
        unsigned int scale_uv = (st->int_vref_mv * 1000) >> st->chip_info->bits;
 
-       return sprintf(buf, "%d.%d\n", scale_uv / 1000, scale_uv % 1000);
+       return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000);
 }
 static IIO_DEVICE_ATTR(in_scale, S_IRUGO, ad7887_show_scale, NULL, 0);
 
index 6309d52..89ccf37 100644 (file)
@@ -432,7 +432,7 @@ static ssize_t ad799x_show_scale(struct device *dev,
        /* Corresponds to Vref / 2^(bits) */
        unsigned int scale_uv = (st->int_vref_mv * 1000) >> st->chip_info->bits;
 
-       return sprintf(buf, "%d.%d\n", scale_uv / 1000, scale_uv % 1000);
+       return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000);
 }
 
 static IIO_DEVICE_ATTR(in_scale, S_IRUGO, ad799x_show_scale, NULL, 0);
index e3387cd..0f87eca 100644 (file)
@@ -87,7 +87,7 @@ static ssize_t ad5446_show_scale(struct device *dev,
        /* Corresponds to Vref / 2^(bits) */
        unsigned int scale_uv = (st->vref_mv * 1000) >> st->chip_info->bits;
 
-       return sprintf(buf, "%d.%d\n", scale_uv / 1000, scale_uv % 1000);
+       return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000);
 }
 static IIO_DEVICE_ATTR(out_scale, S_IRUGO, ad5446_show_scale, NULL, 0);
 
index e38e89d..e2f6d6a 100644 (file)
@@ -874,7 +874,10 @@ static int nc_set_selected_input_dev(u8 value)
                sc_access[3].reg_addr = 0x109;
                sc_access[3].mask = MASK6;
                sc_access[3].value = 0x00;
-               num_val = 4;
+               sc_access[4].reg_addr = 0x104;
+               sc_access[4].value = 0x3C;
+               sc_access[4].mask = 0xff;
+               num_val = 5;
                break;
        default:
                return -EINVAL;
index 3fe5f41..0aad0d7 100644 (file)
@@ -495,7 +495,7 @@ static int send_data_block(struct IR_tx *tx, unsigned char *data_block)
 /* send boot data to the IR TX device */
 static int send_boot_data(struct IR_tx *tx)
 {
-       int ret;
+       int ret, i;
        unsigned char buf[4];
 
        /* send the boot block */
@@ -503,7 +503,7 @@ static int send_boot_data(struct IR_tx *tx)
        if (ret != 0)
                return ret;
 
-       /* kick it off? */
+       /* Hit the go button to activate the new boot data */
        buf[0] = 0x00;
        buf[1] = 0x20;
        ret = i2c_master_send(tx->c, buf, 2);
@@ -511,7 +511,19 @@ static int send_boot_data(struct IR_tx *tx)
                zilog_error("i2c_master_send failed with %d\n", ret);
                return ret < 0 ? ret : -EFAULT;
        }
-       ret = i2c_master_send(tx->c, buf, 1);
+
+       /*
+        * Wait for zilog to settle after hitting go post boot block upload.
+        * Without this delay, the HD-PVR and HVR-1950 both return an -EIO
+        * upon attempting to get firmware revision, and tx probe thus fails.
+        */
+       for (i = 0; i < 10; i++) {
+               ret = i2c_master_send(tx->c, buf, 1);
+               if (ret == 1)
+                       break;
+               udelay(100);
+       }
+
        if (ret != 1) {
                zilog_error("i2c_master_send failed with %d\n", ret);
                return ret < 0 ? ret : -EFAULT;
@@ -523,8 +535,8 @@ static int send_boot_data(struct IR_tx *tx)
                zilog_error("i2c_master_recv failed with %d\n", ret);
                return 0;
        }
-       if (buf[0] != 0x80) {
-               zilog_error("unexpected IR TX response: %02x\n", buf[0]);
+       if ((buf[0] != 0x80) && (buf[0] != 0xa0)) {
+               zilog_error("unexpected IR TX init response: %02x\n", buf[0]);
                return 0;
        }
        zilog_notify("Zilog/Hauppauge IR blaster firmware version "
@@ -827,7 +839,15 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key)
                zilog_error("i2c_master_send failed with %d\n", ret);
                return ret < 0 ? ret : -EFAULT;
        }
-       ret = i2c_master_send(tx->c, buf, 1);
+
+       /* Give the z8 a moment to process data block */
+       for (i = 0; i < 10; i++) {
+               ret = i2c_master_send(tx->c, buf, 1);
+               if (ret == 1)
+                       break;
+               udelay(100);
+       }
+
        if (ret != 1) {
                zilog_error("i2c_master_send failed with %d\n", ret);
                return ret < 0 ? ret : -EFAULT;
index 23fa049..a2f29d4 100644 (file)
@@ -347,7 +347,7 @@ static int msm_fb_suspend(struct platform_device *pdev, pm_message_t state)
        if ((!mfd) || (mfd->key != MFD_KEY))
                return 0;
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(mfd->fbi, 1);
 
        ret = msm_fb_suspend_sub(mfd);
@@ -358,7 +358,7 @@ static int msm_fb_suspend(struct platform_device *pdev, pm_message_t state)
                pdev->dev.power.power_state = state;
        }
 
-       release_console_sem();
+       console_unlock();
        return ret;
 }
 #else
@@ -431,11 +431,11 @@ static int msm_fb_resume(struct platform_device *pdev)
        if ((!mfd) || (mfd->key != MFD_KEY))
                return 0;
 
-       acquire_console_sem();
+       console_lock();
        ret = msm_fb_resume_sub(mfd);
        pdev->dev.power.power_state = PMSG_ON;
        fb_set_suspend(mfd->fbi, 1);
-       release_console_sem();
+       console_unlock();
 
        return ret;
 }
index 9f26dc9..56a283d 100644 (file)
@@ -373,17 +373,17 @@ static void dcon_source_switch(struct work_struct *work)
                 *
                 * For now, we just hope..
                 */
-               acquire_console_sem();
+               console_lock();
                ignore_fb_events = 1;
                if (fb_blank(fbinfo, FB_BLANK_UNBLANK)) {
                        ignore_fb_events = 0;
-                       release_console_sem();
+                       console_unlock();
                        printk(KERN_ERR "olpc-dcon:  Failed to enter CPU mode\n");
                        dcon_pending = DCON_SOURCE_DCON;
                        return;
                }
                ignore_fb_events = 0;
-               release_console_sem();
+               console_unlock();
 
                /* And turn off the DCON */
                pdata->set_dconload(1);
@@ -435,12 +435,12 @@ static void dcon_source_switch(struct work_struct *work)
                        }
                }
 
-               acquire_console_sem();
+               console_lock();
                ignore_fb_events = 1;
                if (fb_blank(fbinfo, FB_BLANK_POWERDOWN))
                        printk(KERN_ERR "olpc-dcon:  couldn't blank fb!\n");
                ignore_fb_events = 0;
-               release_console_sem();
+               console_unlock();
 
                printk(KERN_INFO "olpc-dcon: The DCON has control\n");
                break;
index 701561d..236dd36 100644 (file)
@@ -484,8 +484,6 @@ struct net_device *RtmpPhyNetDevInit(struct rt_rtmp_adapter *pAd,
        net_dev->ml_priv = (void *)pAd;
        pAd->net_dev = net_dev;
 
-       netif_stop_queue(net_dev);
-
        return net_dev;
 
 }
index ee68d51..322bf49 100644 (file)
@@ -106,6 +106,7 @@ struct usb_device_id rtusb_usb_id[] = {
        {USB_DEVICE(0x0411, 0x016f)},   /* MelCo.,Inc. WLI-UC-G301N */
        {USB_DEVICE(0x1737, 0x0070)},   /* Linksys WUSB100 */
        {USB_DEVICE(0x1737, 0x0071)},   /* Linksys WUSB600N */
+       {USB_DEVICE(0x1737, 0x0078)},   /* Linksys WUSB100v2 */
        {USB_DEVICE(0x0411, 0x00e8)},   /* Buffalo WLI-UC-G300N */
        {USB_DEVICE(0x050d, 0x815c)},   /* Belkin F5D8053 */
        {USB_DEVICE(0x100D, 0x9031)},   /* Motorola 2770 */
index 32088a6..84be383 100644 (file)
@@ -128,12 +128,13 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter)
        u8 *ptmpchar = NULL, *ppayload, *ptr;
        struct tx_desc *ptx_desc;
        u32 txdscp_sz = sizeof(struct tx_desc);
+       u8 ret = _FAIL;
 
        ulfilelength = rtl871x_open_fw(padapter, &phfwfile_hdl, &pmappedfw);
        if (pmappedfw && (ulfilelength > 0)) {
                update_fwhdr(&fwhdr, pmappedfw);
                if (chk_fwhdr(&fwhdr, ulfilelength) == _FAIL)
-                       goto exit_fail;
+                       goto firmware_rel;
                fill_fwpriv(padapter, &fwhdr.fwpriv);
                /* firmware check ok */
                maxlen = (fwhdr.img_IMEM_size > fwhdr.img_SRAM_size) ?
@@ -141,7 +142,7 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter)
                maxlen += txdscp_sz;
                ptmpchar = _malloc(maxlen + FWBUFF_ALIGN_SZ);
                if (ptmpchar == NULL)
-                       return _FAIL;
+                       goto firmware_rel;
 
                ptx_desc = (struct tx_desc *)(ptmpchar + FWBUFF_ALIGN_SZ -
                            ((addr_t)(ptmpchar) & (FWBUFF_ALIGN_SZ - 1)));
@@ -273,11 +274,13 @@ static u8 rtl8712_dl_fw(struct _adapter *padapter)
                        goto exit_fail;
        } else
                goto exit_fail;
-       return _SUCCESS;
+       ret = _SUCCESS;
 
 exit_fail:
        kfree(ptmpchar);
-       return _FAIL;
+firmware_rel:
+       release_firmware((struct firmware *)phfwfile_hdl);
+       return ret;
 }
 
 uint rtl8712_hal_init(struct _adapter *padapter)
index a692ee8..21ce2af 100644 (file)
@@ -47,54 +47,123 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf,
 static void r871xu_dev_remove(struct usb_interface *pusb_intf);
 
 static struct usb_device_id rtl871x_usb_id_tbl[] = {
-       /*92SU
-        * Realtek */
-       {USB_DEVICE(0x0bda, 0x8171)},
-       {USB_DEVICE(0x0bda, 0x8172)},
+
+/* RTL8188SU */
+       /* Realtek */
+       {USB_DEVICE(0x0BDA, 0x8171)},
        {USB_DEVICE(0x0bda, 0x8173)},
-       {USB_DEVICE(0x0bda, 0x8174)},
        {USB_DEVICE(0x0bda, 0x8712)},
        {USB_DEVICE(0x0bda, 0x8713)},
        {USB_DEVICE(0x0bda, 0xC512)},
-       /* Abocom  */
+       /* Abocom */
        {USB_DEVICE(0x07B8, 0x8188)},
+       /* ASUS */
+       {USB_DEVICE(0x0B05, 0x1786)},
+       {USB_DEVICE(0x0B05, 0x1791)}, /* 11n mode disable */
+       /* Belkin */
+       {USB_DEVICE(0x050D, 0x945A)},
        /* Corega */
-       {USB_DEVICE(0x07aa, 0x0047)},
-       /* Dlink */
-       {USB_DEVICE(0x07d1, 0x3303)},
-       {USB_DEVICE(0x07d1, 0x3302)},
-       {USB_DEVICE(0x07d1, 0x3300)},
-       /* Dlink for Skyworth */
-       {USB_DEVICE(0x14b2, 0x3300)},
-       {USB_DEVICE(0x14b2, 0x3301)},
-       {USB_DEVICE(0x14b2, 0x3302)},
+       {USB_DEVICE(0x07AA, 0x0047)},
+       /* D-Link */
+       {USB_DEVICE(0x2001, 0x3306)},
+       {USB_DEVICE(0x07D1, 0x3306)}, /* 11n mode disable */
+       /* Edimax */
+       {USB_DEVICE(0x7392, 0x7611)},
        /* EnGenius */
        {USB_DEVICE(0x1740, 0x9603)},
-       {USB_DEVICE(0x1740, 0x9605)},
+       /* Hawking */
+       {USB_DEVICE(0x0E66, 0x0016)},
+       /* Hercules */
+       {USB_DEVICE(0x06F8, 0xE034)},
+       {USB_DEVICE(0x06F8, 0xE032)},
+       /* Logitec */
+       {USB_DEVICE(0x0789, 0x0167)},
+       /* PCI */
+       {USB_DEVICE(0x2019, 0xAB28)},
+       {USB_DEVICE(0x2019, 0xED16)},
+       /* Sitecom */
+       {USB_DEVICE(0x0DF6, 0x0057)},
+       {USB_DEVICE(0x0DF6, 0x0045)},
+       {USB_DEVICE(0x0DF6, 0x0059)}, /* 11n mode disable */
+       {USB_DEVICE(0x0DF6, 0x004B)},
+       {USB_DEVICE(0x0DF6, 0x0063)},
+       /* Sweex */
+       {USB_DEVICE(0x177F, 0x0154)},
+       /* Thinkware */
+       {USB_DEVICE(0x0BDA, 0x5077)},
+       /* Toshiba */
+       {USB_DEVICE(0x1690, 0x0752)},
+       /* - */
+       {USB_DEVICE(0x20F4, 0x646B)},
+       {USB_DEVICE(0x083A, 0xC512)},
+
+/* RTL8191SU */
+       /* Realtek */
+       {USB_DEVICE(0x0BDA, 0x8172)},
+       /* Amigo */
+       {USB_DEVICE(0x0EB0, 0x9061)},
+       /* ASUS/EKB */
+       {USB_DEVICE(0x0BDA, 0x8172)},
+       {USB_DEVICE(0x13D3, 0x3323)},
+       {USB_DEVICE(0x13D3, 0x3311)}, /* 11n mode disable */
+       {USB_DEVICE(0x13D3, 0x3342)},
+       /* ASUS/EKBLenovo */
+       {USB_DEVICE(0x13D3, 0x3333)},
+       {USB_DEVICE(0x13D3, 0x3334)},
+       {USB_DEVICE(0x13D3, 0x3335)}, /* 11n mode disable */
+       {USB_DEVICE(0x13D3, 0x3336)}, /* 11n mode disable */
+       /* ASUS/Media BOX */
+       {USB_DEVICE(0x13D3, 0x3309)},
        /* Belkin */
-       {USB_DEVICE(0x050d, 0x815F)},
-       {USB_DEVICE(0x050d, 0x945A)},
-       {USB_DEVICE(0x050d, 0x845A)},
-       /* Guillemot */
-       {USB_DEVICE(0x06f8, 0xe031)},
+       {USB_DEVICE(0x050D, 0x815F)},
+       /* D-Link */
+       {USB_DEVICE(0x07D1, 0x3302)},
+       {USB_DEVICE(0x07D1, 0x3300)},
+       {USB_DEVICE(0x07D1, 0x3303)},
        /* Edimax */
-       {USB_DEVICE(0x7392, 0x7611)},
        {USB_DEVICE(0x7392, 0x7612)},
-       {USB_DEVICE(0x7392, 0x7622)},
-       /* Sitecom */
-       {USB_DEVICE(0x0DF6, 0x0045)},
+       /* EnGenius */
+       {USB_DEVICE(0x1740, 0x9605)},
+       /* Guillemot */
+       {USB_DEVICE(0x06F8, 0xE031)},
        /* Hawking */
        {USB_DEVICE(0x0E66, 0x0015)},
-       {USB_DEVICE(0x0E66, 0x0016)},
-       {USB_DEVICE(0x0b05, 0x1786)},
-       {USB_DEVICE(0x0b05, 0x1791)},    /* 11n mode disable */
-
+       /* Mediao */
        {USB_DEVICE(0x13D3, 0x3306)},
-       {USB_DEVICE(0x13D3, 0x3309)},
+       /* PCI */
+       {USB_DEVICE(0x2019, 0xED18)},
+       {USB_DEVICE(0x2019, 0x4901)},
+       /* Sitecom */
+       {USB_DEVICE(0x0DF6, 0x0058)},
+       {USB_DEVICE(0x0DF6, 0x0049)},
+       {USB_DEVICE(0x0DF6, 0x004C)},
+       {USB_DEVICE(0x0DF6, 0x0064)},
+       /* Skyworth */
+       {USB_DEVICE(0x14b2, 0x3300)},
+       {USB_DEVICE(0x14b2, 0x3301)},
+       {USB_DEVICE(0x14B2, 0x3302)},
+       /* - */
+       {USB_DEVICE(0x04F2, 0xAFF2)},
+       {USB_DEVICE(0x04F2, 0xAFF5)},
+       {USB_DEVICE(0x04F2, 0xAFF6)},
+       {USB_DEVICE(0x13D3, 0x3339)},
+       {USB_DEVICE(0x13D3, 0x3340)}, /* 11n mode disable */
+       {USB_DEVICE(0x13D3, 0x3341)}, /* 11n mode disable */
        {USB_DEVICE(0x13D3, 0x3310)},
-       {USB_DEVICE(0x13D3, 0x3311)},    /* 11n mode disable */
        {USB_DEVICE(0x13D3, 0x3325)},
-       {USB_DEVICE(0x083A, 0xC512)},
+
+/* RTL8192SU */
+       /* Realtek */
+       {USB_DEVICE(0x0BDA, 0x8174)},
+       {USB_DEVICE(0x0BDA, 0x8174)},
+       /* Belkin */
+       {USB_DEVICE(0x050D, 0x845A)},
+       /* Corega */
+       {USB_DEVICE(0x07AA, 0x0051)},
+       /* Edimax */
+       {USB_DEVICE(0x7392, 0x7622)},
+       /* NEC */
+       {USB_DEVICE(0x0409, 0x02B6)},
        {}
 };
 
@@ -103,8 +172,20 @@ MODULE_DEVICE_TABLE(usb, rtl871x_usb_id_tbl);
 static struct specific_device_id specific_device_id_tbl[] = {
        {.idVendor = 0x0b05, .idProduct = 0x1791,
                 .flags = SPEC_DEV_ID_DISABLE_HT},
+       {.idVendor = 0x0df6, .idProduct = 0x0059,
+                .flags = SPEC_DEV_ID_DISABLE_HT},
+       {.idVendor = 0x13d3, .idProduct = 0x3306,
+                .flags = SPEC_DEV_ID_DISABLE_HT},
        {.idVendor = 0x13D3, .idProduct = 0x3311,
                 .flags = SPEC_DEV_ID_DISABLE_HT},
+       {.idVendor = 0x13d3, .idProduct = 0x3335,
+                .flags = SPEC_DEV_ID_DISABLE_HT},
+       {.idVendor = 0x13d3, .idProduct = 0x3336,
+                .flags = SPEC_DEV_ID_DISABLE_HT},
+       {.idVendor = 0x13d3, .idProduct = 0x3340,
+                .flags = SPEC_DEV_ID_DISABLE_HT},
+       {.idVendor = 0x13d3, .idProduct = 0x3341,
+                .flags = SPEC_DEV_ID_DISABLE_HT},
        {}
 };
 
index 0bc113c..d007e4a 100644 (file)
@@ -1044,9 +1044,9 @@ static int __maybe_unused smtcfb_suspend(struct pci_dev *pdev, pm_message_t msg)
 
        /* when doing suspend, call fb apis and pci apis */
        if (msg.event == PM_EVENT_SUSPEND) {
-               acquire_console_sem();
+               console_lock();
                fb_set_suspend(&sfb->fb, 1);
-               release_console_sem();
+               console_unlock();
                retv = pci_save_state(pdev);
                pci_disable_device(pdev);
                retv = pci_choose_state(pdev, msg);
@@ -1105,9 +1105,9 @@ static int __maybe_unused smtcfb_resume(struct pci_dev *pdev)
 
        smtcfb_setmode(sfb);
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(&sfb->fb, 0);
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
index 408bb9b..07a7f54 100644 (file)
@@ -332,7 +332,7 @@ static ssize_t silent_store(struct kobject *kobj, struct kobj_attribute *attr,
        unsigned long flags;
 
        len = strlen(buf);
-       if (len > 0 || len < 3) {
+       if (len > 0 && len < 3) {
                ch = buf[0];
                if (ch == '\n')
                        ch = '0';
index e8f047e..80183a7 100644 (file)
@@ -986,12 +986,6 @@ static int __devinit synaptics_rmi4_probe
        input_set_abs_params(rmi4_data->input_dev, ABS_MT_TOUCH_MAJOR, 0,
                                                MAX_TOUCH_MAJOR, 0, 0);
 
-       retval = input_register_device(rmi4_data->input_dev);
-       if (retval) {
-               dev_err(&client->dev, "%s:input register failed\n", __func__);
-               goto err_input_register;
-       }
-
        /* Clear interrupts */
        synaptics_rmi4_i2c_block_read(rmi4_data,
                        rmi4_data->fn01_data_base_addr + 1, intr_status,
@@ -1003,15 +997,20 @@ static int __devinit synaptics_rmi4_probe
        if (retval) {
                dev_err(&client->dev, "%s:Unable to get attn irq %d\n",
                                __func__, platformdata->irq_number);
-               goto err_request_irq;
+               goto err_unset_clientdata;
+       }
+
+       retval = input_register_device(rmi4_data->input_dev);
+       if (retval) {
+               dev_err(&client->dev, "%s:input register failed\n", __func__);
+               goto err_free_irq;
        }
 
        return retval;
 
-err_request_irq:
+err_free_irq:
        free_irq(platformdata->irq_number, rmi4_data);
-       input_unregister_device(rmi4_data->input_dev);
-err_input_register:
+err_unset_clientdata:
        i2c_set_clientdata(client, NULL);
 err_query_dev:
        if (platformdata->regulator_en) {
index 5718645..27e0aa8 100644 (file)
@@ -949,7 +949,7 @@ func_end:
  *      Calls the Bridge's CHNL_ISR to determine if this interrupt is ours, then
  *      schedules a DPC to dispatch I/O.
  */
-void io_mbox_msg(u32 msg)
+int io_mbox_msg(struct notifier_block *self, unsigned long len, void *msg)
 {
        struct io_mgr *pio_mgr;
        struct dev_object *dev_obj;
@@ -959,9 +959,9 @@ void io_mbox_msg(u32 msg)
        dev_get_io_mgr(dev_obj, &pio_mgr);
 
        if (!pio_mgr)
-               return;
+               return NOTIFY_BAD;
 
-       pio_mgr->intr_val = (u16)msg;
+       pio_mgr->intr_val = (u16)((u32)msg);
        if (pio_mgr->intr_val & MBX_PM_CLASS)
                io_dispatch_pm(pio_mgr);
 
@@ -973,7 +973,7 @@ void io_mbox_msg(u32 msg)
                spin_unlock_irqrestore(&pio_mgr->dpc_lock, flags);
                tasklet_schedule(&pio_mgr->dpc_tasklet);
        }
-       return;
+       return NOTIFY_OK;
 }
 
 /*
index a3b0a18..a3f69f6 100644 (file)
@@ -223,6 +223,10 @@ static struct bridge_drv_interface drv_interface_fxns = {
        bridge_msg_set_queue_id,
 };
 
+static struct notifier_block dsp_mbox_notifier = {
+       .notifier_call = io_mbox_msg,
+};
+
 static inline void flush_all(struct bridge_dev_context *dev_context)
 {
        if (dev_context->dw_brd_state == BRD_DSP_HIBERNATION ||
@@ -553,7 +557,7 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
                 * Enable Mailbox events and also drain any pending
                 * stale messages.
                 */
-               dev_context->mbox = omap_mbox_get("dsp");
+               dev_context->mbox = omap_mbox_get("dsp", &dsp_mbox_notifier);
                if (IS_ERR(dev_context->mbox)) {
                        dev_context->mbox = NULL;
                        pr_err("%s: Failed to get dsp mailbox handle\n",
@@ -563,8 +567,6 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
 
        }
        if (!status) {
-               dev_context->mbox->rxq->callback = (int (*)(void *))io_mbox_msg;
-
 /*PM_IVA2GRPSEL_PER = 0xC0;*/
                temp = readl(resources->dw_per_pm_base + 0xA8);
                temp = (temp & 0xFFFFFF30) | 0xC0;
@@ -685,7 +687,7 @@ static int bridge_brd_stop(struct bridge_dev_context *dev_ctxt)
        /* Disable the mailbox interrupts */
        if (dev_context->mbox) {
                omap_mbox_disable_irq(dev_context->mbox, IRQ_RX);
-               omap_mbox_put(dev_context->mbox);
+               omap_mbox_put(dev_context->mbox, &dsp_mbox_notifier);
                dev_context->mbox = NULL;
        }
        /* Reset IVA2 clocks*/
@@ -786,10 +788,7 @@ static int bridge_dev_create(struct bridge_dev_context
 
        pt_attrs = kzalloc(sizeof(struct pg_table_attrs), GFP_KERNEL);
        if (pt_attrs != NULL) {
-               /* Assuming that we use only DSP's memory map
-                * until 0x4000:0000 , we would need only 1024
-                * L1 enties i.e L1 size = 4K */
-               pt_attrs->l1_size = 0x1000;
+               pt_attrs->l1_size = SZ_16K; /* 4096 entries of 32 bits */
                align_size = pt_attrs->l1_size;
                /* Align sizes are expected to be power of 2 */
                /* we like to get aligned on L1 table size */
index 18aec55..8242c70 100644 (file)
@@ -72,22 +72,17 @@ extern void io_dpc(unsigned long ref_data);
 /*
  *  ======== io_mbox_msg ========
  *  Purpose:
- *      Main interrupt handler for the shared memory Bridge channel manager.
- *      Calls the Bridge's chnlsm_isr to determine if this interrupt is ours,
- *      then schedules a DPC to dispatch I/O.
+ *     Main message handler for the shared memory Bridge channel manager.
+ *     Determine if this message is ours, then schedules a DPC to
+ *     dispatch I/O.
  *  Parameters:
- *      ref_data:   Pointer to the channel manager object for this board.
- *                  Set in an initial call to ISR_Install().
+ *     self:   Pointer to its own notifier_block struct.
+ *     len:    Length of message.
+ *     msg:    Message code received.
  *  Returns:
- *      TRUE if interrupt handled; FALSE otherwise.
- *  Requires:
- *      Must be in locked memory if executing in kernel mode.
- *      Must only call functions which are in locked memory if Kernel mode.
- *      Must only call asynchronous services.
- *      Interrupts are disabled and EOI for this interrupt has been sent.
- *  Ensures:
+ *     NOTIFY_OK if handled; NOTIFY_BAD otherwise.
  */
-void io_mbox_msg(u32 msg);
+int io_mbox_msg(struct notifier_block *self, unsigned long len, void *msg);
 
 /*
  *  ======== io_request_chnl ========
index 30dbfb6..d732679 100644 (file)
@@ -32,6 +32,7 @@
 
 struct stub_device {
        struct usb_interface *interface;
+       struct usb_device *udev;
        struct list_head list;
 
        struct usbip_device ud;
index b186b5f..a7ce51c 100644 (file)
@@ -258,10 +258,11 @@ static void stub_shutdown_connection(struct usbip_device *ud)
 static void stub_device_reset(struct usbip_device *ud)
 {
        struct stub_device *sdev = container_of(ud, struct stub_device, ud);
-       struct usb_device *udev = interface_to_usbdev(sdev->interface);
+       struct usb_device *udev = sdev->udev;
        int ret;
 
        usbip_udbg("device reset");
+
        ret = usb_lock_device_for_reset(udev, sdev->interface);
        if (ret < 0) {
                dev_err(&udev->dev, "lock for reset\n");
@@ -309,7 +310,8 @@ static void stub_device_unusable(struct usbip_device *ud)
  *
  * Allocates and initializes a new stub_device struct.
  */
-static struct stub_device *stub_device_alloc(struct usb_interface *interface)
+static struct stub_device *stub_device_alloc(struct usb_device *udev,
+                                            struct usb_interface *interface)
 {
        struct stub_device *sdev;
        int busnum = interface_to_busnum(interface);
@@ -324,7 +326,8 @@ static struct stub_device *stub_device_alloc(struct usb_interface *interface)
                return NULL;
        }
 
-       sdev->interface = interface;
+       sdev->interface = usb_get_intf(interface);
+       sdev->udev = usb_get_dev(udev);
 
        /*
         * devid is defined with devnum when this driver is first allocated.
@@ -450,11 +453,12 @@ static int stub_probe(struct usb_interface *interface,
                        return err;
                }
 
+               usb_get_intf(interface);
                return 0;
        }
 
        /* ok. this is my device. */
-       sdev = stub_device_alloc(interface);
+       sdev = stub_device_alloc(udev, interface);
        if (!sdev)
                return -ENOMEM;
 
@@ -476,6 +480,8 @@ static int stub_probe(struct usb_interface *interface,
                dev_err(&interface->dev, "create sysfs files for %s\n",
                        udev_busid);
                usb_set_intfdata(interface, NULL);
+               usb_put_intf(interface);
+
                busid_priv->interf_count = 0;
 
                busid_priv->sdev = NULL;
@@ -545,6 +551,7 @@ static void stub_disconnect(struct usb_interface *interface)
        if (busid_priv->interf_count > 1) {
                busid_priv->interf_count--;
                shutdown_busid(busid_priv);
+               usb_put_intf(interface);
                return;
        }
 
@@ -554,6 +561,9 @@ static void stub_disconnect(struct usb_interface *interface)
        /* 1. shutdown the current connection */
        shutdown_busid(busid_priv);
 
+       usb_put_dev(sdev->udev);
+       usb_put_intf(interface);
+
        /* 3. free sdev */
        busid_priv->sdev = NULL;
        stub_device_free(sdev);
index 3de6fd2..ae6ac82 100644 (file)
@@ -364,7 +364,7 @@ static struct stub_priv *stub_priv_alloc(struct stub_device *sdev,
 
 static int get_pipe(struct stub_device *sdev, int epnum, int dir)
 {
-       struct usb_device *udev = interface_to_usbdev(sdev->interface);
+       struct usb_device *udev = sdev->udev;
        struct usb_host_endpoint *ep;
        struct usb_endpoint_descriptor *epd = NULL;
 
@@ -484,7 +484,7 @@ static void stub_recv_cmd_submit(struct stub_device *sdev,
        int ret;
        struct stub_priv *priv;
        struct usbip_device *ud = &sdev->ud;
-       struct usb_device *udev = interface_to_usbdev(sdev->interface);
+       struct usb_device *udev = sdev->udev;
        int pipe = get_pipe(sdev, pdu->base.ep, pdu->base.direction);
 
 
index 41a1fe5..afc3b1a 100644 (file)
@@ -100,9 +100,6 @@ struct vhci_hcd {
         * But, the index of this array begins from 0.
         */
        struct vhci_device vdev[VHCI_NPORTS];
-
-       /* vhci_device which has not been assiged its address yet */
-       int pending_port;
 };
 
 
@@ -119,6 +116,9 @@ void rh_port_disconnect(int rhport);
 void vhci_rx_loop(struct usbip_task *ut);
 void vhci_tx_loop(struct usbip_task *ut);
 
+struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev,
+                                           __u32 seqnum);
+
 #define hardware               (&the_controller->pdev.dev)
 
 static inline struct vhci_device *port_to_vdev(__u32 port)
index 08bd26a..a35fe61 100644 (file)
@@ -138,8 +138,6 @@ void rh_port_connect(int rhport, enum usb_device_speed speed)
         * the_controller->vdev[rhport].ud.status = VDEV_CONNECT;
         * spin_unlock(&the_controller->vdev[rhport].ud.lock); */
 
-       the_controller->pending_port = rhport;
-
        spin_unlock_irqrestore(&the_controller->lock, flags);
 
        usb_hcd_poll_rh_status(vhci_to_hcd(the_controller));
@@ -559,6 +557,7 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
        struct device *dev = &urb->dev->dev;
        int ret = 0;
        unsigned long flags;
+       struct vhci_device *vdev;
 
        usbip_dbg_vhci_hc("enter, usb_hcd %p urb %p mem_flags %d\n",
                    hcd, urb, mem_flags);
@@ -574,6 +573,18 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
                return urb->status;
        }
 
+       vdev = port_to_vdev(urb->dev->portnum-1);
+
+       /* refuse enqueue for dead connection */
+       spin_lock(&vdev->ud.lock);
+       if (vdev->ud.status == VDEV_ST_NULL || vdev->ud.status == VDEV_ST_ERROR) {
+               usbip_uerr("enqueue for inactive port %d\n", vdev->rhport);
+               spin_unlock(&vdev->ud.lock);
+               spin_unlock_irqrestore(&the_controller->lock, flags);
+               return -ENODEV;
+       }
+       spin_unlock(&vdev->ud.lock);
+
        ret = usb_hcd_link_urb_to_ep(hcd, urb);
        if (ret)
                goto no_need_unlink;
@@ -592,8 +603,6 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
                __u8 type = usb_pipetype(urb->pipe);
                struct usb_ctrlrequest *ctrlreq =
                                (struct usb_ctrlrequest *) urb->setup_packet;
-               struct vhci_device *vdev =
-                               port_to_vdev(the_controller->pending_port);
 
                if (type != PIPE_CONTROL || !ctrlreq) {
                        dev_err(dev, "invalid request to devnum 0\n");
@@ -607,7 +616,9 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
                        dev_info(dev, "SetAddress Request (%d) to port %d\n",
                                 ctrlreq->wValue, vdev->rhport);
 
-                       vdev->udev = urb->dev;
+                       if (vdev->udev)
+                               usb_put_dev(vdev->udev);
+                       vdev->udev = usb_get_dev(urb->dev);
 
                        spin_lock(&vdev->ud.lock);
                        vdev->ud.status = VDEV_ST_USED;
@@ -627,8 +638,9 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
                                                "Get_Descriptor to device 0 "
                                                "(get max pipe size)\n");
 
-                       /* FIXME: reference count? (usb_get_dev()) */
-                       vdev->udev = urb->dev;
+                       if (vdev->udev)
+                               usb_put_dev(vdev->udev);
+                       vdev->udev = usb_get_dev(urb->dev);
                        goto out;
 
                default:
@@ -805,7 +817,6 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
        return 0;
 }
 
-
 static void vhci_device_unlink_cleanup(struct vhci_device *vdev)
 {
        struct vhci_unlink *unlink, *tmp;
@@ -813,11 +824,34 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev)
        spin_lock(&vdev->priv_lock);
 
        list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
+               usbip_uinfo("unlink cleanup tx %lu\n", unlink->unlink_seqnum);
                list_del(&unlink->list);
                kfree(unlink);
        }
 
        list_for_each_entry_safe(unlink, tmp, &vdev->unlink_rx, list) {
+               struct urb *urb;
+
+               /* give back URB of unanswered unlink request */
+               usbip_uinfo("unlink cleanup rx %lu\n", unlink->unlink_seqnum);
+
+               urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);
+               if (!urb) {
+                       usbip_uinfo("the urb (seqnum %lu) was already given back\n",
+                                                       unlink->unlink_seqnum);
+                       list_del(&unlink->list);
+                       kfree(unlink);
+                       continue;
+               }
+
+               urb->status = -ENODEV;
+
+               spin_lock(&the_controller->lock);
+               usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
+               spin_unlock(&the_controller->lock);
+
+               usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status);
+
                list_del(&unlink->list);
                kfree(unlink);
        }
@@ -887,6 +921,10 @@ static void vhci_device_reset(struct usbip_device *ud)
        vdev->speed  = 0;
        vdev->devid  = 0;
 
+       if (vdev->udev)
+               usb_put_dev(vdev->udev);
+       vdev->udev = NULL;
+
        ud->tcp_socket = NULL;
 
        ud->status = VDEV_ST_NULL;
index 8147d72..bf69914 100644 (file)
 #include "vhci.h"
 
 
-/* get URB from transmitted urb queue */
-static struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev,
+/* get URB from transmitted urb queue. caller must hold vdev->priv_lock */
+struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev,
                                            __u32 seqnum)
 {
        struct vhci_priv *priv, *tmp;
        struct urb *urb = NULL;
        int status;
 
-       spin_lock(&vdev->priv_lock);
-
        list_for_each_entry_safe(priv, tmp, &vdev->priv_rx, list) {
                if (priv->seqnum == seqnum) {
                        urb = priv->urb;
@@ -63,8 +61,6 @@ static struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev,
                }
        }
 
-       spin_unlock(&vdev->priv_lock);
-
        return urb;
 }
 
@@ -74,9 +70,11 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev,
        struct usbip_device *ud = &vdev->ud;
        struct urb *urb;
 
+       spin_lock(&vdev->priv_lock);
 
        urb = pickup_urb_and_free_priv(vdev, pdu->base.seqnum);
 
+       spin_unlock(&vdev->priv_lock);
 
        if (!urb) {
                usbip_uerr("cannot find a urb of seqnum %u\n",
@@ -161,7 +159,12 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev,
                return;
        }
 
+       spin_lock(&vdev->priv_lock);
+
        urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);
+
+       spin_unlock(&vdev->priv_lock);
+
        if (!urb) {
                /*
                 * I get the result of a unlink request. But, it seems that I
@@ -190,6 +193,19 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev,
        return;
 }
 
+static int vhci_priv_tx_empty(struct vhci_device *vdev)
+{
+       int empty = 0;
+
+       spin_lock(&vdev->priv_lock);
+
+       empty = list_empty(&vdev->priv_rx);
+
+       spin_unlock(&vdev->priv_lock);
+
+       return empty;
+}
+
 /* recv a pdu */
 static void vhci_rx_pdu(struct usbip_device *ud)
 {
@@ -202,11 +218,29 @@ static void vhci_rx_pdu(struct usbip_device *ud)
 
        memset(&pdu, 0, sizeof(pdu));
 
-
        /* 1. receive a pdu header */
        ret = usbip_xmit(0, ud->tcp_socket, (char *) &pdu, sizeof(pdu), 0);
+       if (ret < 0) {
+               if (ret == -ECONNRESET)
+                       usbip_uinfo("connection reset by peer\n");
+               else if (ret == -EAGAIN) {
+                       /* ignore if connection was idle */
+                       if (vhci_priv_tx_empty(vdev))
+                               return;
+                       usbip_uinfo("connection timed out with pending urbs\n");
+               } else if (ret != -ERESTARTSYS)
+                       usbip_uinfo("xmit failed %d\n", ret);
+
+               usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
+               return;
+       }
+       if (ret == 0) {
+               usbip_uinfo("connection closed");
+               usbip_event_add(ud, VDEV_EVENT_DOWN);
+               return;
+       }
        if (ret != sizeof(pdu)) {
-               usbip_uerr("receiving pdu failed! size is %d, should be %d\n",
+               usbip_uerr("received pdu size is %d, should be %d\n",
                                        ret, (unsigned int)sizeof(pdu));
                usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
                return;
diff --git a/drivers/staging/vme/bridges/Module.symvers b/drivers/staging/vme/bridges/Module.symvers
deleted file mode 100644 (file)
index e69de29..0000000
index 7016fdd..e19b932 100644 (file)
@@ -3954,8 +3954,8 @@ void XGI_GetCRT2ResInfo(unsigned short ModeNo, unsigned short ModeIdIndex,
 unsigned char XGI_IsLCDDualLink(struct vb_device_info *pVBInfo)
 {
 
-       if ((((pVBInfo->VBInfo & SetCRT2ToLCD) | SetCRT2ToLCDA))
-                       && (pVBInfo->LCDInfo & SetLCDDualLink)) /* shampoo0129 */
+       if ((pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) &&
+                       (pVBInfo->LCDInfo & SetLCDDualLink)) /* shampoo0129 */
                return 1;
 
        return 0;
@@ -8773,7 +8773,7 @@ unsigned short XGI_GetVCLK2Ptr(unsigned short ModeNo,
 
        if (pVBInfo->IF_DEF_LVDS == 0) {
                CRT2Index = CRT2Index >> 6; /*  for LCD */
-               if (((pVBInfo->VBInfo & SetCRT2ToLCD) | SetCRT2ToLCDA)) { /*301b*/
+               if (pVBInfo->VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { /*301b*/
                        if (pVBInfo->LCDResInfo != Panel1024x768)
                                VCLKIndex = LCDXlat2VCLK[CRT2Index];
                        else
index 5415712..4bd8cbd 100644 (file)
@@ -227,6 +227,7 @@ static int zram_read(struct zram *zram, struct bio *bio)
 
                if (zram_test_flag(zram, index, ZRAM_ZERO)) {
                        handle_zero_page(page);
+                       index++;
                        continue;
                }
 
@@ -235,12 +236,14 @@ static int zram_read(struct zram *zram, struct bio *bio)
                        pr_debug("Read before write: sector=%lu, size=%u",
                                (ulong)(bio->bi_sector), bio->bi_size);
                        /* Do nothing */
+                       index++;
                        continue;
                }
 
                /* Page is stored uncompressed since it's incompressible */
                if (unlikely(zram_test_flag(zram, index, ZRAM_UNCOMPRESSED))) {
                        handle_uncompressed_page(zram, page, index);
+                       index++;
                        continue;
                }
 
@@ -320,6 +323,7 @@ static int zram_write(struct zram *zram, struct bio *bio)
                        mutex_unlock(&zram->lock);
                        zram_stat_inc(&zram->stats.pages_zero);
                        zram_set_flag(zram, index, ZRAM_ZERO);
+                       index++;
                        continue;
                }
 
index 5cfd708..973bb19 100644 (file)
@@ -13,8 +13,7 @@ target_core_mod-y             := target_core_configfs.o \
                                   target_core_transport.o \
                                   target_core_cdb.o \
                                   target_core_ua.o \
-                                  target_core_rd.o \
-                                  target_core_mib.o
+                                  target_core_rd.o
 
 obj-$(CONFIG_TARGET_CORE)      += target_core_mod.o
 
index 2764510..caf8dc1 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/parser.h>
 #include <linux/syscalls.h>
 #include <linux/configfs.h>
-#include <linux/proc_fs.h>
 
 #include <target/target_core_base.h>
 #include <target/target_core_device.h>
@@ -1971,13 +1970,35 @@ static void target_core_dev_release(struct config_item *item)
 {
        struct se_subsystem_dev *se_dev = container_of(to_config_group(item),
                                struct se_subsystem_dev, se_dev_group);
-       struct config_group *dev_cg;
-
-       if (!(se_dev))
-               return;
+       struct se_hba *hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item);
+       struct se_subsystem_api *t = hba->transport;
+       struct config_group *dev_cg = &se_dev->se_dev_group;
 
-       dev_cg = &se_dev->se_dev_group;
        kfree(dev_cg->default_groups);
+       /*
+        * This pointer will set when the storage is enabled with:
+        *`echo 1 > $CONFIGFS/core/$HBA/$DEV/dev_enable`
+        */
+       if (se_dev->se_dev_ptr) {
+               printk(KERN_INFO "Target_Core_ConfigFS: Calling se_free_"
+                       "virtual_device() for se_dev_ptr: %p\n",
+                       se_dev->se_dev_ptr);
+
+               se_free_virtual_device(se_dev->se_dev_ptr, hba);
+       } else {
+               /*
+                * Release struct se_subsystem_dev->se_dev_su_ptr..
+                */
+               printk(KERN_INFO "Target_Core_ConfigFS: Calling t->free_"
+                       "device() for se_dev_su_ptr: %p\n",
+                       se_dev->se_dev_su_ptr);
+
+               t->free_device(se_dev->se_dev_su_ptr);
+       }
+
+       printk(KERN_INFO "Target_Core_ConfigFS: Deallocating se_subsystem"
+                       "_dev_t: %p\n", se_dev);
+       kfree(se_dev);
 }
 
 static ssize_t target_core_dev_show(struct config_item *item,
@@ -2140,7 +2161,16 @@ static struct configfs_attribute *target_core_alua_lu_gp_attrs[] = {
        NULL,
 };
 
+static void target_core_alua_lu_gp_release(struct config_item *item)
+{
+       struct t10_alua_lu_gp *lu_gp = container_of(to_config_group(item),
+                       struct t10_alua_lu_gp, lu_gp_group);
+
+       core_alua_free_lu_gp(lu_gp);
+}
+
 static struct configfs_item_operations target_core_alua_lu_gp_ops = {
+       .release                = target_core_alua_lu_gp_release,
        .show_attribute         = target_core_alua_lu_gp_attr_show,
        .store_attribute        = target_core_alua_lu_gp_attr_store,
 };
@@ -2191,9 +2221,11 @@ static void target_core_alua_drop_lu_gp(
        printk(KERN_INFO "Target_Core_ConfigFS: Releasing ALUA Logical Unit"
                " Group: core/alua/lu_gps/%s, ID: %hu\n",
                config_item_name(item), lu_gp->lu_gp_id);
-
+       /*
+        * core_alua_free_lu_gp() is called from target_core_alua_lu_gp_ops->release()
+        * -> target_core_alua_lu_gp_release()
+        */
        config_item_put(item);
-       core_alua_free_lu_gp(lu_gp);
 }
 
 static struct configfs_group_operations target_core_alua_lu_gps_group_ops = {
@@ -2549,7 +2581,16 @@ static struct configfs_attribute *target_core_alua_tg_pt_gp_attrs[] = {
        NULL,
 };
 
+static void target_core_alua_tg_pt_gp_release(struct config_item *item)
+{
+       struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(to_config_group(item),
+                       struct t10_alua_tg_pt_gp, tg_pt_gp_group);
+
+       core_alua_free_tg_pt_gp(tg_pt_gp);
+}
+
 static struct configfs_item_operations target_core_alua_tg_pt_gp_ops = {
+       .release                = target_core_alua_tg_pt_gp_release,
        .show_attribute         = target_core_alua_tg_pt_gp_attr_show,
        .store_attribute        = target_core_alua_tg_pt_gp_attr_store,
 };
@@ -2602,9 +2643,11 @@ static void target_core_alua_drop_tg_pt_gp(
        printk(KERN_INFO "Target_Core_ConfigFS: Releasing ALUA Target Port"
                " Group: alua/tg_pt_gps/%s, ID: %hu\n",
                config_item_name(item), tg_pt_gp->tg_pt_gp_id);
-
+       /*
+        * core_alua_free_tg_pt_gp() is called from target_core_alua_tg_pt_gp_ops->release()
+        * -> target_core_alua_tg_pt_gp_release().
+        */
        config_item_put(item);
-       core_alua_free_tg_pt_gp(tg_pt_gp);
 }
 
 static struct configfs_group_operations target_core_alua_tg_pt_gps_group_ops = {
@@ -2771,13 +2814,11 @@ static void target_core_drop_subdev(
        struct se_subsystem_api *t;
        struct config_item *df_item;
        struct config_group *dev_cg, *tg_pt_gp_cg;
-       int i, ret;
+       int i;
 
        hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item);
 
-       if (mutex_lock_interruptible(&hba->hba_access_mutex))
-               goto out;
-
+       mutex_lock(&hba->hba_access_mutex);
        t = hba->transport;
 
        spin_lock(&se_global->g_device_lock);
@@ -2791,7 +2832,10 @@ static void target_core_drop_subdev(
                config_item_put(df_item);
        }
        kfree(tg_pt_gp_cg->default_groups);
-       core_alua_free_tg_pt_gp(T10_ALUA(se_dev)->default_tg_pt_gp);
+       /*
+        * core_alua_free_tg_pt_gp() is called from ->default_tg_pt_gp
+        * directly from target_core_alua_tg_pt_gp_release().
+        */
        T10_ALUA(se_dev)->default_tg_pt_gp = NULL;
 
        dev_cg = &se_dev->se_dev_group;
@@ -2800,38 +2844,12 @@ static void target_core_drop_subdev(
                dev_cg->default_groups[i] = NULL;
                config_item_put(df_item);
        }
-
-       config_item_put(item);
        /*
-        * This pointer will set when the storage is enabled with:
-        * `echo 1 > $CONFIGFS/core/$HBA/$DEV/dev_enable`
+        * The releasing of se_dev and associated se_dev->se_dev_ptr is done
+        * from target_core_dev_item_ops->release() ->target_core_dev_release().
         */
-       if (se_dev->se_dev_ptr) {
-               printk(KERN_INFO "Target_Core_ConfigFS: Calling se_free_"
-                       "virtual_device() for se_dev_ptr: %p\n",
-                               se_dev->se_dev_ptr);
-
-               ret = se_free_virtual_device(se_dev->se_dev_ptr, hba);
-               if (ret < 0)
-                       goto hba_out;
-       } else {
-               /*
-                * Release struct se_subsystem_dev->se_dev_su_ptr..
-                */
-               printk(KERN_INFO "Target_Core_ConfigFS: Calling t->free_"
-                       "device() for se_dev_su_ptr: %p\n",
-                       se_dev->se_dev_su_ptr);
-
-               t->free_device(se_dev->se_dev_su_ptr);
-       }
-
-       printk(KERN_INFO "Target_Core_ConfigFS: Deallocating se_subsystem"
-               "_dev_t: %p\n", se_dev);
-
-hba_out:
+       config_item_put(item);
        mutex_unlock(&hba->hba_access_mutex);
-out:
-       kfree(se_dev);
 }
 
 static struct configfs_group_operations target_core_hba_group_ops = {
@@ -2914,6 +2932,13 @@ SE_HBA_ATTR(hba_mode, S_IRUGO | S_IWUSR);
 
 CONFIGFS_EATTR_OPS(target_core_hba, se_hba, hba_group);
 
+static void target_core_hba_release(struct config_item *item)
+{
+       struct se_hba *hba = container_of(to_config_group(item),
+                               struct se_hba, hba_group);
+       core_delete_hba(hba);
+}
+
 static struct configfs_attribute *target_core_hba_attrs[] = {
        &target_core_hba_hba_info.attr,
        &target_core_hba_hba_mode.attr,
@@ -2921,6 +2946,7 @@ static struct configfs_attribute *target_core_hba_attrs[] = {
 };
 
 static struct configfs_item_operations target_core_hba_item_ops = {
+       .release                = target_core_hba_release,
        .show_attribute         = target_core_hba_attr_show,
        .store_attribute        = target_core_hba_attr_store,
 };
@@ -2997,10 +3023,11 @@ static void target_core_call_delhbafromtarget(
        struct config_group *group,
        struct config_item *item)
 {
-       struct se_hba *hba = item_to_hba(item);
-
+       /*
+        * core_delete_hba() is called from target_core_hba_item_ops->release()
+        * -> target_core_hba_release()
+        */
        config_item_put(item);
-       core_delete_hba(hba);
 }
 
 static struct configfs_group_operations target_core_group_ops = {
@@ -3022,7 +3049,6 @@ static int target_core_init_configfs(void)
        struct config_group *target_cg, *hba_cg = NULL, *alua_cg = NULL;
        struct config_group *lu_gp_cg = NULL;
        struct configfs_subsystem *subsys;
-       struct proc_dir_entry *scsi_target_proc = NULL;
        struct t10_alua_lu_gp *lu_gp;
        int ret;
 
@@ -3128,21 +3154,10 @@ static int target_core_init_configfs(void)
        if (core_dev_setup_virtual_lun0() < 0)
                goto out;
 
-       scsi_target_proc = proc_mkdir("scsi_target", 0);
-       if (!(scsi_target_proc)) {
-               printk(KERN_ERR "proc_mkdir(scsi_target, 0) failed\n");
-               goto out;
-       }
-       ret = init_scsi_target_mib();
-       if (ret < 0)
-               goto out;
-
        return 0;
 
 out:
        configfs_unregister_subsystem(subsys);
-       if (scsi_target_proc)
-               remove_proc_entry("scsi_target", 0);
        core_dev_release_virtual_lun0();
        rd_module_exit();
 out_global:
@@ -3178,8 +3193,7 @@ static void target_core_exit_configfs(void)
                config_item_put(item);
        }
        kfree(lu_gp_cg->default_groups);
-       core_alua_free_lu_gp(se_global->default_lu_gp);
-       se_global->default_lu_gp = NULL;
+       lu_gp_cg->default_groups = NULL;
 
        alua_cg = &se_global->alua_group;
        for (i = 0; alua_cg->default_groups[i]; i++) {
@@ -3188,6 +3202,7 @@ static void target_core_exit_configfs(void)
                config_item_put(item);
        }
        kfree(alua_cg->default_groups);
+       alua_cg->default_groups = NULL;
 
        hba_cg = &se_global->target_core_hbagroup;
        for (i = 0; hba_cg->default_groups[i]; i++) {
@@ -3196,20 +3211,20 @@ static void target_core_exit_configfs(void)
                config_item_put(item);
        }
        kfree(hba_cg->default_groups);
-
-       for (i = 0; subsys->su_group.default_groups[i]; i++) {
-               item = &subsys->su_group.default_groups[i]->cg_item;
-               subsys->su_group.default_groups[i] = NULL;
-               config_item_put(item);
-       }
+       hba_cg->default_groups = NULL;
+       /*
+        * We expect subsys->su_group.default_groups to be released
+        * by configfs subsystem provider logic..
+        */
+       configfs_unregister_subsystem(subsys);
        kfree(subsys->su_group.default_groups);
 
-       configfs_unregister_subsystem(subsys);
+       core_alua_free_lu_gp(se_global->default_lu_gp);
+       se_global->default_lu_gp = NULL;
+
        printk(KERN_INFO "TARGET_CORE[0]: Released ConfigFS Fabric"
                        " Infrastructure\n");
 
-       remove_scsi_target_mib();
-       remove_proc_entry("scsi_target", 0);
        core_dev_release_virtual_lun0();
        rd_module_exit();
        release_se_global();
index 317ce58..5da051a 100644 (file)
@@ -373,11 +373,11 @@ int core_update_device_list_for_node(
                /*
                 * deve->se_lun_acl will be NULL for demo-mode created LUNs
                 * that have not been explictly concerted to MappedLUNs ->
-                * struct se_lun_acl.
+                * struct se_lun_acl, but we remove deve->alua_port_list from
+                * port->sep_alua_list. This also means that active UAs and
+                * NodeACL context specific PR metadata for demo-mode
+                * MappedLUN *deve will be released below..
                 */
-               if (!(deve->se_lun_acl))
-                       return 0;
-
                spin_lock_bh(&port->sep_alua_lock);
                list_del(&deve->alua_port_list);
                spin_unlock_bh(&port->sep_alua_lock);
@@ -395,12 +395,14 @@ int core_update_device_list_for_node(
                                printk(KERN_ERR "struct se_dev_entry->se_lun_acl"
                                        " already set for demo mode -> explict"
                                        " LUN ACL transition\n");
+                               spin_unlock_irq(&nacl->device_list_lock);
                                return -1;
                        }
                        if (deve->se_lun != lun) {
                                printk(KERN_ERR "struct se_dev_entry->se_lun does"
                                        " match passed struct se_lun for demo mode"
                                        " -> explict LUN ACL transition\n");
+                               spin_unlock_irq(&nacl->device_list_lock);
                                return -1;
                        }
                        deve->se_lun_acl = lun_acl;
@@ -865,9 +867,6 @@ static void se_dev_stop(struct se_device *dev)
                }
        }
        spin_unlock(&hba->device_lock);
-
-       while (atomic_read(&hba->dev_mib_access_count))
-               cpu_relax();
 }
 
 int se_dev_check_online(struct se_device *dev)
index 32b148d..b65d1c8 100644 (file)
@@ -214,12 +214,22 @@ TCM_MAPPEDLUN_ATTR(write_protect, S_IRUGO | S_IWUSR);
 
 CONFIGFS_EATTR_OPS(target_fabric_mappedlun, se_lun_acl, se_lun_group);
 
+static void target_fabric_mappedlun_release(struct config_item *item)
+{
+       struct se_lun_acl *lacl = container_of(to_config_group(item),
+                               struct se_lun_acl, se_lun_group);
+       struct se_portal_group *se_tpg = lacl->se_lun_nacl->se_tpg;
+
+       core_dev_free_initiator_node_lun_acl(se_tpg, lacl);
+}
+
 static struct configfs_attribute *target_fabric_mappedlun_attrs[] = {
        &target_fabric_mappedlun_write_protect.attr,
        NULL,
 };
 
 static struct configfs_item_operations target_fabric_mappedlun_item_ops = {
+       .release                = target_fabric_mappedlun_release,
        .show_attribute         = target_fabric_mappedlun_attr_show,
        .store_attribute        = target_fabric_mappedlun_attr_store,
        .allow_link             = target_fabric_mappedlun_link,
@@ -337,15 +347,21 @@ static void target_fabric_drop_mappedlun(
        struct config_group *group,
        struct config_item *item)
 {
-       struct se_lun_acl *lacl = container_of(to_config_group(item),
-                       struct se_lun_acl, se_lun_group);
-       struct se_portal_group *se_tpg = lacl->se_lun_nacl->se_tpg;
-
        config_item_put(item);
-       core_dev_free_initiator_node_lun_acl(se_tpg, lacl);
+}
+
+static void target_fabric_nacl_base_release(struct config_item *item)
+{
+       struct se_node_acl *se_nacl = container_of(to_config_group(item),
+                       struct se_node_acl, acl_group);
+       struct se_portal_group *se_tpg = se_nacl->se_tpg;
+       struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
+
+       tf->tf_ops.fabric_drop_nodeacl(se_nacl);
 }
 
 static struct configfs_item_operations target_fabric_nacl_base_item_ops = {
+       .release                = target_fabric_nacl_base_release,
        .show_attribute         = target_fabric_nacl_base_attr_show,
        .store_attribute        = target_fabric_nacl_base_attr_store,
 };
@@ -404,9 +420,6 @@ static void target_fabric_drop_nodeacl(
        struct config_group *group,
        struct config_item *item)
 {
-       struct se_portal_group *se_tpg = container_of(group,
-                       struct se_portal_group, tpg_acl_group);
-       struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
        struct se_node_acl *se_nacl = container_of(to_config_group(item),
                        struct se_node_acl, acl_group);
        struct config_item *df_item;
@@ -419,9 +432,10 @@ static void target_fabric_drop_nodeacl(
                nacl_cg->default_groups[i] = NULL;
                config_item_put(df_item);
        }
-
+       /*
+        * struct se_node_acl free is done in target_fabric_nacl_base_release()
+        */
        config_item_put(item);
-       tf->tf_ops.fabric_drop_nodeacl(se_nacl);
 }
 
 static struct configfs_group_operations target_fabric_nacl_group_ops = {
@@ -437,7 +451,18 @@ TF_CIT_SETUP(tpg_nacl, NULL, &target_fabric_nacl_group_ops, NULL);
 
 CONFIGFS_EATTR_OPS(target_fabric_np_base, se_tpg_np, tpg_np_group);
 
+static void target_fabric_np_base_release(struct config_item *item)
+{
+       struct se_tpg_np *se_tpg_np = container_of(to_config_group(item),
+                               struct se_tpg_np, tpg_np_group);
+       struct se_portal_group *se_tpg = se_tpg_np->tpg_np_parent;
+       struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
+
+       tf->tf_ops.fabric_drop_np(se_tpg_np);
+}
+
 static struct configfs_item_operations target_fabric_np_base_item_ops = {
+       .release                = target_fabric_np_base_release,
        .show_attribute         = target_fabric_np_base_attr_show,
        .store_attribute        = target_fabric_np_base_attr_store,
 };
@@ -466,6 +491,7 @@ static struct config_group *target_fabric_make_np(
        if (!(se_tpg_np) || IS_ERR(se_tpg_np))
                return ERR_PTR(-EINVAL);
 
+       se_tpg_np->tpg_np_parent = se_tpg;
        config_group_init_type_name(&se_tpg_np->tpg_np_group, name,
                        &TF_CIT_TMPL(tf)->tfc_tpg_np_base_cit);
 
@@ -476,14 +502,10 @@ static void target_fabric_drop_np(
        struct config_group *group,
        struct config_item *item)
 {
-       struct se_portal_group *se_tpg = container_of(group,
-                               struct se_portal_group, tpg_np_group);
-       struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
-       struct se_tpg_np *se_tpg_np = container_of(to_config_group(item),
-                               struct se_tpg_np, tpg_np_group);
-
+       /*
+        * struct se_tpg_np is released via target_fabric_np_base_release()
+        */
        config_item_put(item);
-       tf->tf_ops.fabric_drop_np(se_tpg_np);
 }
 
 static struct configfs_group_operations target_fabric_np_group_ops = {
@@ -814,7 +836,18 @@ TF_CIT_SETUP(tpg_param, &target_fabric_tpg_param_item_ops, NULL, NULL);
  */
 CONFIGFS_EATTR_OPS(target_fabric_tpg, se_portal_group, tpg_group);
 
+static void target_fabric_tpg_release(struct config_item *item)
+{
+       struct se_portal_group *se_tpg = container_of(to_config_group(item),
+                       struct se_portal_group, tpg_group);
+       struct se_wwn *wwn = se_tpg->se_tpg_wwn;
+       struct target_fabric_configfs *tf = wwn->wwn_tf;
+
+       tf->tf_ops.fabric_drop_tpg(se_tpg);
+}
+
 static struct configfs_item_operations target_fabric_tpg_base_item_ops = {
+       .release                = target_fabric_tpg_release,
        .show_attribute         = target_fabric_tpg_attr_show,
        .store_attribute        = target_fabric_tpg_attr_store,
 };
@@ -872,8 +905,6 @@ static void target_fabric_drop_tpg(
        struct config_group *group,
        struct config_item *item)
 {
-       struct se_wwn *wwn = container_of(group, struct se_wwn, wwn_group);
-       struct target_fabric_configfs *tf = wwn->wwn_tf;
        struct se_portal_group *se_tpg = container_of(to_config_group(item),
                                struct se_portal_group, tpg_group);
        struct config_group *tpg_cg = &se_tpg->tpg_group;
@@ -890,15 +921,28 @@ static void target_fabric_drop_tpg(
        }
 
        config_item_put(item);
-       tf->tf_ops.fabric_drop_tpg(se_tpg);
 }
 
+static void target_fabric_release_wwn(struct config_item *item)
+{
+       struct se_wwn *wwn = container_of(to_config_group(item),
+                               struct se_wwn, wwn_group);
+       struct target_fabric_configfs *tf = wwn->wwn_tf;
+
+       tf->tf_ops.fabric_drop_wwn(wwn);
+}
+
+static struct configfs_item_operations target_fabric_tpg_item_ops = {
+       .release        = target_fabric_release_wwn,
+};
+
 static struct configfs_group_operations target_fabric_tpg_group_ops = {
        .make_group     = target_fabric_make_tpg,
        .drop_item      = target_fabric_drop_tpg,
 };
 
-TF_CIT_SETUP(tpg, NULL, &target_fabric_tpg_group_ops, NULL);
+TF_CIT_SETUP(tpg, &target_fabric_tpg_item_ops, &target_fabric_tpg_group_ops,
+               NULL);
 
 /* End of tfc_tpg_cit */
 
@@ -932,13 +976,7 @@ static void target_fabric_drop_wwn(
        struct config_group *group,
        struct config_item *item)
 {
-       struct target_fabric_configfs *tf = container_of(group,
-                               struct target_fabric_configfs, tf_group);
-       struct se_wwn *wwn = container_of(to_config_group(item),
-                               struct se_wwn, wwn_group);
-
        config_item_put(item);
-       tf->tf_ops.fabric_drop_wwn(wwn);
 }
 
 static struct configfs_group_operations target_fabric_wwn_group_ops = {
index c6e0d75..67f0c09 100644 (file)
@@ -154,7 +154,7 @@ static struct se_device *iblock_create_virtdevice(
 
        bd = blkdev_get_by_path(ib_dev->ibd_udev_path,
                                FMODE_WRITE|FMODE_READ|FMODE_EXCL, ib_dev);
-       if (!(bd))
+       if (IS_ERR(bd))
                goto failed;
        /*
         * Setup the local scope queue_limits from struct request_queue->limits
@@ -220,8 +220,10 @@ static void iblock_free_device(void *p)
 {
        struct iblock_dev *ib_dev = p;
 
-       blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL);
-       bioset_free(ib_dev->ibd_bio_set);
+       if (ib_dev->ibd_bd != NULL)
+               blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL);
+       if (ib_dev->ibd_bio_set != NULL)
+               bioset_free(ib_dev->ibd_bio_set);
        kfree(ib_dev);
 }
 
diff --git a/drivers/target/target_core_mib.c b/drivers/target/target_core_mib.c
deleted file mode 100644 (file)
index d5a48aa..0000000
+++ /dev/null
@@ -1,1078 +0,0 @@
-/*******************************************************************************
- * Filename:  target_core_mib.c
- *
- * Copyright (c) 2006-2007 SBE, Inc.  All Rights Reserved.
- * Copyright (c) 2007-2010 Rising Tide Systems
- * Copyright (c) 2008-2010 Linux-iSCSI.org
- *
- * Nicholas A. Bellinger <nab@linux-iscsi.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- ******************************************************************************/
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/version.h>
-#include <generated/utsrelease.h>
-#include <linux/utsname.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/blkdev.h>
-#include <scsi/scsi.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_host.h>
-
-#include <target/target_core_base.h>
-#include <target/target_core_transport.h>
-#include <target/target_core_fabric_ops.h>
-#include <target/target_core_configfs.h>
-
-#include "target_core_hba.h"
-#include "target_core_mib.h"
-
-/* SCSI mib table index */
-static struct scsi_index_table scsi_index_table;
-
-#ifndef INITIAL_JIFFIES
-#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ))
-#endif
-
-/* SCSI Instance Table */
-#define SCSI_INST_SW_INDEX             1
-#define SCSI_TRANSPORT_INDEX           1
-
-#define NONE           "None"
-#define ISPRINT(a)   ((a >= ' ') && (a <= '~'))
-
-static inline int list_is_first(const struct list_head *list,
-                               const struct list_head *head)
-{
-       return list->prev == head;
-}
-
-static void *locate_hba_start(
-       struct seq_file *seq,
-       loff_t *pos)
-{
-       spin_lock(&se_global->g_device_lock);
-       return seq_list_start(&se_global->g_se_dev_list, *pos);
-}
-
-static void *locate_hba_next(
-       struct seq_file *seq,
-       void *v,
-       loff_t *pos)
-{
-       return seq_list_next(v, &se_global->g_se_dev_list, pos);
-}
-
-static void locate_hba_stop(struct seq_file *seq, void *v)
-{
-       spin_unlock(&se_global->g_device_lock);
-}
-
-/****************************************************************************
- * SCSI MIB Tables
- ****************************************************************************/
-
-/*
- * SCSI Instance Table
- */
-static void *scsi_inst_seq_start(
-       struct seq_file *seq,
-       loff_t *pos)
-{
-       spin_lock(&se_global->hba_lock);
-       return seq_list_start(&se_global->g_hba_list, *pos);
-}
-
-static void *scsi_inst_seq_next(
-       struct seq_file *seq,
-       void *v,
-       loff_t *pos)
-{
-       return seq_list_next(v, &se_global->g_hba_list, pos);
-}
-
-static void scsi_inst_seq_stop(struct seq_file *seq, void *v)
-{
-       spin_unlock(&se_global->hba_lock);
-}
-
-static int scsi_inst_seq_show(struct seq_file *seq, void *v)
-{
-       struct se_hba *hba = list_entry(v, struct se_hba, hba_list);
-
-       if (list_is_first(&hba->hba_list, &se_global->g_hba_list))
-               seq_puts(seq, "inst sw_indx\n");
-
-       seq_printf(seq, "%u %u\n", hba->hba_index, SCSI_INST_SW_INDEX);
-       seq_printf(seq, "plugin: %s version: %s\n",
-                       hba->transport->name, TARGET_CORE_VERSION);
-
-       return 0;
-}
-
-static const struct seq_operations scsi_inst_seq_ops = {
-       .start  = scsi_inst_seq_start,
-       .next   = scsi_inst_seq_next,
-       .stop   = scsi_inst_seq_stop,
-       .show   = scsi_inst_seq_show
-};
-
-static int scsi_inst_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &scsi_inst_seq_ops);
-}
-
-static const struct file_operations scsi_inst_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = scsi_inst_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-/*
- * SCSI Device Table
- */
-static void *scsi_dev_seq_start(struct seq_file *seq, loff_t *pos)
-{
-       return locate_hba_start(seq, pos);
-}
-
-static void *scsi_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-       return locate_hba_next(seq, v, pos);
-}
-
-static void scsi_dev_seq_stop(struct seq_file *seq, void *v)
-{
-       locate_hba_stop(seq, v);
-}
-
-static int scsi_dev_seq_show(struct seq_file *seq, void *v)
-{
-       struct se_hba *hba;
-       struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
-                                               g_se_dev_list);
-       struct se_device *dev = se_dev->se_dev_ptr;
-       char str[28];
-       int k;
-
-       if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
-               seq_puts(seq, "inst indx role ports\n");
-
-       if (!(dev))
-               return 0;
-
-       hba = dev->se_hba;
-       if (!(hba)) {
-               /* Log error ? */
-               return 0;
-       }
-
-       seq_printf(seq, "%u %u %s %u\n", hba->hba_index,
-                  dev->dev_index, "Target", dev->dev_port_count);
-
-       memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28);
-
-       /* vendor */
-       for (k = 0; k < 8; k++)
-               str[k] = ISPRINT(DEV_T10_WWN(dev)->vendor[k]) ?
-                               DEV_T10_WWN(dev)->vendor[k] : 0x20;
-       str[k] = 0x20;
-
-       /* model */
-       for (k = 0; k < 16; k++)
-               str[k+9] = ISPRINT(DEV_T10_WWN(dev)->model[k]) ?
-                               DEV_T10_WWN(dev)->model[k] : 0x20;
-       str[k + 9] = 0;
-
-       seq_printf(seq, "dev_alias: %s\n", str);
-
-       return 0;
-}
-
-static const struct seq_operations scsi_dev_seq_ops = {
-       .start  = scsi_dev_seq_start,
-       .next   = scsi_dev_seq_next,
-       .stop   = scsi_dev_seq_stop,
-       .show   = scsi_dev_seq_show
-};
-
-static int scsi_dev_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &scsi_dev_seq_ops);
-}
-
-static const struct file_operations scsi_dev_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = scsi_dev_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-/*
- * SCSI Port Table
- */
-static void *scsi_port_seq_start(struct seq_file *seq, loff_t *pos)
-{
-       return locate_hba_start(seq, pos);
-}
-
-static void *scsi_port_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-       return locate_hba_next(seq, v, pos);
-}
-
-static void scsi_port_seq_stop(struct seq_file *seq, void *v)
-{
-       locate_hba_stop(seq, v);
-}
-
-static int scsi_port_seq_show(struct seq_file *seq, void *v)
-{
-       struct se_hba *hba;
-       struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
-                                               g_se_dev_list);
-       struct se_device *dev = se_dev->se_dev_ptr;
-       struct se_port *sep, *sep_tmp;
-
-       if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
-               seq_puts(seq, "inst device indx role busy_count\n");
-
-       if (!(dev))
-               return 0;
-
-       hba = dev->se_hba;
-       if (!(hba)) {
-               /* Log error ? */
-               return 0;
-       }
-
-       /* FIXME: scsiPortBusyStatuses count */
-       spin_lock(&dev->se_port_lock);
-       list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list, sep_list) {
-               seq_printf(seq, "%u %u %u %s%u %u\n", hba->hba_index,
-                       dev->dev_index, sep->sep_index, "Device",
-                       dev->dev_index, 0);
-       }
-       spin_unlock(&dev->se_port_lock);
-
-       return 0;
-}
-
-static const struct seq_operations scsi_port_seq_ops = {
-       .start  = scsi_port_seq_start,
-       .next   = scsi_port_seq_next,
-       .stop   = scsi_port_seq_stop,
-       .show   = scsi_port_seq_show
-};
-
-static int scsi_port_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &scsi_port_seq_ops);
-}
-
-static const struct file_operations scsi_port_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = scsi_port_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-/*
- * SCSI Transport Table
- */
-static void *scsi_transport_seq_start(struct seq_file *seq, loff_t *pos)
-{
-       return locate_hba_start(seq, pos);
-}
-
-static void *scsi_transport_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-       return locate_hba_next(seq, v, pos);
-}
-
-static void scsi_transport_seq_stop(struct seq_file *seq, void *v)
-{
-       locate_hba_stop(seq, v);
-}
-
-static int scsi_transport_seq_show(struct seq_file *seq, void *v)
-{
-       struct se_hba *hba;
-       struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
-                                               g_se_dev_list);
-       struct se_device *dev = se_dev->se_dev_ptr;
-       struct se_port *se, *se_tmp;
-       struct se_portal_group *tpg;
-       struct t10_wwn *wwn;
-       char buf[64];
-
-       if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
-               seq_puts(seq, "inst device indx dev_name\n");
-
-       if (!(dev))
-               return 0;
-
-       hba = dev->se_hba;
-       if (!(hba)) {
-               /* Log error ? */
-               return 0;
-       }
-
-       wwn = DEV_T10_WWN(dev);
-
-       spin_lock(&dev->se_port_lock);
-       list_for_each_entry_safe(se, se_tmp, &dev->dev_sep_list, sep_list) {
-               tpg = se->sep_tpg;
-               sprintf(buf, "scsiTransport%s",
-                               TPG_TFO(tpg)->get_fabric_name());
-
-               seq_printf(seq, "%u %s %u %s+%s\n",
-                       hba->hba_index, /* scsiTransportIndex */
-                       buf,  /* scsiTransportType */
-                       (TPG_TFO(tpg)->tpg_get_inst_index != NULL) ?
-                       TPG_TFO(tpg)->tpg_get_inst_index(tpg) :
-                       0,
-                       TPG_TFO(tpg)->tpg_get_wwn(tpg),
-                       (strlen(wwn->unit_serial)) ?
-                       /* scsiTransportDevName */
-                       wwn->unit_serial : wwn->vendor);
-       }
-       spin_unlock(&dev->se_port_lock);
-
-       return 0;
-}
-
-static const struct seq_operations scsi_transport_seq_ops = {
-       .start  = scsi_transport_seq_start,
-       .next   = scsi_transport_seq_next,
-       .stop   = scsi_transport_seq_stop,
-       .show   = scsi_transport_seq_show
-};
-
-static int scsi_transport_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &scsi_transport_seq_ops);
-}
-
-static const struct file_operations scsi_transport_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = scsi_transport_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-/*
- * SCSI Target Device Table
- */
-static void *scsi_tgt_dev_seq_start(struct seq_file *seq, loff_t *pos)
-{
-       return locate_hba_start(seq, pos);
-}
-
-static void *scsi_tgt_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-       return locate_hba_next(seq, v, pos);
-}
-
-static void scsi_tgt_dev_seq_stop(struct seq_file *seq, void *v)
-{
-       locate_hba_stop(seq, v);
-}
-
-
-#define LU_COUNT       1  /* for now */
-static int scsi_tgt_dev_seq_show(struct seq_file *seq, void *v)
-{
-       struct se_hba *hba;
-       struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
-                                               g_se_dev_list);
-       struct se_device *dev = se_dev->se_dev_ptr;
-       int non_accessible_lus = 0;
-       char status[16];
-
-       if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
-               seq_puts(seq, "inst indx num_LUs status non_access_LUs"
-                       " resets\n");
-
-       if (!(dev))
-               return 0;
-
-       hba = dev->se_hba;
-       if (!(hba)) {
-               /* Log error ? */
-               return 0;
-       }
-
-       switch (dev->dev_status) {
-       case TRANSPORT_DEVICE_ACTIVATED:
-               strcpy(status, "activated");
-               break;
-       case TRANSPORT_DEVICE_DEACTIVATED:
-               strcpy(status, "deactivated");
-               non_accessible_lus = 1;
-               break;
-       case TRANSPORT_DEVICE_SHUTDOWN:
-               strcpy(status, "shutdown");
-               non_accessible_lus = 1;
-               break;
-       case TRANSPORT_DEVICE_OFFLINE_ACTIVATED:
-       case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED:
-               strcpy(status, "offline");
-               non_accessible_lus = 1;
-               break;
-       default:
-               sprintf(status, "unknown(%d)", dev->dev_status);
-               non_accessible_lus = 1;
-       }
-
-       seq_printf(seq, "%u %u %u %s %u %u\n",
-                  hba->hba_index, dev->dev_index, LU_COUNT,
-                  status, non_accessible_lus, dev->num_resets);
-
-       return 0;
-}
-
-static const struct seq_operations scsi_tgt_dev_seq_ops = {
-       .start  = scsi_tgt_dev_seq_start,
-       .next   = scsi_tgt_dev_seq_next,
-       .stop   = scsi_tgt_dev_seq_stop,
-       .show   = scsi_tgt_dev_seq_show
-};
-
-static int scsi_tgt_dev_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &scsi_tgt_dev_seq_ops);
-}
-
-static const struct file_operations scsi_tgt_dev_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = scsi_tgt_dev_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-/*
- * SCSI Target Port Table
- */
-static void *scsi_tgt_port_seq_start(struct seq_file *seq, loff_t *pos)
-{
-       return locate_hba_start(seq, pos);
-}
-
-static void *scsi_tgt_port_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-       return locate_hba_next(seq, v, pos);
-}
-
-static void scsi_tgt_port_seq_stop(struct seq_file *seq, void *v)
-{
-       locate_hba_stop(seq, v);
-}
-
-static int scsi_tgt_port_seq_show(struct seq_file *seq, void *v)
-{
-       struct se_hba *hba;
-       struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
-                                               g_se_dev_list);
-       struct se_device *dev = se_dev->se_dev_ptr;
-       struct se_port *sep, *sep_tmp;
-       struct se_portal_group *tpg;
-       u32 rx_mbytes, tx_mbytes;
-       unsigned long long num_cmds;
-       char buf[64];
-
-       if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
-               seq_puts(seq, "inst device indx name port_index in_cmds"
-                       " write_mbytes read_mbytes hs_in_cmds\n");
-
-       if (!(dev))
-               return 0;
-
-       hba = dev->se_hba;
-       if (!(hba)) {
-               /* Log error ? */
-               return 0;
-       }
-
-       spin_lock(&dev->se_port_lock);
-       list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list, sep_list) {
-               tpg = sep->sep_tpg;
-               sprintf(buf, "%sPort#",
-                       TPG_TFO(tpg)->get_fabric_name());
-
-               seq_printf(seq, "%u %u %u %s%d %s%s%d ",
-                    hba->hba_index,
-                    dev->dev_index,
-                    sep->sep_index,
-                    buf, sep->sep_index,
-                    TPG_TFO(tpg)->tpg_get_wwn(tpg), "+t+",
-                    TPG_TFO(tpg)->tpg_get_tag(tpg));
-
-               spin_lock(&sep->sep_lun->lun_sep_lock);
-               num_cmds = sep->sep_stats.cmd_pdus;
-               rx_mbytes = (sep->sep_stats.rx_data_octets >> 20);
-               tx_mbytes = (sep->sep_stats.tx_data_octets >> 20);
-               spin_unlock(&sep->sep_lun->lun_sep_lock);
-
-               seq_printf(seq, "%llu %u %u %u\n", num_cmds,
-                       rx_mbytes, tx_mbytes, 0);
-       }
-       spin_unlock(&dev->se_port_lock);
-
-       return 0;
-}
-
-static const struct seq_operations scsi_tgt_port_seq_ops = {
-       .start  = scsi_tgt_port_seq_start,
-       .next   = scsi_tgt_port_seq_next,
-       .stop   = scsi_tgt_port_seq_stop,
-       .show   = scsi_tgt_port_seq_show
-};
-
-static int scsi_tgt_port_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &scsi_tgt_port_seq_ops);
-}
-
-static const struct file_operations scsi_tgt_port_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = scsi_tgt_port_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-/*
- * SCSI Authorized Initiator Table:
- * It contains the SCSI Initiators authorized to be attached to one of the
- * local Target ports.
- * Iterates through all active TPGs and extracts the info from the ACLs
- */
-static void *scsi_auth_intr_seq_start(struct seq_file *seq, loff_t *pos)
-{
-       spin_lock_bh(&se_global->se_tpg_lock);
-       return seq_list_start(&se_global->g_se_tpg_list, *pos);
-}
-
-static void *scsi_auth_intr_seq_next(struct seq_file *seq, void *v,
-                                        loff_t *pos)
-{
-       return seq_list_next(v, &se_global->g_se_tpg_list, pos);
-}
-
-static void scsi_auth_intr_seq_stop(struct seq_file *seq, void *v)
-{
-       spin_unlock_bh(&se_global->se_tpg_lock);
-}
-
-static int scsi_auth_intr_seq_show(struct seq_file *seq, void *v)
-{
-       struct se_portal_group *se_tpg = list_entry(v, struct se_portal_group,
-                                               se_tpg_list);
-       struct se_dev_entry *deve;
-       struct se_lun *lun;
-       struct se_node_acl *se_nacl;
-       int j;
-
-       if (list_is_first(&se_tpg->se_tpg_list,
-                         &se_global->g_se_tpg_list))
-               seq_puts(seq, "inst dev port indx dev_or_port intr_name "
-                        "map_indx att_count num_cmds read_mbytes "
-                        "write_mbytes hs_num_cmds creation_time row_status\n");
-
-       if (!(se_tpg))
-               return 0;
-
-       spin_lock(&se_tpg->acl_node_lock);
-       list_for_each_entry(se_nacl, &se_tpg->acl_node_list, acl_list) {
-
-               atomic_inc(&se_nacl->mib_ref_count);
-               smp_mb__after_atomic_inc();
-               spin_unlock(&se_tpg->acl_node_lock);
-
-               spin_lock_irq(&se_nacl->device_list_lock);
-               for (j = 0; j < TRANSPORT_MAX_LUNS_PER_TPG; j++) {
-                       deve = &se_nacl->device_list[j];
-                       if (!(deve->lun_flags &
-                                       TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) ||
-                           (!deve->se_lun))
-                               continue;
-                       lun = deve->se_lun;
-                       if (!lun->lun_se_dev)
-                               continue;
-
-                       seq_printf(seq, "%u %u %u %u %u %s %u %u %u %u %u %u"
-                                       " %u %s\n",
-                               /* scsiInstIndex */
-                               (TPG_TFO(se_tpg)->tpg_get_inst_index != NULL) ?
-                               TPG_TFO(se_tpg)->tpg_get_inst_index(se_tpg) :
-                               0,
-                               /* scsiDeviceIndex */
-                               lun->lun_se_dev->dev_index,
-                               /* scsiAuthIntrTgtPortIndex */
-                               TPG_TFO(se_tpg)->tpg_get_tag(se_tpg),
-                               /* scsiAuthIntrIndex */
-                               se_nacl->acl_index,
-                               /* scsiAuthIntrDevOrPort */
-                               1,
-                               /* scsiAuthIntrName */
-                               se_nacl->initiatorname[0] ?
-                                       se_nacl->initiatorname : NONE,
-                               /* FIXME: scsiAuthIntrLunMapIndex */
-                               0,
-                               /* scsiAuthIntrAttachedTimes */
-                               deve->attach_count,
-                               /* scsiAuthIntrOutCommands */
-                               deve->total_cmds,
-                               /* scsiAuthIntrReadMegaBytes */
-                               (u32)(deve->read_bytes >> 20),
-                               /* scsiAuthIntrWrittenMegaBytes */
-                               (u32)(deve->write_bytes >> 20),
-                               /* FIXME: scsiAuthIntrHSOutCommands */
-                               0,
-                               /* scsiAuthIntrLastCreation */
-                               (u32)(((u32)deve->creation_time -
-                                           INITIAL_JIFFIES) * 100 / HZ),
-                               /* FIXME: scsiAuthIntrRowStatus */
-                               "Ready");
-               }
-               spin_unlock_irq(&se_nacl->device_list_lock);
-
-               spin_lock(&se_tpg->acl_node_lock);
-               atomic_dec(&se_nacl->mib_ref_count);
-               smp_mb__after_atomic_dec();
-       }
-       spin_unlock(&se_tpg->acl_node_lock);
-
-       return 0;
-}
-
-static const struct seq_operations scsi_auth_intr_seq_ops = {
-       .start  = scsi_auth_intr_seq_start,
-       .next   = scsi_auth_intr_seq_next,
-       .stop   = scsi_auth_intr_seq_stop,
-       .show   = scsi_auth_intr_seq_show
-};
-
-static int scsi_auth_intr_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &scsi_auth_intr_seq_ops);
-}
-
-static const struct file_operations scsi_auth_intr_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = scsi_auth_intr_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-/*
- * SCSI Attached Initiator Port Table:
- * It lists the SCSI Initiators attached to one of the local Target ports.
- * Iterates through all active TPGs and use active sessions from each TPG
- * to list the info fo this table.
- */
-static void *scsi_att_intr_port_seq_start(struct seq_file *seq, loff_t *pos)
-{
-       spin_lock_bh(&se_global->se_tpg_lock);
-       return seq_list_start(&se_global->g_se_tpg_list, *pos);
-}
-
-static void *scsi_att_intr_port_seq_next(struct seq_file *seq, void *v,
-                                        loff_t *pos)
-{
-       return seq_list_next(v, &se_global->g_se_tpg_list, pos);
-}
-
-static void scsi_att_intr_port_seq_stop(struct seq_file *seq, void *v)
-{
-       spin_unlock_bh(&se_global->se_tpg_lock);
-}
-
-static int scsi_att_intr_port_seq_show(struct seq_file *seq, void *v)
-{
-       struct se_portal_group *se_tpg = list_entry(v, struct se_portal_group,
-                                               se_tpg_list);
-       struct se_dev_entry *deve;
-       struct se_lun *lun;
-       struct se_node_acl *se_nacl;
-       struct se_session *se_sess;
-       unsigned char buf[64];
-       int j;
-
-       if (list_is_first(&se_tpg->se_tpg_list,
-                         &se_global->g_se_tpg_list))
-               seq_puts(seq, "inst dev port indx port_auth_indx port_name"
-                       " port_ident\n");
-
-       if (!(se_tpg))
-               return 0;
-
-       spin_lock(&se_tpg->session_lock);
-       list_for_each_entry(se_sess, &se_tpg->tpg_sess_list, sess_list) {
-               if ((TPG_TFO(se_tpg)->sess_logged_in(se_sess)) ||
-                   (!se_sess->se_node_acl) ||
-                   (!se_sess->se_node_acl->device_list))
-                       continue;
-
-               atomic_inc(&se_sess->mib_ref_count);
-               smp_mb__after_atomic_inc();
-               se_nacl = se_sess->se_node_acl;
-               atomic_inc(&se_nacl->mib_ref_count);
-               smp_mb__after_atomic_inc();
-               spin_unlock(&se_tpg->session_lock);
-
-               spin_lock_irq(&se_nacl->device_list_lock);
-               for (j = 0; j < TRANSPORT_MAX_LUNS_PER_TPG; j++) {
-                       deve = &se_nacl->device_list[j];
-                       if (!(deve->lun_flags &
-                                       TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) ||
-                          (!deve->se_lun))
-                               continue;
-
-                       lun = deve->se_lun;
-                       if (!lun->lun_se_dev)
-                               continue;
-
-                       memset(buf, 0, 64);
-                       if (TPG_TFO(se_tpg)->sess_get_initiator_sid != NULL)
-                               TPG_TFO(se_tpg)->sess_get_initiator_sid(
-                                       se_sess, (unsigned char *)&buf[0], 64);
-
-                       seq_printf(seq, "%u %u %u %u %u %s+i+%s\n",
-                               /* scsiInstIndex */
-                               (TPG_TFO(se_tpg)->tpg_get_inst_index != NULL) ?
-                               TPG_TFO(se_tpg)->tpg_get_inst_index(se_tpg) :
-                               0,
-                               /* scsiDeviceIndex */
-                               lun->lun_se_dev->dev_index,
-                               /* scsiPortIndex */
-                               TPG_TFO(se_tpg)->tpg_get_tag(se_tpg),
-                               /* scsiAttIntrPortIndex */
-                               (TPG_TFO(se_tpg)->sess_get_index != NULL) ?
-                               TPG_TFO(se_tpg)->sess_get_index(se_sess) :
-                               0,
-                               /* scsiAttIntrPortAuthIntrIdx */
-                               se_nacl->acl_index,
-                               /* scsiAttIntrPortName */
-                               se_nacl->initiatorname[0] ?
-                                       se_nacl->initiatorname : NONE,
-                               /* scsiAttIntrPortIdentifier */
-                               buf);
-               }
-               spin_unlock_irq(&se_nacl->device_list_lock);
-
-               spin_lock(&se_tpg->session_lock);
-               atomic_dec(&se_nacl->mib_ref_count);
-               smp_mb__after_atomic_dec();
-               atomic_dec(&se_sess->mib_ref_count);
-               smp_mb__after_atomic_dec();
-       }
-       spin_unlock(&se_tpg->session_lock);
-
-       return 0;
-}
-
-static const struct seq_operations scsi_att_intr_port_seq_ops = {
-       .start  = scsi_att_intr_port_seq_start,
-       .next   = scsi_att_intr_port_seq_next,
-       .stop   = scsi_att_intr_port_seq_stop,
-       .show   = scsi_att_intr_port_seq_show
-};
-
-static int scsi_att_intr_port_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &scsi_att_intr_port_seq_ops);
-}
-
-static const struct file_operations scsi_att_intr_port_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = scsi_att_intr_port_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-/*
- * SCSI Logical Unit Table
- */
-static void *scsi_lu_seq_start(struct seq_file *seq, loff_t *pos)
-{
-       return locate_hba_start(seq, pos);
-}
-
-static void *scsi_lu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-       return locate_hba_next(seq, v, pos);
-}
-
-static void scsi_lu_seq_stop(struct seq_file *seq, void *v)
-{
-       locate_hba_stop(seq, v);
-}
-
-#define SCSI_LU_INDEX          1
-static int scsi_lu_seq_show(struct seq_file *seq, void *v)
-{
-       struct se_hba *hba;
-       struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
-                                               g_se_dev_list);
-       struct se_device *dev = se_dev->se_dev_ptr;
-       int j;
-       char str[28];
-
-       if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
-               seq_puts(seq, "inst dev indx LUN lu_name vend prod rev"
-               " dev_type status state-bit num_cmds read_mbytes"
-               " write_mbytes resets full_stat hs_num_cmds creation_time\n");
-
-       if (!(dev))
-               return 0;
-
-       hba = dev->se_hba;
-       if (!(hba)) {
-               /* Log error ? */
-               return 0;
-       }
-
-       /* Fix LU state, if we can read it from the device */
-       seq_printf(seq, "%u %u %u %llu %s", hba->hba_index,
-                       dev->dev_index, SCSI_LU_INDEX,
-                       (unsigned long long)0, /* FIXME: scsiLuDefaultLun */
-                       (strlen(DEV_T10_WWN(dev)->unit_serial)) ?
-                       /* scsiLuWwnName */
-                       (char *)&DEV_T10_WWN(dev)->unit_serial[0] :
-                       "None");
-
-       memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28);
-       /* scsiLuVendorId */
-       for (j = 0; j < 8; j++)
-               str[j] = ISPRINT(DEV_T10_WWN(dev)->vendor[j]) ?
-                       DEV_T10_WWN(dev)->vendor[j] : 0x20;
-       str[8] = 0;
-       seq_printf(seq, " %s", str);
-
-       /* scsiLuProductId */
-       for (j = 0; j < 16; j++)
-               str[j] = ISPRINT(DEV_T10_WWN(dev)->model[j]) ?
-                       DEV_T10_WWN(dev)->model[j] : 0x20;
-       str[16] = 0;
-       seq_printf(seq, " %s", str);
-
-       /* scsiLuRevisionId */
-       for (j = 0; j < 4; j++)
-               str[j] = ISPRINT(DEV_T10_WWN(dev)->revision[j]) ?
-                       DEV_T10_WWN(dev)->revision[j] : 0x20;
-       str[4] = 0;
-       seq_printf(seq, " %s", str);
-
-       seq_printf(seq, " %u %s %s %llu %u %u %u %u %u %u\n",
-               /* scsiLuPeripheralType */
-                  TRANSPORT(dev)->get_device_type(dev),
-                  (dev->dev_status == TRANSPORT_DEVICE_ACTIVATED) ?
-               "available" : "notavailable", /* scsiLuStatus */
-               "exposed",      /* scsiLuState */
-               (unsigned long long)dev->num_cmds,
-               /* scsiLuReadMegaBytes */
-               (u32)(dev->read_bytes >> 20),
-               /* scsiLuWrittenMegaBytes */
-               (u32)(dev->write_bytes >> 20),
-               dev->num_resets, /* scsiLuInResets */
-               0, /* scsiLuOutTaskSetFullStatus */
-               0, /* scsiLuHSInCommands */
-               (u32)(((u32)dev->creation_time - INITIAL_JIFFIES) *
-                                                       100 / HZ));
-
-       return 0;
-}
-
-static const struct seq_operations scsi_lu_seq_ops = {
-       .start  = scsi_lu_seq_start,
-       .next   = scsi_lu_seq_next,
-       .stop   = scsi_lu_seq_stop,
-       .show   = scsi_lu_seq_show
-};
-
-static int scsi_lu_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &scsi_lu_seq_ops);
-}
-
-static const struct file_operations scsi_lu_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = scsi_lu_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release,
-};
-
-/****************************************************************************/
-
-/*
- * Remove proc fs entries
- */
-void remove_scsi_target_mib(void)
-{
-       remove_proc_entry("scsi_target/mib/scsi_inst", NULL);
-       remove_proc_entry("scsi_target/mib/scsi_dev", NULL);
-       remove_proc_entry("scsi_target/mib/scsi_port", NULL);
-       remove_proc_entry("scsi_target/mib/scsi_transport", NULL);
-       remove_proc_entry("scsi_target/mib/scsi_tgt_dev", NULL);
-       remove_proc_entry("scsi_target/mib/scsi_tgt_port", NULL);
-       remove_proc_entry("scsi_target/mib/scsi_auth_intr", NULL);
-       remove_proc_entry("scsi_target/mib/scsi_att_intr_port", NULL);
-       remove_proc_entry("scsi_target/mib/scsi_lu", NULL);
-       remove_proc_entry("scsi_target/mib", NULL);
-}
-
-/*
- * Create proc fs entries for the mib tables
- */
-int init_scsi_target_mib(void)
-{
-       struct proc_dir_entry *dir_entry;
-       struct proc_dir_entry *scsi_inst_entry;
-       struct proc_dir_entry *scsi_dev_entry;
-       struct proc_dir_entry *scsi_port_entry;
-       struct proc_dir_entry *scsi_transport_entry;
-       struct proc_dir_entry *scsi_tgt_dev_entry;
-       struct proc_dir_entry *scsi_tgt_port_entry;
-       struct proc_dir_entry *scsi_auth_intr_entry;
-       struct proc_dir_entry *scsi_att_intr_port_entry;
-       struct proc_dir_entry *scsi_lu_entry;
-
-       dir_entry = proc_mkdir("scsi_target/mib", NULL);
-       if (!(dir_entry)) {
-               printk(KERN_ERR "proc_mkdir() failed.\n");
-               return -1;
-       }
-
-       scsi_inst_entry =
-               create_proc_entry("scsi_target/mib/scsi_inst", 0, NULL);
-       if (scsi_inst_entry)
-               scsi_inst_entry->proc_fops = &scsi_inst_seq_fops;
-       else
-               goto error;
-
-       scsi_dev_entry =
-               create_proc_entry("scsi_target/mib/scsi_dev", 0, NULL);
-       if (scsi_dev_entry)
-               scsi_dev_entry->proc_fops = &scsi_dev_seq_fops;
-       else
-               goto error;
-
-       scsi_port_entry =
-               create_proc_entry("scsi_target/mib/scsi_port", 0, NULL);
-       if (scsi_port_entry)
-               scsi_port_entry->proc_fops = &scsi_port_seq_fops;
-       else
-               goto error;
-
-       scsi_transport_entry =
-               create_proc_entry("scsi_target/mib/scsi_transport", 0, NULL);
-       if (scsi_transport_entry)
-               scsi_transport_entry->proc_fops = &scsi_transport_seq_fops;
-       else
-               goto error;
-
-       scsi_tgt_dev_entry =
-               create_proc_entry("scsi_target/mib/scsi_tgt_dev", 0, NULL);
-       if (scsi_tgt_dev_entry)
-               scsi_tgt_dev_entry->proc_fops = &scsi_tgt_dev_seq_fops;
-       else
-               goto error;
-
-       scsi_tgt_port_entry =
-               create_proc_entry("scsi_target/mib/scsi_tgt_port", 0, NULL);
-       if (scsi_tgt_port_entry)
-               scsi_tgt_port_entry->proc_fops = &scsi_tgt_port_seq_fops;
-       else
-               goto error;
-
-       scsi_auth_intr_entry =
-               create_proc_entry("scsi_target/mib/scsi_auth_intr", 0, NULL);
-       if (scsi_auth_intr_entry)
-               scsi_auth_intr_entry->proc_fops = &scsi_auth_intr_seq_fops;
-       else
-               goto error;
-
-       scsi_att_intr_port_entry =
-             create_proc_entry("scsi_target/mib/scsi_att_intr_port", 0, NULL);
-       if (scsi_att_intr_port_entry)
-               scsi_att_intr_port_entry->proc_fops =
-                               &scsi_att_intr_port_seq_fops;
-       else
-               goto error;
-
-       scsi_lu_entry = create_proc_entry("scsi_target/mib/scsi_lu", 0, NULL);
-       if (scsi_lu_entry)
-               scsi_lu_entry->proc_fops = &scsi_lu_seq_fops;
-       else
-               goto error;
-
-       return 0;
-
-error:
-       printk(KERN_ERR "create_proc_entry() failed.\n");
-       remove_scsi_target_mib();
-       return -1;
-}
-
-/*
- * Initialize the index table for allocating unique row indexes to various mib
- * tables
- */
-void init_scsi_index_table(void)
-{
-       memset(&scsi_index_table, 0, sizeof(struct scsi_index_table));
-       spin_lock_init(&scsi_index_table.lock);
-}
-
-/*
- * Allocate a new row index for the entry type specified
- */
-u32 scsi_get_new_index(scsi_index_t type)
-{
-       u32 new_index;
-
-       if ((type < 0) || (type >= SCSI_INDEX_TYPE_MAX)) {
-               printk(KERN_ERR "Invalid index type %d\n", type);
-               return -1;
-       }
-
-       spin_lock(&scsi_index_table.lock);
-       new_index = ++scsi_index_table.scsi_mib_index[type];
-       if (new_index == 0)
-               new_index = ++scsi_index_table.scsi_mib_index[type];
-       spin_unlock(&scsi_index_table.lock);
-
-       return new_index;
-}
-EXPORT_SYMBOL(scsi_get_new_index);
diff --git a/drivers/target/target_core_mib.h b/drivers/target/target_core_mib.h
deleted file mode 100644 (file)
index 2772046..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef TARGET_CORE_MIB_H
-#define TARGET_CORE_MIB_H
-
-typedef enum {
-       SCSI_INST_INDEX,
-       SCSI_DEVICE_INDEX,
-       SCSI_AUTH_INTR_INDEX,
-       SCSI_INDEX_TYPE_MAX
-} scsi_index_t;
-
-struct scsi_index_table {
-       spinlock_t      lock;
-       u32             scsi_mib_index[SCSI_INDEX_TYPE_MAX];
-} ____cacheline_aligned;
-
-/* SCSI Port stats */
-struct scsi_port_stats {
-       u64     cmd_pdus;
-       u64     tx_data_octets;
-       u64     rx_data_octets;
-} ____cacheline_aligned;
-
-extern int init_scsi_target_mib(void);
-extern void remove_scsi_target_mib(void);
-extern void init_scsi_index_table(void);
-extern u32 scsi_get_new_index(scsi_index_t);
-
-#endif   /*** TARGET_CORE_MIB_H ***/
index 742d246..f2a0847 100644 (file)
@@ -462,8 +462,8 @@ static struct se_device *pscsi_create_type_disk(
         */
        bd = blkdev_get_by_path(se_dev->se_dev_udev_path,
                                FMODE_WRITE|FMODE_READ|FMODE_EXCL, pdv);
-       if (!(bd)) {
-               printk("pSCSI: blkdev_get_by_path() failed\n");
+       if (IS_ERR(bd)) {
+               printk(KERN_ERR "pSCSI: blkdev_get_by_path() failed\n");
                scsi_device_put(sd);
                return NULL;
        }
index 158cecb..4a10983 100644 (file)
@@ -282,6 +282,9 @@ int core_tmr_lun_reset(
 
                        atomic_set(&task->task_active, 0);
                        atomic_set(&task->task_stop, 0);
+               } else {
+                       if (atomic_read(&task->task_execute_queue) != 0)
+                               transport_remove_task_from_execute_queue(task, dev);
                }
                __transport_stop_task_timer(task, &flags);
 
@@ -301,6 +304,7 @@ int core_tmr_lun_reset(
                        DEBUG_LR("LUN_RESET: got t_transport_active = 1 for"
                                " task: %p, t_fe_count: %d dev: %p\n", task,
                                fe_count, dev);
+                       atomic_set(&T_TASK(cmd)->t_transport_aborted, 1);
                        spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock,
                                                flags);
                        core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
@@ -310,6 +314,7 @@ int core_tmr_lun_reset(
                }
                DEBUG_LR("LUN_RESET: Got t_transport_active = 0 for task: %p,"
                        " t_fe_count: %d dev: %p\n", task, fe_count, dev);
+               atomic_set(&T_TASK(cmd)->t_transport_aborted, 1);
                spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
                core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
 
index abfa81a..c26f674 100644 (file)
@@ -275,7 +275,6 @@ struct se_node_acl *core_tpg_check_initiator_node_acl(
        spin_lock_init(&acl->device_list_lock);
        spin_lock_init(&acl->nacl_sess_lock);
        atomic_set(&acl->acl_pr_ref_count, 0);
-       atomic_set(&acl->mib_ref_count, 0);
        acl->queue_depth = TPG_TFO(tpg)->tpg_get_default_depth(tpg);
        snprintf(acl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname);
        acl->se_tpg = tpg;
@@ -318,12 +317,6 @@ void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *nacl)
                cpu_relax();
 }
 
-void core_tpg_wait_for_mib_ref(struct se_node_acl *nacl)
-{
-       while (atomic_read(&nacl->mib_ref_count) != 0)
-               cpu_relax();
-}
-
 void core_tpg_clear_object_luns(struct se_portal_group *tpg)
 {
        int i, ret;
@@ -480,7 +473,6 @@ int core_tpg_del_initiator_node_acl(
        spin_unlock_bh(&tpg->session_lock);
 
        core_tpg_wait_for_nacl_pr_ref(acl);
-       core_tpg_wait_for_mib_ref(acl);
        core_clear_initiator_node_from_tpg(acl, tpg);
        core_free_device_list_for_node(acl, tpg);
 
@@ -701,6 +693,8 @@ EXPORT_SYMBOL(core_tpg_register);
 
 int core_tpg_deregister(struct se_portal_group *se_tpg)
 {
+       struct se_node_acl *nacl, *nacl_tmp;
+
        printk(KERN_INFO "TARGET_CORE[%s]: Deallocating %s struct se_portal_group"
                " for endpoint: %s Portal Tag %u\n",
                (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) ?
@@ -714,6 +708,25 @@ int core_tpg_deregister(struct se_portal_group *se_tpg)
 
        while (atomic_read(&se_tpg->tpg_pr_ref_count) != 0)
                cpu_relax();
+       /*
+        * Release any remaining demo-mode generated se_node_acl that have
+        * not been released because of TFO->tpg_check_demo_mode_cache() == 1
+        * in transport_deregister_session().
+        */
+       spin_lock_bh(&se_tpg->acl_node_lock);
+       list_for_each_entry_safe(nacl, nacl_tmp, &se_tpg->acl_node_list,
+                       acl_list) {
+               list_del(&nacl->acl_list);
+               se_tpg->num_node_acls--;
+               spin_unlock_bh(&se_tpg->acl_node_lock);
+
+               core_tpg_wait_for_nacl_pr_ref(nacl);
+               core_free_device_list_for_node(nacl, se_tpg);
+               TPG_TFO(se_tpg)->tpg_release_fabric_acl(se_tpg, nacl);
+
+               spin_lock_bh(&se_tpg->acl_node_lock);
+       }
+       spin_unlock_bh(&se_tpg->acl_node_lock);
 
        if (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL)
                core_tpg_release_virtual_lun0(se_tpg);
index 28b6292..4bbf6c1 100644 (file)
@@ -379,6 +379,40 @@ void release_se_global(void)
        se_global = NULL;
 }
 
+/* SCSI statistics table index */
+static struct scsi_index_table scsi_index_table;
+
+/*
+ * Initialize the index table for allocating unique row indexes to various mib
+ * tables.
+ */
+void init_scsi_index_table(void)
+{
+       memset(&scsi_index_table, 0, sizeof(struct scsi_index_table));
+       spin_lock_init(&scsi_index_table.lock);
+}
+
+/*
+ * Allocate a new row index for the entry type specified
+ */
+u32 scsi_get_new_index(scsi_index_t type)
+{
+       u32 new_index;
+
+       if ((type < 0) || (type >= SCSI_INDEX_TYPE_MAX)) {
+               printk(KERN_ERR "Invalid index type %d\n", type);
+               return -EINVAL;
+       }
+
+       spin_lock(&scsi_index_table.lock);
+       new_index = ++scsi_index_table.scsi_mib_index[type];
+       if (new_index == 0)
+               new_index = ++scsi_index_table.scsi_mib_index[type];
+       spin_unlock(&scsi_index_table.lock);
+
+       return new_index;
+}
+
 void transport_init_queue_obj(struct se_queue_obj *qobj)
 {
        atomic_set(&qobj->queue_cnt, 0);
@@ -437,7 +471,6 @@ struct se_session *transport_init_session(void)
        }
        INIT_LIST_HEAD(&se_sess->sess_list);
        INIT_LIST_HEAD(&se_sess->sess_acl_list);
-       atomic_set(&se_sess->mib_ref_count, 0);
 
        return se_sess;
 }
@@ -546,12 +579,6 @@ void transport_deregister_session(struct se_session *se_sess)
                transport_free_session(se_sess);
                return;
        }
-       /*
-        * Wait for possible reference in drivers/target/target_core_mib.c:
-        * scsi_att_intr_port_seq_show()
-        */
-       while (atomic_read(&se_sess->mib_ref_count) != 0)
-               cpu_relax();
 
        spin_lock_bh(&se_tpg->session_lock);
        list_del(&se_sess->sess_list);
@@ -574,7 +601,6 @@ void transport_deregister_session(struct se_session *se_sess)
                                spin_unlock_bh(&se_tpg->acl_node_lock);
 
                                core_tpg_wait_for_nacl_pr_ref(se_nacl);
-                               core_tpg_wait_for_mib_ref(se_nacl);
                                core_free_device_list_for_node(se_nacl, se_tpg);
                                TPG_TFO(se_tpg)->tpg_release_fabric_acl(se_tpg,
                                                se_nacl);
@@ -1181,7 +1207,7 @@ transport_get_task_from_execute_queue(struct se_device *dev)
  *
  *
  */
-static void transport_remove_task_from_execute_queue(
+void transport_remove_task_from_execute_queue(
        struct se_task *task,
        struct se_device *dev)
 {
@@ -4827,6 +4853,8 @@ static int transport_do_se_mem_map(
 
                return ret;
        }
+
+       BUG_ON(list_empty(se_mem_list));
        /*
         * This is the normal path for all normal non BIDI and BIDI-COMMAND
         * WRITE payloads..  If we need to do BIDI READ passthrough for
@@ -5008,7 +5036,9 @@ transport_map_control_cmd_to_task(struct se_cmd *cmd)
                struct se_mem *se_mem = NULL, *se_mem_lout = NULL;
                u32 se_mem_cnt = 0, task_offset = 0;
 
-               BUG_ON(list_empty(cmd->t_task->t_mem_list));
+               if (!list_empty(T_TASK(cmd)->t_mem_list))
+                       se_mem = list_entry(T_TASK(cmd)->t_mem_list->next,
+                                       struct se_mem, se_list);
 
                ret = transport_do_se_mem_map(dev, task,
                                cmd->t_task->t_mem_list, NULL, se_mem,
@@ -5519,7 +5549,8 @@ static void transport_generic_wait_for_tasks(
 
                atomic_set(&T_TASK(cmd)->transport_lun_stop, 0);
        }
-       if (!atomic_read(&T_TASK(cmd)->t_transport_active))
+       if (!atomic_read(&T_TASK(cmd)->t_transport_active) ||
+            atomic_read(&T_TASK(cmd)->t_transport_aborted))
                goto remove;
 
        atomic_set(&T_TASK(cmd)->t_transport_stop, 1);
@@ -5926,6 +5957,9 @@ static void transport_processing_shutdown(struct se_device *dev)
 
                        atomic_set(&task->task_active, 0);
                        atomic_set(&task->task_stop, 0);
+               } else {
+                       if (atomic_read(&task->task_execute_queue) != 0)
+                               transport_remove_task_from_execute_queue(task, dev);
                }
                __transport_stop_task_timer(task, &flags);
 
index f7a5dba..bf7c687 100644 (file)
@@ -4,7 +4,6 @@
 
 menuconfig THERMAL
        tristate "Generic Thermal sysfs driver"
-       depends on NET
        help
          Generic Thermal Sysfs driver offers a generic mechanism for
          thermal management. Usually it's made up of one or more thermal
index 7d0e63c..713b7ea 100644 (file)
@@ -62,20 +62,6 @@ static DEFINE_MUTEX(thermal_list_lock);
 
 static unsigned int thermal_event_seqnum;
 
-static struct genl_family thermal_event_genl_family = {
-       .id = GENL_ID_GENERATE,
-       .name = THERMAL_GENL_FAMILY_NAME,
-       .version = THERMAL_GENL_VERSION,
-       .maxattr = THERMAL_GENL_ATTR_MAX,
-};
-
-static struct genl_multicast_group thermal_event_mcgrp = {
-       .name = THERMAL_GENL_MCAST_GROUP_NAME,
-};
-
-static int genetlink_init(void);
-static void genetlink_exit(void);
-
 static int get_idr(struct idr *idr, struct mutex *lock, int *id)
 {
        int err;
@@ -1225,6 +1211,18 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
 
 EXPORT_SYMBOL(thermal_zone_device_unregister);
 
+#ifdef CONFIG_NET
+static struct genl_family thermal_event_genl_family = {
+       .id = GENL_ID_GENERATE,
+       .name = THERMAL_GENL_FAMILY_NAME,
+       .version = THERMAL_GENL_VERSION,
+       .maxattr = THERMAL_GENL_ATTR_MAX,
+};
+
+static struct genl_multicast_group thermal_event_mcgrp = {
+       .name = THERMAL_GENL_MCAST_GROUP_NAME,
+};
+
 int generate_netlink_event(u32 orig, enum events event)
 {
        struct sk_buff *skb;
@@ -1301,6 +1299,15 @@ static int genetlink_init(void)
        return result;
 }
 
+static void genetlink_exit(void)
+{
+       genl_unregister_family(&thermal_event_genl_family);
+}
+#else /* !CONFIG_NET */
+static inline int genetlink_init(void) { return 0; }
+static inline void genetlink_exit(void) {}
+#endif /* !CONFIG_NET */
+
 static int __init thermal_init(void)
 {
        int result = 0;
@@ -1316,11 +1323,6 @@ static int __init thermal_init(void)
        return result;
 }
 
-static void genetlink_exit(void)
-{
-       genl_unregister_family(&thermal_event_genl_family);
-}
-
 static void __exit thermal_exit(void)
 {
        class_unregister(&thermal_class);
index e6bed5f..d79e7e9 100644 (file)
@@ -10,4 +10,3 @@ obj-$(CONFIG_HVC_XEN)         += hvc_xen.o
 obj-$(CONFIG_HVC_IUCV)         += hvc_iucv.o
 obj-$(CONFIG_HVC_UDBG)         += hvc_udbg.o
 obj-$(CONFIG_HVCS)             += hvcs.o
-obj-$(CONFIG_VIRTIO_CONSOLE)   += virtio_console.o
diff --git a/drivers/tty/hvc/virtio_console.c b/drivers/tty/hvc/virtio_console.c
deleted file mode 100644 (file)
index 896a2ce..0000000
+++ /dev/null
@@ -1,1838 +0,0 @@
-/*
- * Copyright (C) 2006, 2007, 2009 Rusty Russell, IBM Corporation
- * Copyright (C) 2009, 2010 Red Hat, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#include <linux/cdev.h>
-#include <linux/debugfs.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/poll.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/virtio.h>
-#include <linux/virtio_console.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-#include "hvc_console.h"
-
-/*
- * This is a global struct for storing common data for all the devices
- * this driver handles.
- *
- * Mainly, it has a linked list for all the consoles in one place so
- * that callbacks from hvc for get_chars(), put_chars() work properly
- * across multiple devices and multiple ports per device.
- */
-struct ports_driver_data {
-       /* Used for registering chardevs */
-       struct class *class;
-
-       /* Used for exporting per-port information to debugfs */
-       struct dentry *debugfs_dir;
-
-       /* List of all the devices we're handling */
-       struct list_head portdevs;
-
-       /* Number of devices this driver is handling */
-       unsigned int index;
-
-       /*
-        * This is used to keep track of the number of hvc consoles
-        * spawned by this driver.  This number is given as the first
-        * argument to hvc_alloc().  To correctly map an initial
-        * console spawned via hvc_instantiate to the console being
-        * hooked up via hvc_alloc, we need to pass the same vtermno.
-        *
-        * We also just assume the first console being initialised was
-        * the first one that got used as the initial console.
-        */
-       unsigned int next_vtermno;
-
-       /* All the console devices handled by this driver */
-       struct list_head consoles;
-};
-static struct ports_driver_data pdrvdata;
-
-DEFINE_SPINLOCK(pdrvdata_lock);
-
-/* This struct holds information that's relevant only for console ports */
-struct console {
-       /* We'll place all consoles in a list in the pdrvdata struct */
-       struct list_head list;
-
-       /* The hvc device associated with this console port */
-       struct hvc_struct *hvc;
-
-       /* The size of the console */
-       struct winsize ws;
-
-       /*
-        * This number identifies the number that we used to register
-        * with hvc in hvc_instantiate() and hvc_alloc(); this is the
-        * number passed on by the hvc callbacks to us to
-        * differentiate between the other console ports handled by
-        * this driver
-        */
-       u32 vtermno;
-};
-
-struct port_buffer {
-       char *buf;
-
-       /* size of the buffer in *buf above */
-       size_t size;
-
-       /* used length of the buffer */
-       size_t len;
-       /* offset in the buf from which to consume data */
-       size_t offset;
-};
-
-/*
- * This is a per-device struct that stores data common to all the
- * ports for that device (vdev->priv).
- */
-struct ports_device {
-       /* Next portdev in the list, head is in the pdrvdata struct */
-       struct list_head list;
-
-       /*
-        * Workqueue handlers where we process deferred work after
-        * notification
-        */
-       struct work_struct control_work;
-
-       struct list_head ports;
-
-       /* To protect the list of ports */
-       spinlock_t ports_lock;
-
-       /* To protect the vq operations for the control channel */
-       spinlock_t cvq_lock;
-
-       /* The current config space is stored here */
-       struct virtio_console_config config;
-
-       /* The virtio device we're associated with */
-       struct virtio_device *vdev;
-
-       /*
-        * A couple of virtqueues for the control channel: one for
-        * guest->host transfers, one for host->guest transfers
-        */
-       struct virtqueue *c_ivq, *c_ovq;
-
-       /* Array of per-port IO virtqueues */
-       struct virtqueue **in_vqs, **out_vqs;
-
-       /* Used for numbering devices for sysfs and debugfs */
-       unsigned int drv_index;
-
-       /* Major number for this device.  Ports will be created as minors. */
-       int chr_major;
-};
-
-/* This struct holds the per-port data */
-struct port {
-       /* Next port in the list, head is in the ports_device */
-       struct list_head list;
-
-       /* Pointer to the parent virtio_console device */
-       struct ports_device *portdev;
-
-       /* The current buffer from which data has to be fed to readers */
-       struct port_buffer *inbuf;
-
-       /*
-        * To protect the operations on the in_vq associated with this
-        * port.  Has to be a spinlock because it can be called from
-        * interrupt context (get_char()).
-        */
-       spinlock_t inbuf_lock;
-
-       /* Protect the operations on the out_vq. */
-       spinlock_t outvq_lock;
-
-       /* The IO vqs for this port */
-       struct virtqueue *in_vq, *out_vq;
-
-       /* File in the debugfs directory that exposes this port's information */
-       struct dentry *debugfs_file;
-
-       /*
-        * The entries in this struct will be valid if this port is
-        * hooked up to an hvc console
-        */
-       struct console cons;
-
-       /* Each port associates with a separate char device */
-       struct cdev *cdev;
-       struct device *dev;
-
-       /* Reference-counting to handle port hot-unplugs and file operations */
-       struct kref kref;
-
-       /* A waitqueue for poll() or blocking read operations */
-       wait_queue_head_t waitqueue;
-
-       /* The 'name' of the port that we expose via sysfs properties */
-       char *name;
-
-       /* We can notify apps of host connect / disconnect events via SIGIO */
-       struct fasync_struct *async_queue;
-
-       /* The 'id' to identify the port with the Host */
-       u32 id;
-
-       bool outvq_full;
-
-       /* Is the host device open */
-       bool host_connected;
-
-       /* We should allow only one process to open a port */
-       bool guest_connected;
-};
-
-/* This is the very early arch-specified put chars function. */
-static int (*early_put_chars)(u32, const char *, int);
-
-static struct port *find_port_by_vtermno(u32 vtermno)
-{
-       struct port *port;
-       struct console *cons;
-       unsigned long flags;
-
-       spin_lock_irqsave(&pdrvdata_lock, flags);
-       list_for_each_entry(cons, &pdrvdata.consoles, list) {
-               if (cons->vtermno == vtermno) {
-                       port = container_of(cons, struct port, cons);
-                       goto out;
-               }
-       }
-       port = NULL;
-out:
-       spin_unlock_irqrestore(&pdrvdata_lock, flags);
-       return port;
-}
-
-static struct port *find_port_by_devt_in_portdev(struct ports_device *portdev,
-                                                dev_t dev)
-{
-       struct port *port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&portdev->ports_lock, flags);
-       list_for_each_entry(port, &portdev->ports, list)
-               if (port->cdev->dev == dev)
-                       goto out;
-       port = NULL;
-out:
-       spin_unlock_irqrestore(&portdev->ports_lock, flags);
-
-       return port;
-}
-
-static struct port *find_port_by_devt(dev_t dev)
-{
-       struct ports_device *portdev;
-       struct port *port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&pdrvdata_lock, flags);
-       list_for_each_entry(portdev, &pdrvdata.portdevs, list) {
-               port = find_port_by_devt_in_portdev(portdev, dev);
-               if (port)
-                       goto out;
-       }
-       port = NULL;
-out:
-       spin_unlock_irqrestore(&pdrvdata_lock, flags);
-       return port;
-}
-
-static struct port *find_port_by_id(struct ports_device *portdev, u32 id)
-{
-       struct port *port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&portdev->ports_lock, flags);
-       list_for_each_entry(port, &portdev->ports, list)
-               if (port->id == id)
-                       goto out;
-       port = NULL;
-out:
-       spin_unlock_irqrestore(&portdev->ports_lock, flags);
-
-       return port;
-}
-
-static struct port *find_port_by_vq(struct ports_device *portdev,
-                                   struct virtqueue *vq)
-{
-       struct port *port;
-       unsigned long flags;
-
-       spin_lock_irqsave(&portdev->ports_lock, flags);
-       list_for_each_entry(port, &portdev->ports, list)
-               if (port->in_vq == vq || port->out_vq == vq)
-                       goto out;
-       port = NULL;
-out:
-       spin_unlock_irqrestore(&portdev->ports_lock, flags);
-       return port;
-}
-
-static bool is_console_port(struct port *port)
-{
-       if (port->cons.hvc)
-               return true;
-       return false;
-}
-
-static inline bool use_multiport(struct ports_device *portdev)
-{
-       /*
-        * This condition can be true when put_chars is called from
-        * early_init
-        */
-       if (!portdev->vdev)
-               return 0;
-       return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
-}
-
-static void free_buf(struct port_buffer *buf)
-{
-       kfree(buf->buf);
-       kfree(buf);
-}
-
-static struct port_buffer *alloc_buf(size_t buf_size)
-{
-       struct port_buffer *buf;
-
-       buf = kmalloc(sizeof(*buf), GFP_KERNEL);
-       if (!buf)
-               goto fail;
-       buf->buf = kzalloc(buf_size, GFP_KERNEL);
-       if (!buf->buf)
-               goto free_buf;
-       buf->len = 0;
-       buf->offset = 0;
-       buf->size = buf_size;
-       return buf;
-
-free_buf:
-       kfree(buf);
-fail:
-       return NULL;
-}
-
-/* Callers should take appropriate locks */
-static void *get_inbuf(struct port *port)
-{
-       struct port_buffer *buf;
-       struct virtqueue *vq;
-       unsigned int len;
-
-       vq = port->in_vq;
-       buf = virtqueue_get_buf(vq, &len);
-       if (buf) {
-               buf->len = len;
-               buf->offset = 0;
-       }
-       return buf;
-}
-
-/*
- * Create a scatter-gather list representing our input buffer and put
- * it in the queue.
- *
- * Callers should take appropriate locks.
- */
-static int add_inbuf(struct virtqueue *vq, struct port_buffer *buf)
-{
-       struct scatterlist sg[1];
-       int ret;
-
-       sg_init_one(sg, buf->buf, buf->size);
-
-       ret = virtqueue_add_buf(vq, sg, 0, 1, buf);
-       virtqueue_kick(vq);
-       return ret;
-}
-
-/* Discard any unread data this port has. Callers lockers. */
-static void discard_port_data(struct port *port)
-{
-       struct port_buffer *buf;
-       struct virtqueue *vq;
-       unsigned int len;
-       int ret;
-
-       vq = port->in_vq;
-       if (port->inbuf)
-               buf = port->inbuf;
-       else
-               buf = virtqueue_get_buf(vq, &len);
-
-       ret = 0;
-       while (buf) {
-               if (add_inbuf(vq, buf) < 0) {
-                       ret++;
-                       free_buf(buf);
-               }
-               buf = virtqueue_get_buf(vq, &len);
-       }
-       port->inbuf = NULL;
-       if (ret)
-               dev_warn(port->dev, "Errors adding %d buffers back to vq\n",
-                        ret);
-}
-
-static bool port_has_data(struct port *port)
-{
-       unsigned long flags;
-       bool ret;
-
-       spin_lock_irqsave(&port->inbuf_lock, flags);
-       if (port->inbuf) {
-               ret = true;
-               goto out;
-       }
-       port->inbuf = get_inbuf(port);
-       if (port->inbuf) {
-               ret = true;
-               goto out;
-       }
-       ret = false;
-out:
-       spin_unlock_irqrestore(&port->inbuf_lock, flags);
-       return ret;
-}
-
-static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id,
-                                 unsigned int event, unsigned int value)
-{
-       struct scatterlist sg[1];
-       struct virtio_console_control cpkt;
-       struct virtqueue *vq;
-       unsigned int len;
-
-       if (!use_multiport(portdev))
-               return 0;
-
-       cpkt.id = port_id;
-       cpkt.event = event;
-       cpkt.value = value;
-
-       vq = portdev->c_ovq;
-
-       sg_init_one(sg, &cpkt, sizeof(cpkt));
-       if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt) >= 0) {
-               virtqueue_kick(vq);
-               while (!virtqueue_get_buf(vq, &len))
-                       cpu_relax();
-       }
-       return 0;
-}
-
-static ssize_t send_control_msg(struct port *port, unsigned int event,
-                               unsigned int value)
-{
-       /* Did the port get unplugged before userspace closed it? */
-       if (port->portdev)
-               return __send_control_msg(port->portdev, port->id, event, value);
-       return 0;
-}
-
-/* Callers must take the port->outvq_lock */
-static void reclaim_consumed_buffers(struct port *port)
-{
-       void *buf;
-       unsigned int len;
-
-       while ((buf = virtqueue_get_buf(port->out_vq, &len))) {
-               kfree(buf);
-               port->outvq_full = false;
-       }
-}
-
-static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
-                       bool nonblock)
-{
-       struct scatterlist sg[1];
-       struct virtqueue *out_vq;
-       ssize_t ret;
-       unsigned long flags;
-       unsigned int len;
-
-       out_vq = port->out_vq;
-
-       spin_lock_irqsave(&port->outvq_lock, flags);
-
-       reclaim_consumed_buffers(port);
-
-       sg_init_one(sg, in_buf, in_count);
-       ret = virtqueue_add_buf(out_vq, sg, 1, 0, in_buf);
-
-       /* Tell Host to go! */
-       virtqueue_kick(out_vq);
-
-       if (ret < 0) {
-               in_count = 0;
-               goto done;
-       }
-
-       if (ret == 0)
-               port->outvq_full = true;
-
-       if (nonblock)
-               goto done;
-
-       /*
-        * Wait till the host acknowledges it pushed out the data we
-        * sent.  This is done for data from the hvc_console; the tty
-        * operations are performed with spinlocks held so we can't
-        * sleep here.  An alternative would be to copy the data to a
-        * buffer and relax the spinning requirement.  The downside is
-        * we need to kmalloc a GFP_ATOMIC buffer each time the
-        * console driver writes something out.
-        */
-       while (!virtqueue_get_buf(out_vq, &len))
-               cpu_relax();
-done:
-       spin_unlock_irqrestore(&port->outvq_lock, flags);
-       /*
-        * We're expected to return the amount of data we wrote -- all
-        * of it
-        */
-       return in_count;
-}
-
-/*
- * Give out the data that's requested from the buffer that we have
- * queued up.
- */
-static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count,
-                           bool to_user)
-{
-       struct port_buffer *buf;
-       unsigned long flags;
-
-       if (!out_count || !port_has_data(port))
-               return 0;
-
-       buf = port->inbuf;
-       out_count = min(out_count, buf->len - buf->offset);
-
-       if (to_user) {
-               ssize_t ret;
-
-               ret = copy_to_user(out_buf, buf->buf + buf->offset, out_count);
-               if (ret)
-                       return -EFAULT;
-       } else {
-               memcpy(out_buf, buf->buf + buf->offset, out_count);
-       }
-
-       buf->offset += out_count;
-
-       if (buf->offset == buf->len) {
-               /*
-                * We're done using all the data in this buffer.
-                * Re-queue so that the Host can send us more data.
-                */
-               spin_lock_irqsave(&port->inbuf_lock, flags);
-               port->inbuf = NULL;
-
-               if (add_inbuf(port->in_vq, buf) < 0)
-                       dev_warn(port->dev, "failed add_buf\n");
-
-               spin_unlock_irqrestore(&port->inbuf_lock, flags);
-       }
-       /* Return the number of bytes actually copied */
-       return out_count;
-}
-
-/* The condition that must be true for polling to end */
-static bool will_read_block(struct port *port)
-{
-       if (!port->guest_connected) {
-               /* Port got hot-unplugged. Let's exit. */
-               return false;
-       }
-       return !port_has_data(port) && port->host_connected;
-}
-
-static bool will_write_block(struct port *port)
-{
-       bool ret;
-
-       if (!port->guest_connected) {
-               /* Port got hot-unplugged. Let's exit. */
-               return false;
-       }
-       if (!port->host_connected)
-               return true;
-
-       spin_lock_irq(&port->outvq_lock);
-       /*
-        * Check if the Host has consumed any buffers since we last
-        * sent data (this is only applicable for nonblocking ports).
-        */
-       reclaim_consumed_buffers(port);
-       ret = port->outvq_full;
-       spin_unlock_irq(&port->outvq_lock);
-
-       return ret;
-}
-
-static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
-                             size_t count, loff_t *offp)
-{
-       struct port *port;
-       ssize_t ret;
-
-       port = filp->private_data;
-
-       if (!port_has_data(port)) {
-               /*
-                * If nothing's connected on the host just return 0 in
-                * case of list_empty; this tells the userspace app
-                * that there's no connection
-                */
-               if (!port->host_connected)
-                       return 0;
-               if (filp->f_flags & O_NONBLOCK)
-                       return -EAGAIN;
-
-               ret = wait_event_interruptible(port->waitqueue,
-                                              !will_read_block(port));
-               if (ret < 0)
-                       return ret;
-       }
-       /* Port got hot-unplugged. */
-       if (!port->guest_connected)
-               return -ENODEV;
-       /*
-        * We could've received a disconnection message while we were
-        * waiting for more data.
-        *
-        * This check is not clubbed in the if() statement above as we
-        * might receive some data as well as the host could get
-        * disconnected after we got woken up from our wait.  So we
-        * really want to give off whatever data we have and only then
-        * check for host_connected.
-        */
-       if (!port_has_data(port) && !port->host_connected)
-               return 0;
-
-       return fill_readbuf(port, ubuf, count, true);
-}
-
-static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
-                              size_t count, loff_t *offp)
-{
-       struct port *port;
-       char *buf;
-       ssize_t ret;
-       bool nonblock;
-
-       /* Userspace could be out to fool us */
-       if (!count)
-               return 0;
-
-       port = filp->private_data;
-
-       nonblock = filp->f_flags & O_NONBLOCK;
-
-       if (will_write_block(port)) {
-               if (nonblock)
-                       return -EAGAIN;
-
-               ret = wait_event_interruptible(port->waitqueue,
-                                              !will_write_block(port));
-               if (ret < 0)
-                       return ret;
-       }
-       /* Port got hot-unplugged. */
-       if (!port->guest_connected)
-               return -ENODEV;
-
-       count = min((size_t)(32 * 1024), count);
-
-       buf = kmalloc(count, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       ret = copy_from_user(buf, ubuf, count);
-       if (ret) {
-               ret = -EFAULT;
-               goto free_buf;
-       }
-
-       /*
-        * We now ask send_buf() to not spin for generic ports -- we
-        * can re-use the same code path that non-blocking file
-        * descriptors take for blocking file descriptors since the
-        * wait is already done and we're certain the write will go
-        * through to the host.
-        */
-       nonblock = true;
-       ret = send_buf(port, buf, count, nonblock);
-
-       if (nonblock && ret > 0)
-               goto out;
-
-free_buf:
-       kfree(buf);
-out:
-       return ret;
-}
-
-static unsigned int port_fops_poll(struct file *filp, poll_table *wait)
-{
-       struct port *port;
-       unsigned int ret;
-
-       port = filp->private_data;
-       poll_wait(filp, &port->waitqueue, wait);
-
-       if (!port->guest_connected) {
-               /* Port got unplugged */
-               return POLLHUP;
-       }
-       ret = 0;
-       if (!will_read_block(port))
-               ret |= POLLIN | POLLRDNORM;
-       if (!will_write_block(port))
-               ret |= POLLOUT;
-       if (!port->host_connected)
-               ret |= POLLHUP;
-
-       return ret;
-}
-
-static void remove_port(struct kref *kref);
-
-static int port_fops_release(struct inode *inode, struct file *filp)
-{
-       struct port *port;
-
-       port = filp->private_data;
-
-       /* Notify host of port being closed */
-       send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
-
-       spin_lock_irq(&port->inbuf_lock);
-       port->guest_connected = false;
-
-       discard_port_data(port);
-
-       spin_unlock_irq(&port->inbuf_lock);
-
-       spin_lock_irq(&port->outvq_lock);
-       reclaim_consumed_buffers(port);
-       spin_unlock_irq(&port->outvq_lock);
-
-       /*
-        * Locks aren't necessary here as a port can't be opened after
-        * unplug, and if a port isn't unplugged, a kref would already
-        * exist for the port.  Plus, taking ports_lock here would
-        * create a dependency on other locks taken by functions
-        * inside remove_port if we're the last holder of the port,
-        * creating many problems.
-        */
-       kref_put(&port->kref, remove_port);
-
-       return 0;
-}
-
-static int port_fops_open(struct inode *inode, struct file *filp)
-{
-       struct cdev *cdev = inode->i_cdev;
-       struct port *port;
-       int ret;
-
-       port = find_port_by_devt(cdev->dev);
-       filp->private_data = port;
-
-       /* Prevent against a port getting hot-unplugged at the same time */
-       spin_lock_irq(&port->portdev->ports_lock);
-       kref_get(&port->kref);
-       spin_unlock_irq(&port->portdev->ports_lock);
-
-       /*
-        * Don't allow opening of console port devices -- that's done
-        * via /dev/hvc
-        */
-       if (is_console_port(port)) {
-               ret = -ENXIO;
-               goto out;
-       }
-
-       /* Allow only one process to open a particular port at a time */
-       spin_lock_irq(&port->inbuf_lock);
-       if (port->guest_connected) {
-               spin_unlock_irq(&port->inbuf_lock);
-               ret = -EMFILE;
-               goto out;
-       }
-
-       port->guest_connected = true;
-       spin_unlock_irq(&port->inbuf_lock);
-
-       spin_lock_irq(&port->outvq_lock);
-       /*
-        * There might be a chance that we missed reclaiming a few
-        * buffers in the window of the port getting previously closed
-        * and opening now.
-        */
-       reclaim_consumed_buffers(port);
-       spin_unlock_irq(&port->outvq_lock);
-
-       nonseekable_open(inode, filp);
-
-       /* Notify host of port being opened */
-       send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1);
-
-       return 0;
-out:
-       kref_put(&port->kref, remove_port);
-       return ret;
-}
-
-static int port_fops_fasync(int fd, struct file *filp, int mode)
-{
-       struct port *port;
-
-       port = filp->private_data;
-       return fasync_helper(fd, filp, mode, &port->async_queue);
-}
-
-/*
- * The file operations that we support: programs in the guest can open
- * a console device, read from it, write to it, poll for data and
- * close it.  The devices are at
- *   /dev/vport<device number>p<port number>
- */
-static const struct file_operations port_fops = {
-       .owner = THIS_MODULE,
-       .open  = port_fops_open,
-       .read  = port_fops_read,
-       .write = port_fops_write,
-       .poll  = port_fops_poll,
-       .release = port_fops_release,
-       .fasync = port_fops_fasync,
-       .llseek = no_llseek,
-};
-
-/*
- * The put_chars() callback is pretty straightforward.
- *
- * We turn the characters into a scatter-gather list, add it to the
- * output queue and then kick the Host.  Then we sit here waiting for
- * it to finish: inefficient in theory, but in practice
- * implementations will do it immediately (lguest's Launcher does).
- */
-static int put_chars(u32 vtermno, const char *buf, int count)
-{
-       struct port *port;
-
-       if (unlikely(early_put_chars))
-               return early_put_chars(vtermno, buf, count);
-
-       port = find_port_by_vtermno(vtermno);
-       if (!port)
-               return -EPIPE;
-
-       return send_buf(port, (void *)buf, count, false);
-}
-
-/*
- * get_chars() is the callback from the hvc_console infrastructure
- * when an interrupt is received.
- *
- * We call out to fill_readbuf that gets us the required data from the
- * buffers that are queued up.
- */
-static int get_chars(u32 vtermno, char *buf, int count)
-{
-       struct port *port;
-
-       /* If we've not set up the port yet, we have no input to give. */
-       if (unlikely(early_put_chars))
-               return 0;
-
-       port = find_port_by_vtermno(vtermno);
-       if (!port)
-               return -EPIPE;
-
-       /* If we don't have an input queue yet, we can't get input. */
-       BUG_ON(!port->in_vq);
-
-       return fill_readbuf(port, buf, count, false);
-}
-
-static void resize_console(struct port *port)
-{
-       struct virtio_device *vdev;
-
-       /* The port could have been hot-unplugged */
-       if (!port || !is_console_port(port))
-               return;
-
-       vdev = port->portdev->vdev;
-       if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE))
-               hvc_resize(port->cons.hvc, port->cons.ws);
-}
-
-/* We set the configuration at this point, since we now have a tty */
-static int notifier_add_vio(struct hvc_struct *hp, int data)
-{
-       struct port *port;
-
-       port = find_port_by_vtermno(hp->vtermno);
-       if (!port)
-               return -EINVAL;
-
-       hp->irq_requested = 1;
-       resize_console(port);
-
-       return 0;
-}
-
-static void notifier_del_vio(struct hvc_struct *hp, int data)
-{
-       hp->irq_requested = 0;
-}
-
-/* The operations for console ports. */
-static const struct hv_ops hv_ops = {
-       .get_chars = get_chars,
-       .put_chars = put_chars,
-       .notifier_add = notifier_add_vio,
-       .notifier_del = notifier_del_vio,
-       .notifier_hangup = notifier_del_vio,
-};
-
-/*
- * Console drivers are initialized very early so boot messages can go
- * out, so we do things slightly differently from the generic virtio
- * initialization of the net and block drivers.
- *
- * At this stage, the console is output-only.  It's too early to set
- * up a virtqueue, so we let the drivers do some boutique early-output
- * thing.
- */
-int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int))
-{
-       early_put_chars = put_chars;
-       return hvc_instantiate(0, 0, &hv_ops);
-}
-
-int init_port_console(struct port *port)
-{
-       int ret;
-
-       /*
-        * The Host's telling us this port is a console port.  Hook it
-        * up with an hvc console.
-        *
-        * To set up and manage our virtual console, we call
-        * hvc_alloc().
-        *
-        * The first argument of hvc_alloc() is the virtual console
-        * number.  The second argument is the parameter for the
-        * notification mechanism (like irq number).  We currently
-        * leave this as zero, virtqueues have implicit notifications.
-        *
-        * The third argument is a "struct hv_ops" containing the
-        * put_chars() get_chars(), notifier_add() and notifier_del()
-        * pointers.  The final argument is the output buffer size: we
-        * can do any size, so we put PAGE_SIZE here.
-        */
-       port->cons.vtermno = pdrvdata.next_vtermno;
-
-       port->cons.hvc = hvc_alloc(port->cons.vtermno, 0, &hv_ops, PAGE_SIZE);
-       if (IS_ERR(port->cons.hvc)) {
-               ret = PTR_ERR(port->cons.hvc);
-               dev_err(port->dev,
-                       "error %d allocating hvc for port\n", ret);
-               port->cons.hvc = NULL;
-               return ret;
-       }
-       spin_lock_irq(&pdrvdata_lock);
-       pdrvdata.next_vtermno++;
-       list_add_tail(&port->cons.list, &pdrvdata.consoles);
-       spin_unlock_irq(&pdrvdata_lock);
-       port->guest_connected = true;
-
-       /*
-        * Start using the new console output if this is the first
-        * console to come up.
-        */
-       if (early_put_chars)
-               early_put_chars = NULL;
-
-       /* Notify host of port being opened */
-       send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
-
-       return 0;
-}
-
-static ssize_t show_port_name(struct device *dev,
-                             struct device_attribute *attr, char *buffer)
-{
-       struct port *port;
-
-       port = dev_get_drvdata(dev);
-
-       return sprintf(buffer, "%s\n", port->name);
-}
-
-static DEVICE_ATTR(name, S_IRUGO, show_port_name, NULL);
-
-static struct attribute *port_sysfs_entries[] = {
-       &dev_attr_name.attr,
-       NULL
-};
-
-static struct attribute_group port_attribute_group = {
-       .name = NULL,           /* put in device directory */
-       .attrs = port_sysfs_entries,
-};
-
-static int debugfs_open(struct inode *inode, struct file *filp)
-{
-       filp->private_data = inode->i_private;
-       return 0;
-}
-
-static ssize_t debugfs_read(struct file *filp, char __user *ubuf,
-                           size_t count, loff_t *offp)
-{
-       struct port *port;
-       char *buf;
-       ssize_t ret, out_offset, out_count;
-
-       out_count = 1024;
-       buf = kmalloc(out_count, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       port = filp->private_data;
-       out_offset = 0;
-       out_offset += snprintf(buf + out_offset, out_count,
-                              "name: %s\n", port->name ? port->name : "");
-       out_offset += snprintf(buf + out_offset, out_count - out_offset,
-                              "guest_connected: %d\n", port->guest_connected);
-       out_offset += snprintf(buf + out_offset, out_count - out_offset,
-                              "host_connected: %d\n", port->host_connected);
-       out_offset += snprintf(buf + out_offset, out_count - out_offset,
-                              "outvq_full: %d\n", port->outvq_full);
-       out_offset += snprintf(buf + out_offset, out_count - out_offset,
-                              "is_console: %s\n",
-                              is_console_port(port) ? "yes" : "no");
-       out_offset += snprintf(buf + out_offset, out_count - out_offset,
-                              "console_vtermno: %u\n", port->cons.vtermno);
-
-       ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset);
-       kfree(buf);
-       return ret;
-}
-
-static const struct file_operations port_debugfs_ops = {
-       .owner = THIS_MODULE,
-       .open  = debugfs_open,
-       .read  = debugfs_read,
-};
-
-static void set_console_size(struct port *port, u16 rows, u16 cols)
-{
-       if (!port || !is_console_port(port))
-               return;
-
-       port->cons.ws.ws_row = rows;
-       port->cons.ws.ws_col = cols;
-}
-
-static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock)
-{
-       struct port_buffer *buf;
-       unsigned int nr_added_bufs;
-       int ret;
-
-       nr_added_bufs = 0;
-       do {
-               buf = alloc_buf(PAGE_SIZE);
-               if (!buf)
-                       break;
-
-               spin_lock_irq(lock);
-               ret = add_inbuf(vq, buf);
-               if (ret < 0) {
-                       spin_unlock_irq(lock);
-                       free_buf(buf);
-                       break;
-               }
-               nr_added_bufs++;
-               spin_unlock_irq(lock);
-       } while (ret > 0);
-
-       return nr_added_bufs;
-}
-
-static void send_sigio_to_port(struct port *port)
-{
-       if (port->async_queue && port->guest_connected)
-               kill_fasync(&port->async_queue, SIGIO, POLL_OUT);
-}
-
-static int add_port(struct ports_device *portdev, u32 id)
-{
-       char debugfs_name[16];
-       struct port *port;
-       struct port_buffer *buf;
-       dev_t devt;
-       unsigned int nr_added_bufs;
-       int err;
-
-       port = kmalloc(sizeof(*port), GFP_KERNEL);
-       if (!port) {
-               err = -ENOMEM;
-               goto fail;
-       }
-       kref_init(&port->kref);
-
-       port->portdev = portdev;
-       port->id = id;
-
-       port->name = NULL;
-       port->inbuf = NULL;
-       port->cons.hvc = NULL;
-       port->async_queue = NULL;
-
-       port->cons.ws.ws_row = port->cons.ws.ws_col = 0;
-
-       port->host_connected = port->guest_connected = false;
-
-       port->outvq_full = false;
-
-       port->in_vq = portdev->in_vqs[port->id];
-       port->out_vq = portdev->out_vqs[port->id];
-
-       port->cdev = cdev_alloc();
-       if (!port->cdev) {
-               dev_err(&port->portdev->vdev->dev, "Error allocating cdev\n");
-               err = -ENOMEM;
-               goto free_port;
-       }
-       port->cdev->ops = &port_fops;
-
-       devt = MKDEV(portdev->chr_major, id);
-       err = cdev_add(port->cdev, devt, 1);
-       if (err < 0) {
-               dev_err(&port->portdev->vdev->dev,
-                       "Error %d adding cdev for port %u\n", err, id);
-               goto free_cdev;
-       }
-       port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev,
-                                 devt, port, "vport%up%u",
-                                 port->portdev->drv_index, id);
-       if (IS_ERR(port->dev)) {
-               err = PTR_ERR(port->dev);
-               dev_err(&port->portdev->vdev->dev,
-                       "Error %d creating device for port %u\n",
-                       err, id);
-               goto free_cdev;
-       }
-
-       spin_lock_init(&port->inbuf_lock);
-       spin_lock_init(&port->outvq_lock);
-       init_waitqueue_head(&port->waitqueue);
-
-       /* Fill the in_vq with buffers so the host can send us data. */
-       nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock);
-       if (!nr_added_bufs) {
-               dev_err(port->dev, "Error allocating inbufs\n");
-               err = -ENOMEM;
-               goto free_device;
-       }
-
-       /*
-        * If we're not using multiport support, this has to be a console port
-        */
-       if (!use_multiport(port->portdev)) {
-               err = init_port_console(port);
-               if (err)
-                       goto free_inbufs;
-       }
-
-       spin_lock_irq(&portdev->ports_lock);
-       list_add_tail(&port->list, &port->portdev->ports);
-       spin_unlock_irq(&portdev->ports_lock);
-
-       /*
-        * Tell the Host we're set so that it can send us various
-        * configuration parameters for this port (eg, port name,
-        * caching, whether this is a console port, etc.)
-        */
-       send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
-
-       if (pdrvdata.debugfs_dir) {
-               /*
-                * Finally, create the debugfs file that we can use to
-                * inspect a port's state at any time
-                */
-               sprintf(debugfs_name, "vport%up%u",
-                       port->portdev->drv_index, id);
-               port->debugfs_file = debugfs_create_file(debugfs_name, 0444,
-                                                        pdrvdata.debugfs_dir,
-                                                        port,
-                                                        &port_debugfs_ops);
-       }
-       return 0;
-
-free_inbufs:
-       while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
-               free_buf(buf);
-free_device:
-       device_destroy(pdrvdata.class, port->dev->devt);
-free_cdev:
-       cdev_del(port->cdev);
-free_port:
-       kfree(port);
-fail:
-       /* The host might want to notify management sw about port add failure */
-       __send_control_msg(portdev, id, VIRTIO_CONSOLE_PORT_READY, 0);
-       return err;
-}
-
-/* No users remain, remove all port-specific data. */
-static void remove_port(struct kref *kref)
-{
-       struct port *port;
-
-       port = container_of(kref, struct port, kref);
-
-       sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
-       device_destroy(pdrvdata.class, port->dev->devt);
-       cdev_del(port->cdev);
-
-       kfree(port->name);
-
-       debugfs_remove(port->debugfs_file);
-
-       kfree(port);
-}
-
-/*
- * Port got unplugged.  Remove port from portdev's list and drop the
- * kref reference.  If no userspace has this port opened, it will
- * result in immediate removal the port.
- */
-static void unplug_port(struct port *port)
-{
-       struct port_buffer *buf;
-
-       spin_lock_irq(&port->portdev->ports_lock);
-       list_del(&port->list);
-       spin_unlock_irq(&port->portdev->ports_lock);
-
-       if (port->guest_connected) {
-               port->guest_connected = false;
-               port->host_connected = false;
-               wake_up_interruptible(&port->waitqueue);
-
-               /* Let the app know the port is going down. */
-               send_sigio_to_port(port);
-       }
-
-       if (is_console_port(port)) {
-               spin_lock_irq(&pdrvdata_lock);
-               list_del(&port->cons.list);
-               spin_unlock_irq(&pdrvdata_lock);
-#if 0
-               /*
-                * hvc_remove() not called as removing one hvc port
-                * results in other hvc ports getting frozen.
-                *
-                * Once this is resolved in hvc, this functionality
-                * will be enabled.  Till that is done, the -EPIPE
-                * return from get_chars() above will help
-                * hvc_console.c to clean up on ports we remove here.
-                */
-               hvc_remove(port->cons.hvc);
-#endif
-       }
-
-       /* Remove unused data this port might have received. */
-       discard_port_data(port);
-
-       reclaim_consumed_buffers(port);
-
-       /* Remove buffers we queued up for the Host to send us data in. */
-       while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
-               free_buf(buf);
-
-       /*
-        * We should just assume the device itself has gone off --
-        * else a close on an open port later will try to send out a
-        * control message.
-        */
-       port->portdev = NULL;
-
-       /*
-        * Locks around here are not necessary - a port can't be
-        * opened after we removed the port struct from ports_list
-        * above.
-        */
-       kref_put(&port->kref, remove_port);
-}
-
-/* Any private messages that the Host and Guest want to share */
-static void handle_control_message(struct ports_device *portdev,
-                                  struct port_buffer *buf)
-{
-       struct virtio_console_control *cpkt;
-       struct port *port;
-       size_t name_size;
-       int err;
-
-       cpkt = (struct virtio_console_control *)(buf->buf + buf->offset);
-
-       port = find_port_by_id(portdev, cpkt->id);
-       if (!port && cpkt->event != VIRTIO_CONSOLE_PORT_ADD) {
-               /* No valid header at start of buffer.  Drop it. */
-               dev_dbg(&portdev->vdev->dev,
-                       "Invalid index %u in control packet\n", cpkt->id);
-               return;
-       }
-
-       switch (cpkt->event) {
-       case VIRTIO_CONSOLE_PORT_ADD:
-               if (port) {
-                       dev_dbg(&portdev->vdev->dev,
-                               "Port %u already added\n", port->id);
-                       send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
-                       break;
-               }
-               if (cpkt->id >= portdev->config.max_nr_ports) {
-                       dev_warn(&portdev->vdev->dev,
-                               "Request for adding port with out-of-bound id %u, max. supported id: %u\n",
-                               cpkt->id, portdev->config.max_nr_ports - 1);
-                       break;
-               }
-               add_port(portdev, cpkt->id);
-               break;
-       case VIRTIO_CONSOLE_PORT_REMOVE:
-               unplug_port(port);
-               break;
-       case VIRTIO_CONSOLE_CONSOLE_PORT:
-               if (!cpkt->value)
-                       break;
-               if (is_console_port(port))
-                       break;
-
-               init_port_console(port);
-               /*
-                * Could remove the port here in case init fails - but
-                * have to notify the host first.
-                */
-               break;
-       case VIRTIO_CONSOLE_RESIZE: {
-               struct {
-                       __u16 rows;
-                       __u16 cols;
-               } size;
-
-               if (!is_console_port(port))
-                       break;
-
-               memcpy(&size, buf->buf + buf->offset + sizeof(*cpkt),
-                      sizeof(size));
-               set_console_size(port, size.rows, size.cols);
-
-               port->cons.hvc->irq_requested = 1;
-               resize_console(port);
-               break;
-       }
-       case VIRTIO_CONSOLE_PORT_OPEN:
-               port->host_connected = cpkt->value;
-               wake_up_interruptible(&port->waitqueue);
-               /*
-                * If the host port got closed and the host had any
-                * unconsumed buffers, we'll be able to reclaim them
-                * now.
-                */
-               spin_lock_irq(&port->outvq_lock);
-               reclaim_consumed_buffers(port);
-               spin_unlock_irq(&port->outvq_lock);
-
-               /*
-                * If the guest is connected, it'll be interested in
-                * knowing the host connection state changed.
-                */
-               send_sigio_to_port(port);
-               break;
-       case VIRTIO_CONSOLE_PORT_NAME:
-               /*
-                * Skip the size of the header and the cpkt to get the size
-                * of the name that was sent
-                */
-               name_size = buf->len - buf->offset - sizeof(*cpkt) + 1;
-
-               port->name = kmalloc(name_size, GFP_KERNEL);
-               if (!port->name) {
-                       dev_err(port->dev,
-                               "Not enough space to store port name\n");
-                       break;
-               }
-               strncpy(port->name, buf->buf + buf->offset + sizeof(*cpkt),
-                       name_size - 1);
-               port->name[name_size - 1] = 0;
-
-               /*
-                * Since we only have one sysfs attribute, 'name',
-                * create it only if we have a name for the port.
-                */
-               err = sysfs_create_group(&port->dev->kobj,
-                                        &port_attribute_group);
-               if (err) {
-                       dev_err(port->dev,
-                               "Error %d creating sysfs device attributes\n",
-                               err);
-               } else {
-                       /*
-                        * Generate a udev event so that appropriate
-                        * symlinks can be created based on udev
-                        * rules.
-                        */
-                       kobject_uevent(&port->dev->kobj, KOBJ_CHANGE);
-               }
-               break;
-       }
-}
-
-static void control_work_handler(struct work_struct *work)
-{
-       struct ports_device *portdev;
-       struct virtqueue *vq;
-       struct port_buffer *buf;
-       unsigned int len;
-
-       portdev = container_of(work, struct ports_device, control_work);
-       vq = portdev->c_ivq;
-
-       spin_lock(&portdev->cvq_lock);
-       while ((buf = virtqueue_get_buf(vq, &len))) {
-               spin_unlock(&portdev->cvq_lock);
-
-               buf->len = len;
-               buf->offset = 0;
-
-               handle_control_message(portdev, buf);
-
-               spin_lock(&portdev->cvq_lock);
-               if (add_inbuf(portdev->c_ivq, buf) < 0) {
-                       dev_warn(&portdev->vdev->dev,
-                                "Error adding buffer to queue\n");
-                       free_buf(buf);
-               }
-       }
-       spin_unlock(&portdev->cvq_lock);
-}
-
-static void in_intr(struct virtqueue *vq)
-{
-       struct port *port;
-       unsigned long flags;
-
-       port = find_port_by_vq(vq->vdev->priv, vq);
-       if (!port)
-               return;
-
-       spin_lock_irqsave(&port->inbuf_lock, flags);
-       if (!port->inbuf)
-               port->inbuf = get_inbuf(port);
-
-       /*
-        * Don't queue up data when port is closed.  This condition
-        * can be reached when a console port is not yet connected (no
-        * tty is spawned) and the host sends out data to console
-        * ports.  For generic serial ports, the host won't
-        * (shouldn't) send data till the guest is connected.
-        */
-       if (!port->guest_connected)
-               discard_port_data(port);
-
-       spin_unlock_irqrestore(&port->inbuf_lock, flags);
-
-       wake_up_interruptible(&port->waitqueue);
-
-       /* Send a SIGIO indicating new data in case the process asked for it */
-       send_sigio_to_port(port);
-
-       if (is_console_port(port) && hvc_poll(port->cons.hvc))
-               hvc_kick();
-}
-
-static void control_intr(struct virtqueue *vq)
-{
-       struct ports_device *portdev;
-
-       portdev = vq->vdev->priv;
-       schedule_work(&portdev->control_work);
-}
-
-static void config_intr(struct virtio_device *vdev)
-{
-       struct ports_device *portdev;
-
-       portdev = vdev->priv;
-
-       if (!use_multiport(portdev)) {
-               struct port *port;
-               u16 rows, cols;
-
-               vdev->config->get(vdev,
-                                 offsetof(struct virtio_console_config, cols),
-                                 &cols, sizeof(u16));
-               vdev->config->get(vdev,
-                                 offsetof(struct virtio_console_config, rows),
-                                 &rows, sizeof(u16));
-
-               port = find_port_by_id(portdev, 0);
-               set_console_size(port, rows, cols);
-
-               /*
-                * We'll use this way of resizing only for legacy
-                * support.  For newer userspace
-                * (VIRTIO_CONSOLE_F_MULTPORT+), use control messages
-                * to indicate console size changes so that it can be
-                * done per-port.
-                */
-               resize_console(port);
-       }
-}
-
-static int init_vqs(struct ports_device *portdev)
-{
-       vq_callback_t **io_callbacks;
-       char **io_names;
-       struct virtqueue **vqs;
-       u32 i, j, nr_ports, nr_queues;
-       int err;
-
-       nr_ports = portdev->config.max_nr_ports;
-       nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2;
-
-       vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL);
-       io_callbacks = kmalloc(nr_queues * sizeof(vq_callback_t *), GFP_KERNEL);
-       io_names = kmalloc(nr_queues * sizeof(char *), GFP_KERNEL);
-       portdev->in_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
-                                 GFP_KERNEL);
-       portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
-                                  GFP_KERNEL);
-       if (!vqs || !io_callbacks || !io_names || !portdev->in_vqs ||
-                       !portdev->out_vqs) {
-               err = -ENOMEM;
-               goto free;
-       }
-
-       /*
-        * For backward compat (newer host but older guest), the host
-        * spawns a console port first and also inits the vqs for port
-        * 0 before others.
-        */
-       j = 0;
-       io_callbacks[j] = in_intr;
-       io_callbacks[j + 1] = NULL;
-       io_names[j] = "input";
-       io_names[j + 1] = "output";
-       j += 2;
-
-       if (use_multiport(portdev)) {
-               io_callbacks[j] = control_intr;
-               io_callbacks[j + 1] = NULL;
-               io_names[j] = "control-i";
-               io_names[j + 1] = "control-o";
-
-               for (i = 1; i < nr_ports; i++) {
-                       j += 2;
-                       io_callbacks[j] = in_intr;
-                       io_callbacks[j + 1] = NULL;
-                       io_names[j] = "input";
-                       io_names[j + 1] = "output";
-               }
-       }
-       /* Find the queues. */
-       err = portdev->vdev->config->find_vqs(portdev->vdev, nr_queues, vqs,
-                                             io_callbacks,
-                                             (const char **)io_names);
-       if (err)
-               goto free;
-
-       j = 0;
-       portdev->in_vqs[0] = vqs[0];
-       portdev->out_vqs[0] = vqs[1];
-       j += 2;
-       if (use_multiport(portdev)) {
-               portdev->c_ivq = vqs[j];
-               portdev->c_ovq = vqs[j + 1];
-
-               for (i = 1; i < nr_ports; i++) {
-                       j += 2;
-                       portdev->in_vqs[i] = vqs[j];
-                       portdev->out_vqs[i] = vqs[j + 1];
-               }
-       }
-       kfree(io_names);
-       kfree(io_callbacks);
-       kfree(vqs);
-
-       return 0;
-
-free:
-       kfree(portdev->out_vqs);
-       kfree(portdev->in_vqs);
-       kfree(io_names);
-       kfree(io_callbacks);
-       kfree(vqs);
-
-       return err;
-}
-
-static const struct file_operations portdev_fops = {
-       .owner = THIS_MODULE,
-};
-
-/*
- * Once we're further in boot, we get probed like any other virtio
- * device.
- *
- * If the host also supports multiple console ports, we check the
- * config space to see how many ports the host has spawned.  We
- * initialize each port found.
- */
-static int __devinit virtcons_probe(struct virtio_device *vdev)
-{
-       struct ports_device *portdev;
-       int err;
-       bool multiport;
-
-       portdev = kmalloc(sizeof(*portdev), GFP_KERNEL);
-       if (!portdev) {
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       /* Attach this portdev to this virtio_device, and vice-versa. */
-       portdev->vdev = vdev;
-       vdev->priv = portdev;
-
-       spin_lock_irq(&pdrvdata_lock);
-       portdev->drv_index = pdrvdata.index++;
-       spin_unlock_irq(&pdrvdata_lock);
-
-       portdev->chr_major = register_chrdev(0, "virtio-portsdev",
-                                            &portdev_fops);
-       if (portdev->chr_major < 0) {
-               dev_err(&vdev->dev,
-                       "Error %d registering chrdev for device %u\n",
-                       portdev->chr_major, portdev->drv_index);
-               err = portdev->chr_major;
-               goto free;
-       }
-
-       multiport = false;
-       portdev->config.max_nr_ports = 1;
-       if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT)) {
-               multiport = true;
-               vdev->features[0] |= 1 << VIRTIO_CONSOLE_F_MULTIPORT;
-
-               vdev->config->get(vdev, offsetof(struct virtio_console_config,
-                                                max_nr_ports),
-                                 &portdev->config.max_nr_ports,
-                                 sizeof(portdev->config.max_nr_ports));
-       }
-
-       /* Let the Host know we support multiple ports.*/
-       vdev->config->finalize_features(vdev);
-
-       err = init_vqs(portdev);
-       if (err < 0) {
-               dev_err(&vdev->dev, "Error %d initializing vqs\n", err);
-               goto free_chrdev;
-       }
-
-       spin_lock_init(&portdev->ports_lock);
-       INIT_LIST_HEAD(&portdev->ports);
-
-       if (multiport) {
-               unsigned int nr_added_bufs;
-
-               spin_lock_init(&portdev->cvq_lock);
-               INIT_WORK(&portdev->control_work, &control_work_handler);
-
-               nr_added_bufs = fill_queue(portdev->c_ivq, &portdev->cvq_lock);
-               if (!nr_added_bufs) {
-                       dev_err(&vdev->dev,
-                               "Error allocating buffers for control queue\n");
-                       err = -ENOMEM;
-                       goto free_vqs;
-               }
-       } else {
-               /*
-                * For backward compatibility: Create a console port
-                * if we're running on older host.
-                */
-               add_port(portdev, 0);
-       }
-
-       spin_lock_irq(&pdrvdata_lock);
-       list_add_tail(&portdev->list, &pdrvdata.portdevs);
-       spin_unlock_irq(&pdrvdata_lock);
-
-       __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
-                          VIRTIO_CONSOLE_DEVICE_READY, 1);
-       return 0;
-
-free_vqs:
-       /* The host might want to notify mgmt sw about device add failure */
-       __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
-                          VIRTIO_CONSOLE_DEVICE_READY, 0);
-       vdev->config->del_vqs(vdev);
-       kfree(portdev->in_vqs);
-       kfree(portdev->out_vqs);
-free_chrdev:
-       unregister_chrdev(portdev->chr_major, "virtio-portsdev");
-free:
-       kfree(portdev);
-fail:
-       return err;
-}
-
-static void virtcons_remove(struct virtio_device *vdev)
-{
-       struct ports_device *portdev;
-       struct port *port, *port2;
-
-       portdev = vdev->priv;
-
-       spin_lock_irq(&pdrvdata_lock);
-       list_del(&portdev->list);
-       spin_unlock_irq(&pdrvdata_lock);
-
-       /* Disable interrupts for vqs */
-       vdev->config->reset(vdev);
-       /* Finish up work that's lined up */
-       cancel_work_sync(&portdev->control_work);
-
-       list_for_each_entry_safe(port, port2, &portdev->ports, list)
-               unplug_port(port);
-
-       unregister_chrdev(portdev->chr_major, "virtio-portsdev");
-
-       /*
-        * When yanking out a device, we immediately lose the
-        * (device-side) queues.  So there's no point in keeping the
-        * guest side around till we drop our final reference.  This
-        * also means that any ports which are in an open state will
-        * have to just stop using the port, as the vqs are going
-        * away.
-        */
-       if (use_multiport(portdev)) {
-               struct port_buffer *buf;
-               unsigned int len;
-
-               while ((buf = virtqueue_get_buf(portdev->c_ivq, &len)))
-                       free_buf(buf);
-
-               while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq)))
-                       free_buf(buf);
-       }
-
-       vdev->config->del_vqs(vdev);
-       kfree(portdev->in_vqs);
-       kfree(portdev->out_vqs);
-
-       kfree(portdev);
-}
-
-static struct virtio_device_id id_table[] = {
-       { VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID },
-       { 0 },
-};
-
-static unsigned int features[] = {
-       VIRTIO_CONSOLE_F_SIZE,
-       VIRTIO_CONSOLE_F_MULTIPORT,
-};
-
-static struct virtio_driver virtio_console = {
-       .feature_table = features,
-       .feature_table_size = ARRAY_SIZE(features),
-       .driver.name =  KBUILD_MODNAME,
-       .driver.owner = THIS_MODULE,
-       .id_table =     id_table,
-       .probe =        virtcons_probe,
-       .remove =       virtcons_remove,
-       .config_changed = config_intr,
-};
-
-static int __init init(void)
-{
-       int err;
-
-       pdrvdata.class = class_create(THIS_MODULE, "virtio-ports");
-       if (IS_ERR(pdrvdata.class)) {
-               err = PTR_ERR(pdrvdata.class);
-               pr_err("Error %d creating virtio-ports class\n", err);
-               return err;
-       }
-
-       pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL);
-       if (!pdrvdata.debugfs_dir) {
-               pr_warning("Error %ld creating debugfs dir for virtio-ports\n",
-                          PTR_ERR(pdrvdata.debugfs_dir));
-       }
-       INIT_LIST_HEAD(&pdrvdata.consoles);
-       INIT_LIST_HEAD(&pdrvdata.portdevs);
-
-       return register_virtio_driver(&virtio_console);
-}
-
-static void __exit fini(void)
-{
-       unregister_virtio_driver(&virtio_console);
-
-       class_destroy(pdrvdata.class);
-       if (pdrvdata.debugfs_dir)
-               debugfs_remove_recursive(pdrvdata.debugfs_dir);
-}
-module_init(init);
-module_exit(fini);
-
-MODULE_DEVICE_TABLE(virtio, id_table);
-MODULE_DESCRIPTION("Virtio console driver");
-MODULE_LICENSE("GPL");
index 44b8412..aa2e5d3 100644 (file)
@@ -2414,6 +2414,7 @@ static int gsmld_config(struct tty_struct *tty, struct gsm_mux *gsm,
 
        gsm->initiator = c->initiator;
        gsm->mru = c->mru;
+       gsm->mtu = c->mtu;
        gsm->encoding = c->encapsulation;
        gsm->adaption = c->adaption;
        gsm->n2 = c->n2;
index 47d3228..52fc0c9 100644 (file)
@@ -581,8 +581,9 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
                           __u8 __user *buf, size_t nr)
 {
        struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
-       int ret;
+       int ret = 0;
        struct n_hdlc_buf *rbuf;
+       DECLARE_WAITQUEUE(wait, current);
 
        if (debuglevel >= DEBUG_LEVEL_INFO)     
                printk("%s(%d)n_hdlc_tty_read() called\n",__FILE__,__LINE__);
@@ -598,57 +599,55 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
                return -EFAULT;
        }
 
-       tty_lock();
+       add_wait_queue(&tty->read_wait, &wait);
 
        for (;;) {
                if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
-                       tty_unlock();
-                       return -EIO;
+                       ret = -EIO;
+                       break;
                }
+               if (tty_hung_up_p(file))
+                       break;
 
-               n_hdlc = tty2n_hdlc (tty);
-               if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC ||
-                        tty != n_hdlc->tty) {
-                       tty_unlock();
-                       return 0;
-               }
+               set_current_state(TASK_INTERRUPTIBLE);
 
                rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
-               if (rbuf)
+               if (rbuf) {
+                       if (rbuf->count > nr) {
+                               /* too large for caller's buffer */
+                               ret = -EOVERFLOW;
+                       } else {
+                               if (copy_to_user(buf, rbuf->buf, rbuf->count))
+                                       ret = -EFAULT;
+                               else
+                                       ret = rbuf->count;
+                       }
+
+                       if (n_hdlc->rx_free_buf_list.count >
+                           DEFAULT_RX_BUF_COUNT)
+                               kfree(rbuf);
+                       else
+                               n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, rbuf);
                        break;
+               }
                        
                /* no data */
                if (file->f_flags & O_NONBLOCK) {
-                       tty_unlock();
-                       return -EAGAIN;
+                       ret = -EAGAIN;
+                       break;
                }
-                       
-               interruptible_sleep_on (&tty->read_wait);
+
+               schedule();
+
                if (signal_pending(current)) {
-                       tty_unlock();
-                       return -EINTR;
+                       ret = -EINTR;
+                       break;
                }
        }
-               
-       if (rbuf->count > nr)
-               /* frame too large for caller's buffer (discard frame) */
-               ret = -EOVERFLOW;
-       else {
-               /* Copy the data to the caller's buffer */
-               if (copy_to_user(buf, rbuf->buf, rbuf->count))
-                       ret = -EFAULT;
-               else
-                       ret = rbuf->count;
-       }
-       
-       /* return HDLC buffer to free list unless the free list */
-       /* count has exceeded the default value, in which case the */
-       /* buffer is freed back to the OS to conserve memory */
-       if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT)
-               kfree(rbuf);
-       else    
-               n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf);
-       tty_unlock();
+
+       remove_wait_queue(&tty->read_wait, &wait);
+       __set_current_state(TASK_RUNNING);
+
        return ret;
        
 }      /* end of n_hdlc_tty_read() */
@@ -691,14 +690,15 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
                count = maxframe;
        }
        
-       tty_lock();
-
        add_wait_queue(&tty->write_wait, &wait);
-       set_current_state(TASK_INTERRUPTIBLE);
+
+       for (;;) {
+               set_current_state(TASK_INTERRUPTIBLE);
        
-       /* Allocate transmit buffer */
-       /* sleep until transmit buffer available */             
-       while (!(tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list))) {
+               tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list);
+               if (tbuf)
+                       break;
+
                if (file->f_flags & O_NONBLOCK) {
                        error = -EAGAIN;
                        break;
@@ -719,7 +719,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
                }
        }
 
-       set_current_state(TASK_RUNNING);
+       __set_current_state(TASK_RUNNING);
        remove_wait_queue(&tty->write_wait, &wait);
 
        if (!error) {           
@@ -731,7 +731,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
                n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf);
                n_hdlc_send_frames(n_hdlc,tty);
        }
-       tty_unlock();
+
        return error;
        
 }      /* end of n_hdlc_tty_write() */
index be0ebce..de0160e 100644 (file)
@@ -262,7 +262,7 @@ static void status_handle(struct m68k_serial *info, unsigned short status)
 
 static void receive_chars(struct m68k_serial *info, unsigned short rx)
 {
-       struct tty_struct *tty = info->port.tty;
+       struct tty_struct *tty = info->tty;
        m68328_uart *uart = &uart_addr[info->line];
        unsigned char ch, flag;
 
@@ -329,7 +329,7 @@ static void transmit_chars(struct m68k_serial *info)
                goto clear_and_return;
        }
 
-       if((info->xmit_cnt <= 0) || info->port.tty->stopped) {
+       if((info->xmit_cnt <= 0) || info->tty->stopped) {
                /* That's peculiar... TX ints off */
                uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
                goto clear_and_return;
@@ -383,7 +383,7 @@ static void do_softint(struct work_struct *work)
        struct m68k_serial      *info = container_of(work, struct m68k_serial, tqueue);
        struct tty_struct       *tty;
        
-       tty = info->port.tty;
+       tty = info->tty;
        if (!tty)
                return;
 #if 0
@@ -407,7 +407,7 @@ static void do_serial_hangup(struct work_struct *work)
        struct m68k_serial      *info = container_of(work, struct m68k_serial, tqueue_hangup);
        struct tty_struct       *tty;
        
-       tty = info->port.tty;
+       tty = info->tty;
        if (!tty)
                return;
 
@@ -451,8 +451,8 @@ static int startup(struct m68k_serial * info)
        uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK;
 #endif
 
-       if (info->port.tty)
-               clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
+       if (info->tty)
+               clear_bit(TTY_IO_ERROR, &info->tty->flags);
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 
        /*
@@ -486,8 +486,8 @@ static void shutdown(struct m68k_serial * info)
                info->xmit_buf = 0;
        }
 
-       if (info->port.tty)
-               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+       if (info->tty)
+               set_bit(TTY_IO_ERROR, &info->tty->flags);
        
        info->flags &= ~S_INITIALIZED;
        local_irq_restore(flags);
@@ -553,9 +553,9 @@ static void change_speed(struct m68k_serial *info)
        unsigned cflag;
        int     i;
 
-       if (!info->port.tty || !info->port.tty->termios)
+       if (!info->tty || !info->tty->termios)
                return;
-       cflag = info->port.tty->termios->c_cflag;
+       cflag = info->tty->termios->c_cflag;
        if (!(port = info->port))
                return;
 
@@ -970,7 +970,6 @@ static void send_break(struct m68k_serial * info, unsigned int duration)
 static int rs_ioctl(struct tty_struct *tty, struct file * file,
                    unsigned int cmd, unsigned long arg)
 {
-       int error;
        struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
        int retval;
 
@@ -1104,7 +1103,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
        tty_ldisc_flush(tty);
        tty->closing = 0;
        info->event = 0;
-       info->port.tty = NULL;
+       info->tty = NULL;
 #warning "This is not and has never been valid so fix it"      
 #if 0
        if (tty->ldisc.num != ldiscs[N_TTY].num) {
@@ -1142,7 +1141,7 @@ void rs_hangup(struct tty_struct *tty)
        info->event = 0;
        info->count = 0;
        info->flags &= ~S_NORMAL_ACTIVE;
-       info->port.tty = NULL;
+       info->tty = NULL;
        wake_up_interruptible(&info->open_wait);
 }
 
@@ -1261,7 +1260,7 @@ int rs_open(struct tty_struct *tty, struct file * filp)
 
        info->count++;
        tty->driver_data = info;
-       info->port.tty = tty;
+       info->tty = tty;
 
        /*
         * Start up serial port
@@ -1338,7 +1337,7 @@ rs68328_init(void)
            info = &m68k_soft[i];
            info->magic = SERIAL_MAGIC;
            info->port = (int) &uart_addr[i];
-           info->port.tty = NULL;
+           info->tty = NULL;
            info->irq = uart_irqs[i];
            info->custom_divisor = 16;
            info->close_delay = 50;
index 88b1335..bc21eea 100644 (file)
@@ -2428,6 +2428,7 @@ static const struct tty_operations rs_360_ops = {
        /* .read_proc = rs_360_read_proc, */
        .tiocmget = rs_360_tiocmget,
        .tiocmset = rs_360_tiocmset,
+       .get_icount = rs_360_get_icount,
 };
 
 static int __init rs_360_init(void)
index b25e6e4..3975df6 100644 (file)
@@ -236,7 +236,8 @@ static const struct serial8250_config uart_config[] = {
                .fifo_size      = 128,
                .tx_loadsz      = 128,
                .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
-               .flags          = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
+               /* UART_CAP_EFR breaks billionon CF bluetooth card. */
+               .flags          = UART_CAP_FIFO | UART_CAP_SLEEP,
        },
        [PORT_16654] = {
                .name           = "ST16654",
index b1682d7..2b83346 100644 (file)
@@ -1518,6 +1518,7 @@ config SERIAL_BCM63XX_CONSOLE
 config SERIAL_GRLIB_GAISLER_APBUART
        tristate "GRLIB APBUART serial support"
        depends on OF
+       select SERIAL_CORE
        ---help---
        Add support for the GRLIB APBUART serial port.
 
index e381b89..9b1ff2b 100644 (file)
@@ -370,10 +370,8 @@ static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id)
 {
        struct bfin_serial_port *uart = dev_id;
 
-       spin_lock(&uart->port.lock);
        while (UART_GET_LSR(uart) & DR)
                bfin_serial_rx_chars(uart);
-       spin_unlock(&uart->port.lock);
 
        return IRQ_HANDLED;
 }
@@ -490,9 +488,8 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
 {
        int x_pos, pos;
 
-       dma_disable_irq(uart->tx_dma_channel);
-       dma_disable_irq(uart->rx_dma_channel);
-       spin_lock_bh(&uart->port.lock);
+       dma_disable_irq_nosync(uart->rx_dma_channel);
+       spin_lock_bh(&uart->rx_lock);
 
        /* 2D DMA RX buffer ring is used. Because curr_y_count and
         * curr_x_count can't be read as an atomic operation,
@@ -523,8 +520,7 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
                uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
        }
 
-       spin_unlock_bh(&uart->port.lock);
-       dma_enable_irq(uart->tx_dma_channel);
+       spin_unlock_bh(&uart->rx_lock);
        dma_enable_irq(uart->rx_dma_channel);
 
        mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES);
@@ -571,7 +567,7 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
        unsigned short irqstat;
        int x_pos, pos;
 
-       spin_lock(&uart->port.lock);
+       spin_lock(&uart->rx_lock);
        irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);
        clear_dma_irqstat(uart->rx_dma_channel);
 
@@ -589,7 +585,7 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
                uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
        }
 
-       spin_unlock(&uart->port.lock);
+       spin_unlock(&uart->rx_lock);
 
        return IRQ_HANDLED;
 }
@@ -1332,6 +1328,7 @@ static int bfin_serial_probe(struct platform_device *pdev)
                }
 
 #ifdef CONFIG_SERIAL_BFIN_DMA
+               spin_lock_init(&uart->rx_lock);
                uart->tx_done       = 1;
                uart->tx_count      = 0;
 
index beb1afa..7b951ad 100644 (file)
@@ -601,7 +601,7 @@ static int max3100_startup(struct uart_port *port)
        s->rts = 0;
 
        sprintf(b, "max3100-%d", s->minor);
-       s->workqueue = create_freezeable_workqueue(b);
+       s->workqueue = create_freezable_workqueue(b);
        if (!s->workqueue) {
                dev_warn(&s->spi->dev, "cannot create workqueue\n");
                return -EBUSY;
index 910870e..750b4f6 100644 (file)
@@ -833,7 +833,7 @@ static int max3107_startup(struct uart_port *port)
        struct max3107_port *s = container_of(port, struct max3107_port, port);
 
        /* Initialize work queue */
-       s->workqueue = create_freezeable_workqueue("max3107");
+       s->workqueue = create_freezable_workqueue("max3107");
        if (!s->workqueue) {
                dev_err(&s->spi->dev, "Workqueue creation failed\n");
                return -EBUSY;
index a2f2b32..602d984 100644 (file)
@@ -829,7 +829,7 @@ static void __init sbd_probe_duarts(void)
 #ifdef CONFIG_SERIAL_SB1250_DUART_CONSOLE
 /*
  * Serial console stuff.  Very basic, polling driver for doing serial
- * console output.  The console_sem is held by the caller, so we
+ * console output.  The console_lock is held by the caller, so we
  * shouldn't be interrupted for more console activity.
  */
 static void sbd_console_putchar(struct uart_port *uport, int ch)
index 93760b2..1ef4df9 100644 (file)
@@ -712,6 +712,7 @@ static struct pcmcia_device_id serial_ids[] = {
        PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet+Modem II", 0x2e3ee845, 0xeca401bf),
        PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0e01),
        PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0a05),
+       PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0b05),
        PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x1101),
        PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0104, 0x0070),
        PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0101, 0x0562),
index c556ed9..81f1395 100644 (file)
@@ -46,7 +46,7 @@
 #include <asm/irq_regs.h>
 
 /* Whether we react on sysrq keys or just ignore them */
-static int __read_mostly sysrq_enabled = 1;
+static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE;
 static bool __read_mostly sysrq_always_enabled;
 
 static bool sysrq_on(void)
@@ -571,6 +571,7 @@ struct sysrq_state {
        unsigned int alt_use;
        bool active;
        bool need_reinject;
+       bool reinjecting;
 };
 
 static void sysrq_reinject_alt_sysrq(struct work_struct *work)
@@ -581,6 +582,10 @@ static void sysrq_reinject_alt_sysrq(struct work_struct *work)
        unsigned int alt_code = sysrq->alt_use;
 
        if (sysrq->need_reinject) {
+               /* we do not want the assignment to be reordered */
+               sysrq->reinjecting = true;
+               mb();
+
                /* Simulate press and release of Alt + SysRq */
                input_inject_event(handle, EV_KEY, alt_code, 1);
                input_inject_event(handle, EV_KEY, KEY_SYSRQ, 1);
@@ -589,6 +594,9 @@ static void sysrq_reinject_alt_sysrq(struct work_struct *work)
                input_inject_event(handle, EV_KEY, KEY_SYSRQ, 0);
                input_inject_event(handle, EV_KEY, alt_code, 0);
                input_inject_event(handle, EV_SYN, SYN_REPORT, 1);
+
+               mb();
+               sysrq->reinjecting = false;
        }
 }
 
@@ -599,6 +607,13 @@ static bool sysrq_filter(struct input_handle *handle,
        bool was_active = sysrq->active;
        bool suppress;
 
+       /*
+        * Do not filter anything if we are in the process of re-injecting
+        * Alt+SysRq combination.
+        */
+       if (sysrq->reinjecting)
+               return false;
+
        switch (type) {
 
        case EV_SYN:
@@ -629,7 +644,7 @@ static bool sysrq_filter(struct input_handle *handle,
                                sysrq->alt_use = sysrq->alt;
                                /*
                                 * If nothing else will be pressed we'll need
-                                * to re-inject Alt-SysRq keysroke.
+                                * to re-inject Alt-SysRq keysroke.
                                 */
                                sysrq->need_reinject = true;
                        }
index 464d09d..0065da4 100644 (file)
@@ -3256,8 +3256,8 @@ static ssize_t show_cons_active(struct device *dev,
        struct console *c;
        ssize_t count = 0;
 
-       acquire_console_sem();
-       for (c = console_drivers; c; c = c->next) {
+       console_lock();
+       for_each_console(c) {
                if (!c->device)
                        continue;
                if (!c->write)
@@ -3271,7 +3271,7 @@ static ssize_t show_cons_active(struct device *dev,
        while (i--)
                count += sprintf(buf + count, "%s%d%c",
                                 cs[i]->name, cs[i]->index, i ? ' ':'\n');
-       release_console_sem();
+       console_unlock();
 
        return count;
 }
@@ -3306,7 +3306,7 @@ int __init tty_init(void)
        if (IS_ERR(consdev))
                consdev = NULL;
        else
-               device_create_file(consdev, &dev_attr_active);
+               WARN_ON(device_create_file(consdev, &dev_attr_active) < 0);
 
 #ifdef CONFIG_VT
        vty_init(&console_fops);
index ebae344..c956ed6 100644 (file)
@@ -316,9 +316,9 @@ int paste_selection(struct tty_struct *tty)
        /* always called with BTM from vt_ioctl */
        WARN_ON(!tty_locked());
 
-       acquire_console_sem();
+       console_lock();
        poke_blanked_console();
-       release_console_sem();
+       console_unlock();
 
        ld = tty_ldisc_ref(tty);
        if (!ld) {
index eab3a1f..a672ed1 100644 (file)
@@ -202,7 +202,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
        /* Select the proper current console and verify
         * sanity of the situation under the console lock.
         */
-       acquire_console_sem();
+       console_lock();
 
        attr = (currcons & 128);
        currcons = (currcons & 127);
@@ -336,9 +336,9 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
                 * the pagefault handling code may want to call printk().
                 */
 
-               release_console_sem();
+               console_unlock();
                ret = copy_to_user(buf, con_buf_start, orig_count);
-               acquire_console_sem();
+               console_lock();
 
                if (ret) {
                        read += (orig_count - ret);
@@ -354,7 +354,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
        if (read)
                ret = read;
 unlock_out:
-       release_console_sem();
+       console_unlock();
        mutex_unlock(&con_buf_mtx);
        return ret;
 }
@@ -379,7 +379,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
        /* Select the proper current console and verify
         * sanity of the situation under the console lock.
         */
-       acquire_console_sem();
+       console_lock();
 
        attr = (currcons & 128);
        currcons = (currcons & 127);
@@ -414,9 +414,9 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
                /* Temporarily drop the console lock so that we can read
                 * in the write data from userspace safely.
                 */
-               release_console_sem();
+               console_unlock();
                ret = copy_from_user(con_buf, buf, this_round);
-               acquire_console_sem();
+               console_lock();
 
                if (ret) {
                        this_round -= ret;
@@ -542,7 +542,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
                vcs_scr_updated(vc);
 
 unlock_out:
-       release_console_sem();
+       console_unlock();
 
        mutex_unlock(&con_buf_mtx);
 
index 76407ec..147ede3 100644 (file)
@@ -1003,9 +1003,9 @@ static int vt_resize(struct tty_struct *tty, struct winsize *ws)
        struct vc_data *vc = tty->driver_data;
        int ret;
 
-       acquire_console_sem();
+       console_lock();
        ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row);
-       release_console_sem();
+       console_unlock();
        return ret;
 }
 
@@ -1271,7 +1271,7 @@ static void default_attr(struct vc_data *vc)
        vc->vc_color = vc->vc_def_color;
 }
 
-/* console_sem is held */
+/* console_lock is held */
 static void csi_m(struct vc_data *vc)
 {
        int i;
@@ -1415,7 +1415,7 @@ int mouse_reporting(void)
        return vc_cons[fg_console].d->vc_report_mouse;
 }
 
-/* console_sem is held */
+/* console_lock is held */
 static void set_mode(struct vc_data *vc, int on_off)
 {
        int i;
@@ -1485,7 +1485,7 @@ static void set_mode(struct vc_data *vc, int on_off)
                }
 }
 
-/* console_sem is held */
+/* console_lock is held */
 static void setterm_command(struct vc_data *vc)
 {
        switch(vc->vc_par[0]) {
@@ -1545,7 +1545,7 @@ static void setterm_command(struct vc_data *vc)
        }
 }
 
-/* console_sem is held */
+/* console_lock is held */
 static void csi_at(struct vc_data *vc, unsigned int nr)
 {
        if (nr > vc->vc_cols - vc->vc_x)
@@ -1555,7 +1555,7 @@ static void csi_at(struct vc_data *vc, unsigned int nr)
        insert_char(vc, nr);
 }
 
-/* console_sem is held */
+/* console_lock is held */
 static void csi_L(struct vc_data *vc, unsigned int nr)
 {
        if (nr > vc->vc_rows - vc->vc_y)
@@ -1566,7 +1566,7 @@ static void csi_L(struct vc_data *vc, unsigned int nr)
        vc->vc_need_wrap = 0;
 }
 
-/* console_sem is held */
+/* console_lock is held */
 static void csi_P(struct vc_data *vc, unsigned int nr)
 {
        if (nr > vc->vc_cols - vc->vc_x)
@@ -1576,7 +1576,7 @@ static void csi_P(struct vc_data *vc, unsigned int nr)
        delete_char(vc, nr);
 }
 
-/* console_sem is held */
+/* console_lock is held */
 static void csi_M(struct vc_data *vc, unsigned int nr)
 {
        if (nr > vc->vc_rows - vc->vc_y)
@@ -1587,7 +1587,7 @@ static void csi_M(struct vc_data *vc, unsigned int nr)
        vc->vc_need_wrap = 0;
 }
 
-/* console_sem is held (except via vc_init->reset_terminal */
+/* console_lock is held (except via vc_init->reset_terminal */
 static void save_cur(struct vc_data *vc)
 {
        vc->vc_saved_x          = vc->vc_x;
@@ -1603,7 +1603,7 @@ static void save_cur(struct vc_data *vc)
        vc->vc_saved_G1         = vc->vc_G1_charset;
 }
 
-/* console_sem is held */
+/* console_lock is held */
 static void restore_cur(struct vc_data *vc)
 {
        gotoxy(vc, vc->vc_saved_x, vc->vc_saved_y);
@@ -1625,7 +1625,7 @@ enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
        EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
        ESpalette };
 
-/* console_sem is held (except via vc_init()) */
+/* console_lock is held (except via vc_init()) */
 static void reset_terminal(struct vc_data *vc, int do_clear)
 {
        vc->vc_top              = 0;
@@ -1685,7 +1685,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
            csi_J(vc, 2);
 }
 
-/* console_sem is held */
+/* console_lock is held */
 static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
 {
        /*
@@ -2119,7 +2119,7 @@ static int is_double_width(uint32_t ucs)
        return bisearch(ucs, double_width, ARRAY_SIZE(double_width) - 1);
 }
 
-/* acquires console_sem */
+/* acquires console_lock */
 static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count)
 {
 #ifdef VT_BUF_VRAM_ONLY
@@ -2147,11 +2147,11 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
 
        might_sleep();
 
-       acquire_console_sem();
+       console_lock();
        vc = tty->driver_data;
        if (vc == NULL) {
                printk(KERN_ERR "vt: argh, driver_data is NULL !\n");
-               release_console_sem();
+               console_unlock();
                return 0;
        }
 
@@ -2159,7 +2159,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
        if (!vc_cons_allocated(currcons)) {
            /* could this happen? */
                printk_once("con_write: tty %d not allocated\n", currcons+1);
-           release_console_sem();
+           console_unlock();
            return 0;
        }
 
@@ -2375,7 +2375,7 @@ rescan_last_byte:
        }
        FLUSH
        console_conditional_schedule();
-       release_console_sem();
+       console_unlock();
        notify_update(vc);
        return n;
 #undef FLUSH
@@ -2388,11 +2388,11 @@ rescan_last_byte:
  * us to do the switches asynchronously (needed when we want
  * to switch due to a keyboard interrupt).  Synchronization
  * with other console code and prevention of re-entrancy is
- * ensured with console_sem.
+ * ensured with console_lock.
  */
 static void console_callback(struct work_struct *ignored)
 {
-       acquire_console_sem();
+       console_lock();
 
        if (want_console >= 0) {
                if (want_console != fg_console &&
@@ -2422,7 +2422,7 @@ static void console_callback(struct work_struct *ignored)
        }
        notify_update(vc_cons[fg_console].d);
 
-       release_console_sem();
+       console_unlock();
 }
 
 int set_console(int nr)
@@ -2603,7 +2603,7 @@ static struct console vt_console_driver = {
  */
 
 /*
- * Generally a bit racy with respect to console_sem().
+ * Generally a bit racy with respect to console_lock();.
  *
  * There are some functions which don't need it.
  *
@@ -2629,17 +2629,17 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
        switch (type)
        {
                case TIOCL_SETSEL:
-                       acquire_console_sem();
+                       console_lock();
                        ret = set_selection((struct tiocl_selection __user *)(p+1), tty);
-                       release_console_sem();
+                       console_unlock();
                        break;
                case TIOCL_PASTESEL:
                        ret = paste_selection(tty);
                        break;
                case TIOCL_UNBLANKSCREEN:
-                       acquire_console_sem();
+                       console_lock();
                        unblank_screen();
-                       release_console_sem();
+                       console_unlock();
                        break;
                case TIOCL_SELLOADLUT:
                        ret = sel_loadlut(p);
@@ -2688,10 +2688,10 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
                        }
                        break;
                case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */
-                       acquire_console_sem();
+                       console_lock();
                        ignore_poke = 1;
                        do_blank_screen(0);
-                       release_console_sem();
+                       console_unlock();
                        break;
                case TIOCL_BLANKEDSCREEN:
                        ret = console_blanked;
@@ -2790,11 +2790,11 @@ static void con_flush_chars(struct tty_struct *tty)
                return;
 
        /* if we race with con_close(), vt may be null */
-       acquire_console_sem();
+       console_lock();
        vc = tty->driver_data;
        if (vc)
                set_cursor(vc);
-       release_console_sem();
+       console_unlock();
 }
 
 /*
@@ -2805,7 +2805,7 @@ static int con_open(struct tty_struct *tty, struct file *filp)
        unsigned int currcons = tty->index;
        int ret = 0;
 
-       acquire_console_sem();
+       console_lock();
        if (tty->driver_data == NULL) {
                ret = vc_allocate(currcons);
                if (ret == 0) {
@@ -2813,7 +2813,7 @@ static int con_open(struct tty_struct *tty, struct file *filp)
 
                        /* Still being freed */
                        if (vc->port.tty) {
-                               release_console_sem();
+                               console_unlock();
                                return -ERESTARTSYS;
                        }
                        tty->driver_data = vc;
@@ -2827,11 +2827,11 @@ static int con_open(struct tty_struct *tty, struct file *filp)
                                tty->termios->c_iflag |= IUTF8;
                        else
                                tty->termios->c_iflag &= ~IUTF8;
-                       release_console_sem();
+                       console_unlock();
                        return ret;
                }
        }
-       release_console_sem();
+       console_unlock();
        return ret;
 }
 
@@ -2844,9 +2844,9 @@ static void con_shutdown(struct tty_struct *tty)
 {
        struct vc_data *vc = tty->driver_data;
        BUG_ON(vc == NULL);
-       acquire_console_sem();
+       console_lock();
        vc->port.tty = NULL;
-       release_console_sem();
+       console_unlock();
        tty_shutdown(tty);
 }
 
@@ -2893,13 +2893,13 @@ static int __init con_init(void)
        struct vc_data *vc;
        unsigned int currcons = 0, i;
 
-       acquire_console_sem();
+       console_lock();
 
        if (conswitchp)
                display_desc = conswitchp->con_startup();
        if (!display_desc) {
                fg_console = 0;
-               release_console_sem();
+               console_unlock();
                return 0;
        }
 
@@ -2946,7 +2946,7 @@ static int __init con_init(void)
        printable = 1;
        printk("\n");
 
-       release_console_sem();
+       console_unlock();
 
 #ifdef CONFIG_VT_CONSOLE
        register_console(&vt_console_driver);
@@ -2994,7 +2994,7 @@ int __init vty_init(const struct file_operations *console_fops)
        if (IS_ERR(tty0dev))
                tty0dev = NULL;
        else
-               device_create_file(tty0dev, &dev_attr_active);
+               WARN_ON(device_create_file(tty0dev, &dev_attr_active) < 0);
 
        vcs_init();
 
@@ -3037,7 +3037,7 @@ static int bind_con_driver(const struct consw *csw, int first, int last,
        if (!try_module_get(owner))
                return -ENODEV;
 
-       acquire_console_sem();
+       console_lock();
 
        /* check if driver is registered */
        for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
@@ -3122,7 +3122,7 @@ static int bind_con_driver(const struct consw *csw, int first, int last,
 
        retval = 0;
 err:
-       release_console_sem();
+       console_unlock();
        module_put(owner);
        return retval;
 };
@@ -3171,7 +3171,7 @@ int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
        if (!try_module_get(owner))
                return -ENODEV;
 
-       acquire_console_sem();
+       console_lock();
 
        /* check if driver is registered and if it is unbindable */
        for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
@@ -3185,7 +3185,7 @@ int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
        }
 
        if (retval) {
-               release_console_sem();
+               console_unlock();
                goto err;
        }
 
@@ -3204,12 +3204,12 @@ int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
        }
 
        if (retval) {
-               release_console_sem();
+               console_unlock();
                goto err;
        }
 
        if (!con_is_bound(csw)) {
-               release_console_sem();
+               console_unlock();
                goto err;
        }
 
@@ -3238,7 +3238,7 @@ int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
        if (!con_is_bound(csw))
                con_driver->flag &= ~CON_DRIVER_FLAG_INIT;
 
-       release_console_sem();
+       console_unlock();
        /* ignore return value, binding should not fail */
        bind_con_driver(defcsw, first, last, deflt);
 err:
@@ -3538,14 +3538,14 @@ int register_con_driver(const struct consw *csw, int first, int last)
        if (!try_module_get(owner))
                return -ENODEV;
 
-       acquire_console_sem();
+       console_lock();
 
        for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
                con_driver = &registered_con_driver[i];
 
                /* already registered */
                if (con_driver->con == csw)
-                       retval = -EINVAL;
+                       retval = -EBUSY;
        }
 
        if (retval)
@@ -3592,7 +3592,7 @@ int register_con_driver(const struct consw *csw, int first, int last)
        }
 
 err:
-       release_console_sem();
+       console_unlock();
        module_put(owner);
        return retval;
 }
@@ -3613,7 +3613,7 @@ int unregister_con_driver(const struct consw *csw)
 {
        int i, retval = -ENODEV;
 
-       acquire_console_sem();
+       console_lock();
 
        /* cannot unregister a bound driver */
        if (con_is_bound(csw))
@@ -3639,7 +3639,7 @@ int unregister_con_driver(const struct consw *csw)
                }
        }
 err:
-       release_console_sem();
+       console_unlock();
        return retval;
 }
 EXPORT_SYMBOL(unregister_con_driver);
@@ -3656,7 +3656,12 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt)
        int err;
 
        err = register_con_driver(csw, first, last);
-
+       /* if we get an busy error we still want to bind the console driver
+        * and return success, as we may have unbound the console driver
+       Â * but not unregistered it.
+       */
+       if (err == -EBUSY)
+               err = 0;
        if (!err)
                bind_con_driver(csw, first, last, deflt);
 
@@ -3934,9 +3939,9 @@ int con_set_cmap(unsigned char __user *arg)
 {
        int rc;
 
-       acquire_console_sem();
+       console_lock();
        rc = set_get_cmap (arg,1);
-       release_console_sem();
+       console_unlock();
 
        return rc;
 }
@@ -3945,9 +3950,9 @@ int con_get_cmap(unsigned char __user *arg)
 {
        int rc;
 
-       acquire_console_sem();
+       console_lock();
        rc = set_get_cmap (arg,0);
-       release_console_sem();
+       console_unlock();
 
        return rc;
 }
@@ -3994,12 +3999,12 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
        } else
                font.data = NULL;
 
-       acquire_console_sem();
+       console_lock();
        if (vc->vc_sw->con_font_get)
                rc = vc->vc_sw->con_font_get(vc, &font);
        else
                rc = -ENOSYS;
-       release_console_sem();
+       console_unlock();
 
        if (rc)
                goto out;
@@ -4076,12 +4081,12 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op)
        font.data = memdup_user(op->data, size);
        if (IS_ERR(font.data))
                return PTR_ERR(font.data);
-       acquire_console_sem();
+       console_lock();
        if (vc->vc_sw->con_font_set)
                rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
        else
                rc = -ENOSYS;
-       release_console_sem();
+       console_unlock();
        kfree(font.data);
        return rc;
 }
@@ -4103,12 +4108,12 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op)
        else
                name[MAX_FONT_NAME - 1] = 0;
 
-       acquire_console_sem();
+       console_lock();
        if (vc->vc_sw->con_font_default)
                rc = vc->vc_sw->con_font_default(vc, &font, s);
        else
                rc = -ENOSYS;
-       release_console_sem();
+       console_unlock();
        if (!rc) {
                op->width = font.width;
                op->height = font.height;
@@ -4124,7 +4129,7 @@ static int con_font_copy(struct vc_data *vc, struct console_font_op *op)
        if (vc->vc_mode != KD_TEXT)
                return -EINVAL;
 
-       acquire_console_sem();
+       console_lock();
        if (!vc->vc_sw->con_font_copy)
                rc = -ENOSYS;
        else if (con < 0 || !vc_cons_allocated(con))
@@ -4133,7 +4138,7 @@ static int con_font_copy(struct vc_data *vc, struct console_font_op *op)
                rc = 0;
        else
                rc = vc->vc_sw->con_font_copy(vc, con);
-       release_console_sem();
+       console_unlock();
        return rc;
 }
 
index 6b68a0f..1235ebd 100644 (file)
@@ -649,12 +649,12 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                /*
                 * explicitly blank/unblank the screen if switching modes
                 */
-               acquire_console_sem();
+               console_lock();
                if (arg == KD_TEXT)
                        do_unblank_screen(1);
                else
                        do_blank_screen(1);
-               release_console_sem();
+               console_unlock();
                break;
 
        case KDGETMODE:
@@ -893,7 +893,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                        ret = -EINVAL;
                        goto out;
                }
-               acquire_console_sem();
+               console_lock();
                vc->vt_mode = tmp;
                /* the frsig is ignored, so we set it to 0 */
                vc->vt_mode.frsig = 0;
@@ -901,7 +901,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                vc->vt_pid = get_pid(task_pid(current));
                /* no switch is required -- saw@shade.msu.ru */
                vc->vt_newvt = -1;
-               release_console_sem();
+               console_unlock();
                break;
        }
 
@@ -910,9 +910,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                struct vt_mode tmp;
                int rc;
 
-               acquire_console_sem();
+               console_lock();
                memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode));
-               release_console_sem();
+               console_unlock();
 
                rc = copy_to_user(up, &tmp, sizeof(struct vt_mode));
                if (rc)
@@ -965,9 +965,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                        ret =  -ENXIO;
                else {
                        arg--;
-                       acquire_console_sem();
+                       console_lock();
                        ret = vc_allocate(arg);
-                       release_console_sem();
+                       console_unlock();
                        if (ret)
                                break;
                        set_console(arg);
@@ -990,7 +990,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                        ret = -ENXIO;
                else {
                        vsa.console--;
-                       acquire_console_sem();
+                       console_lock();
                        ret = vc_allocate(vsa.console);
                        if (ret == 0) {
                                struct vc_data *nvc;
@@ -1003,7 +1003,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                                put_pid(nvc->vt_pid);
                                nvc->vt_pid = get_pid(task_pid(current));
                        }
-                       release_console_sem();
+                       console_unlock();
                        if (ret)
                                break;
                        /* Commence switch and lock */
@@ -1044,7 +1044,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                /*
                 * Switching-from response
                 */
-               acquire_console_sem();
+               console_lock();
                if (vc->vt_newvt >= 0) {
                        if (arg == 0)
                                /*
@@ -1063,7 +1063,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                                vc->vt_newvt = -1;
                                ret = vc_allocate(newvt);
                                if (ret) {
-                                       release_console_sem();
+                                       console_unlock();
                                        break;
                                }
                                /*
@@ -1083,7 +1083,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                        if (arg != VT_ACKACQ)
                                ret = -EINVAL;
                }
-               release_console_sem();
+               console_unlock();
                break;
 
         /*
@@ -1096,20 +1096,20 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                }
                if (arg == 0) {
                    /* deallocate all unused consoles, but leave 0 */
-                       acquire_console_sem();
+                       console_lock();
                        for (i=1; i<MAX_NR_CONSOLES; i++)
                                if (! VT_BUSY(i))
                                        vc_deallocate(i);
-                       release_console_sem();
+                       console_unlock();
                } else {
                        /* deallocate a single console, if possible */
                        arg--;
                        if (VT_BUSY(arg))
                                ret = -EBUSY;
                        else if (arg) {                       /* leave 0 */
-                               acquire_console_sem();
+                               console_lock();
                                vc_deallocate(arg);
-                               release_console_sem();
+                               console_unlock();
                        }
                }
                break;
@@ -1126,7 +1126,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                    get_user(cc, &vtsizes->v_cols))
                        ret = -EFAULT;
                else {
-                       acquire_console_sem();
+                       console_lock();
                        for (i = 0; i < MAX_NR_CONSOLES; i++) {
                                vc = vc_cons[i].d;
 
@@ -1135,7 +1135,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                                        vc_resize(vc_cons[i].d, cc, ll);
                                }
                        }
-                       release_console_sem();
+                       console_unlock();
                }
                break;
        }
@@ -1187,14 +1187,14 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                for (i = 0; i < MAX_NR_CONSOLES; i++) {
                        if (!vc_cons[i].d)
                                continue;
-                       acquire_console_sem();
+                       console_lock();
                        if (vlin)
                                vc_cons[i].d->vc_scan_lines = vlin;
                        if (clin)
                                vc_cons[i].d->vc_font.height = clin;
                        vc_cons[i].d->vc_resize_user = 1;
                        vc_resize(vc_cons[i].d, cc, ll);
-                       release_console_sem();
+                       console_unlock();
                }
                break;
        }
@@ -1367,7 +1367,7 @@ void vc_SAK(struct work_struct *work)
        struct vc_data *vc;
        struct tty_struct *tty;
 
-       acquire_console_sem();
+       console_lock();
        vc = vc_con->d;
        if (vc) {
                tty = vc->port.tty;
@@ -1379,7 +1379,7 @@ void vc_SAK(struct work_struct *work)
                        __do_SAK(tty);
                reset_vc(vc);
        }
-       release_console_sem();
+       console_unlock();
 }
 
 #ifdef CONFIG_COMPAT
@@ -1737,10 +1737,10 @@ int vt_move_to_console(unsigned int vt, int alloc)
 {
        int prev;
 
-       acquire_console_sem();
+       console_lock();
        /* Graphics mode - up to X */
        if (disable_vt_switch) {
-               release_console_sem();
+               console_unlock();
                return 0;
        }
        prev = fg_console;
@@ -1748,7 +1748,7 @@ int vt_move_to_console(unsigned int vt, int alloc)
        if (alloc && vc_allocate(vt)) {
                /* we can't have a free VC for now. Too bad,
                 * we don't want to mess the screen for now. */
-               release_console_sem();
+               console_unlock();
                return -ENOSPC;
        }
 
@@ -1758,10 +1758,10 @@ int vt_move_to_console(unsigned int vt, int alloc)
                 * Let the calling function know so it can decide
                 * what to do.
                 */
-               release_console_sem();
+               console_unlock();
                return -EIO;
        }
-       release_console_sem();
+       console_unlock();
        tty_lock();
        if (vt_waitactive(vt + 1)) {
                pr_debug("Suspend: Can't switch VCs.");
@@ -1781,8 +1781,8 @@ int vt_move_to_console(unsigned int vt, int alloc)
  */
 void pm_set_vt_switch(int do_switch)
 {
-       acquire_console_sem();
+       console_lock();
        disable_vt_switch = !do_switch;
-       release_console_sem();
+       console_unlock();
 }
 EXPORT_SYMBOL(pm_set_vt_switch);
index d6ede98..4ab49d4 100644 (file)
@@ -1607,6 +1607,7 @@ static const struct usb_device_id acm_ids[] = {
        { NOKIA_PCSUITE_ACM_INFO(0x0154), }, /* Nokia 5800 XpressMusic */
        { NOKIA_PCSUITE_ACM_INFO(0x04ce), }, /* Nokia E90 */
        { NOKIA_PCSUITE_ACM_INFO(0x01d4), }, /* Nokia E55 */
+       { NOKIA_PCSUITE_ACM_INFO(0x0302), }, /* Nokia N8 */
        { SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) */
 
        /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */
index 6ee4451..47085e5 100644 (file)
@@ -342,7 +342,7 @@ static ssize_t wdm_write
                goto outnp;
        }
 
-       if (!file->f_flags && O_NONBLOCK)
+       if (!(file->f_flags & O_NONBLOCK))
                r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE,
                                                                &desc->flags));
        else
index 9da2505..df502a9 100644 (file)
@@ -192,12 +192,12 @@ int usb_create_ep_devs(struct device *parent,
        ep_dev->dev.parent = parent;
        ep_dev->dev.release = ep_device_release;
        dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress);
-       device_enable_async_suspend(&ep_dev->dev);
 
        retval = device_register(&ep_dev->dev);
        if (retval)
                goto error_register;
 
+       device_enable_async_suspend(&ep_dev->dev);
        endpoint->ep_dev = ep_dev;
        return retval;
 
index b55d460..f71e8e3 100644 (file)
@@ -405,7 +405,12 @@ static int suspend_common(struct device *dev, bool do_wakeup)
                        return retval;
        }
 
-       synchronize_irq(pci_dev->irq);
+       /* If MSI-X is enabled, the driver will have synchronized all vectors
+        * in pci_suspend(). If MSI or legacy PCI is enabled, that will be
+        * synchronized here.
+        */
+       if (!hcd->msix_enabled)
+               synchronize_irq(pci_dev->irq);
 
        /* Downstream ports from this root hub should already be quiesced, so
         * there will be no DMA activity.  Now we can shut down the upstream
index 6a95017..e935f71 100644 (file)
@@ -1955,7 +1955,6 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
 
        dev_dbg(&rhdev->dev, "usb %s%s\n",
                        (msg.event & PM_EVENT_AUTO ? "auto-" : ""), "resume");
-       clear_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags);
        if (!hcd->driver->bus_resume)
                return -ENOENT;
        if (hcd->state == HC_STATE_RUNNING)
@@ -1963,6 +1962,7 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
 
        hcd->state = HC_STATE_RESUMING;
        status = hcd->driver->bus_resume(hcd);
+       clear_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags);
        if (status == 0) {
                /* TRSMRCY = 10 msec */
                msleep(10);
index b98efae..0f299b7 100644 (file)
@@ -676,6 +676,8 @@ static void hub_init_func3(struct work_struct *ws);
 static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
 {
        struct usb_device *hdev = hub->hdev;
+       struct usb_hcd *hcd;
+       int ret;
        int port1;
        int status;
        bool need_debounce_delay = false;
@@ -714,6 +716,25 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
                        usb_autopm_get_interface_no_resume(
                                        to_usb_interface(hub->intfdev));
                        return;         /* Continues at init2: below */
+               } else if (type == HUB_RESET_RESUME) {
+                       /* The internal host controller state for the hub device
+                        * may be gone after a host power loss on system resume.
+                        * Update the device's info so the HW knows it's a hub.
+                        */
+                       hcd = bus_to_hcd(hdev->bus);
+                       if (hcd->driver->update_hub_device) {
+                               ret = hcd->driver->update_hub_device(hcd, hdev,
+                                               &hub->tt, GFP_NOIO);
+                               if (ret < 0) {
+                                       dev_err(hub->intfdev, "Host not "
+                                                       "accepting hub info "
+                                                       "update.\n");
+                                       dev_err(hub->intfdev, "LS/FS devices "
+                                                       "and hubs may not work "
+                                                       "under this hub\n.");
+                               }
+                       }
+                       hub_power_on(hub, true);
                } else {
                        hub_power_on(hub, true);
                }
@@ -2660,17 +2681,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 
        mutex_lock(&usb_address0_mutex);
 
-       if (!udev->config && oldspeed == USB_SPEED_SUPER) {
-               /* Don't reset USB 3.0 devices during an initial setup */
-               usb_set_device_state(udev, USB_STATE_DEFAULT);
-       } else {
-               /* Reset the device; full speed may morph to high speed */
-               /* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
-               retval = hub_port_reset(hub, port1, udev, delay);
-               if (retval < 0)         /* error or disconnect */
-                       goto fail;
-               /* success, speed is known */
-       }
+       /* Reset the device; full speed may morph to high speed */
+       /* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
+       retval = hub_port_reset(hub, port1, udev, delay);
+       if (retval < 0)         /* error or disconnect */
+               goto fail;
+       /* success, speed is known */
+
        retval = -ENODEV;
 
        if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
@@ -2732,6 +2749,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
                udev->ttport = hdev->ttport;
        } else if (udev->speed != USB_SPEED_HIGH
                        && hdev->speed == USB_SPEED_HIGH) {
+               if (!hub->tt.hub) {
+                       dev_err(&udev->dev, "parent hub has no TT\n");
+                       retval = -EINVAL;
+                       goto fail;
+               }
                udev->tt = &hub->tt;
                udev->ttport = port1;
        }
index 44c5954..81ce6a8 100644 (file)
@@ -48,6 +48,10 @@ static const struct usb_device_id usb_quirk_list[] = {
        { USB_DEVICE(0x04b4, 0x0526), .driver_info =
                        USB_QUIRK_CONFIG_INTF_STRINGS },
 
+       /* Samsung Android phone modem - ID conflict with SPH-I500 */
+       { USB_DEVICE(0x04e8, 0x6601), .driver_info =
+                       USB_QUIRK_CONFIG_INTF_STRINGS },
+
        /* Roland SC-8820 */
        { USB_DEVICE(0x0582, 0x0007), .driver_info = USB_QUIRK_RESET_RESUME },
 
@@ -68,6 +72,10 @@ static const struct usb_device_id usb_quirk_list[] = {
        /* M-Systems Flash Disk Pioneers */
        { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
 
+       /* Keytouch QWERTY Panel keyboard */
+       { USB_DEVICE(0x0926, 0x3333), .driver_info =
+                       USB_QUIRK_CONFIG_INTF_STRINGS },
+
        /* X-Rite/Gretag-Macbeth Eye-One Pro display colorimeter */
        { USB_DEVICE(0x0971, 0x2000), .driver_info = USB_QUIRK_NO_SET_INTF },
 
index 1dc9739..d500996 100644 (file)
@@ -509,7 +509,7 @@ config USB_LANGWELL
        select USB_GADGET_SELECTED
 
 config USB_GADGET_EG20T
-       boolean "Intel EG20T(Topcliff) USB Device controller"
+       boolean "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH UDC"
        depends on PCI
        select USB_GADGET_DUALSPEED
        help
@@ -525,6 +525,11 @@ config USB_GADGET_EG20T
          This driver dose not support interrupt transfer or isochronous
          transfer modes.
 
+         This driver also can be used for OKI SEMICONDUCTOR's ML7213 which is
+         for IVI(In-Vehicle Infotainment) use.
+         ML7213 is companion chip for Intel Atom E6xx series.
+         ML7213 is completely compatible for Intel EG20T PCH.
+
 config USB_EG20T
        tristate
        depends on USB_GADGET_EG20T
@@ -541,6 +546,8 @@ config USB_GADGET_CI13XXX_MSM
          ci13xxx_udc core.
          This driver depends on OTG driver for PHY initialization,
          clock management, powering up VBUS, and power management.
+         This driver is not supported on boards like trout which
+         has an external PHY.
 
          Say "y" to link the driver statically, or "m" to build a
          dynamically linked module called "ci13xxx_msm" and force all
index 31656a2..a1c67ae 100644 (file)
@@ -76,10 +76,21 @@ static DEFINE_SPINLOCK(udc_lock);
 
 /* control endpoint description */
 static const struct usb_endpoint_descriptor
-ctrl_endpt_desc = {
+ctrl_endpt_out_desc = {
        .bLength         = USB_DT_ENDPOINT_SIZE,
        .bDescriptorType = USB_DT_ENDPOINT,
 
+       .bEndpointAddress = USB_DIR_OUT,
+       .bmAttributes    = USB_ENDPOINT_XFER_CONTROL,
+       .wMaxPacketSize  = cpu_to_le16(CTRL_PAYLOAD_MAX),
+};
+
+static const struct usb_endpoint_descriptor
+ctrl_endpt_in_desc = {
+       .bLength         = USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType = USB_DT_ENDPOINT,
+
+       .bEndpointAddress = USB_DIR_IN,
        .bmAttributes    = USB_ENDPOINT_XFER_CONTROL,
        .wMaxPacketSize  = cpu_to_le16(CTRL_PAYLOAD_MAX),
 };
@@ -265,10 +276,10 @@ static int hw_device_init(void __iomem *base)
        hw_bank.size /= sizeof(u32);
 
        reg = hw_aread(ABS_DCCPARAMS, DCCPARAMS_DEN) >> ffs_nr(DCCPARAMS_DEN);
-       if (reg == 0 || reg > ENDPT_MAX)
-               return -ENODEV;
+       hw_ep_max = reg * 2;   /* cache hw ENDPT_MAX */
 
-       hw_ep_max = reg;   /* cache hw ENDPT_MAX */
+       if (hw_ep_max == 0 || hw_ep_max > ENDPT_MAX)
+               return -ENODEV;
 
        /* setup lock mode ? */
 
@@ -1197,16 +1208,17 @@ static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
        }
 
        spin_lock_irqsave(udc->lock, flags);
-       for (i = 0; i < hw_ep_max; i++) {
-               struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
+       for (i = 0; i < hw_ep_max/2; i++) {
+               struct ci13xxx_ep *mEpRx = &udc->ci13xxx_ep[i];
+               struct ci13xxx_ep *mEpTx = &udc->ci13xxx_ep[i + hw_ep_max/2];
                n += scnprintf(buf + n, PAGE_SIZE - n,
                               "EP=%02i: RX=%08X TX=%08X\n",
-                              i, (u32)mEp->qh[RX].dma, (u32)mEp->qh[TX].dma);
+                              i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
                for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) {
                        n += scnprintf(buf + n, PAGE_SIZE - n,
                                       " %04X:    %08X    %08X\n", j,
-                                      *((u32 *)mEp->qh[RX].ptr + j),
-                                      *((u32 *)mEp->qh[TX].ptr + j));
+                                      *((u32 *)mEpRx->qh.ptr + j),
+                                      *((u32 *)mEpTx->qh.ptr + j));
                }
        }
        spin_unlock_irqrestore(udc->lock, flags);
@@ -1293,7 +1305,7 @@ static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
        unsigned long flags;
        struct list_head   *ptr = NULL;
        struct ci13xxx_req *req = NULL;
-       unsigned i, j, k, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
+       unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
 
        dbg_trace("[%s] %p\n", __func__, buf);
        if (attr == NULL || buf == NULL) {
@@ -1303,22 +1315,20 @@ static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
 
        spin_lock_irqsave(udc->lock, flags);
        for (i = 0; i < hw_ep_max; i++)
-               for (k = RX; k <= TX; k++)
-                       list_for_each(ptr, &udc->ci13xxx_ep[i].qh[k].queue)
-                       {
-                               req = list_entry(ptr,
-                                                struct ci13xxx_req, queue);
+               list_for_each(ptr, &udc->ci13xxx_ep[i].qh.queue)
+               {
+                       req = list_entry(ptr, struct ci13xxx_req, queue);
+
+                       n += scnprintf(buf + n, PAGE_SIZE - n,
+                                       "EP=%02i: TD=%08X %s\n",
+                                       i % hw_ep_max/2, (u32)req->dma,
+                                       ((i < hw_ep_max/2) ? "RX" : "TX"));
 
+                       for (j = 0; j < qSize; j++)
                                n += scnprintf(buf + n, PAGE_SIZE - n,
-                                              "EP=%02i: TD=%08X %s\n",
-                                              i, (u32)req->dma,
-                                              ((k == RX) ? "RX" : "TX"));
-
-                               for (j = 0; j < qSize; j++)
-                                       n += scnprintf(buf + n, PAGE_SIZE - n,
-                                                      " %04X:    %08X\n", j,
-                                                      *((u32 *)req->ptr + j));
-                       }
+                                               " %04X:    %08X\n", j,
+                                               *((u32 *)req->ptr + j));
+               }
        spin_unlock_irqrestore(udc->lock, flags);
 
        return n;
@@ -1467,12 +1477,12 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
         *  At this point it's guaranteed exclusive access to qhead
         *  (endpt is not primed) so it's no need to use tripwire
         */
-       mEp->qh[mEp->dir].ptr->td.next   = mReq->dma;    /* TERMINATE = 0 */
-       mEp->qh[mEp->dir].ptr->td.token &= ~TD_STATUS;   /* clear status */
+       mEp->qh.ptr->td.next   = mReq->dma;    /* TERMINATE = 0 */
+       mEp->qh.ptr->td.token &= ~TD_STATUS;   /* clear status */
        if (mReq->req.zero == 0)
-               mEp->qh[mEp->dir].ptr->cap |=  QH_ZLT;
+               mEp->qh.ptr->cap |=  QH_ZLT;
        else
-               mEp->qh[mEp->dir].ptr->cap &= ~QH_ZLT;
+               mEp->qh.ptr->cap &= ~QH_ZLT;
 
        wmb();   /* synchronize before ep prime */
 
@@ -1542,11 +1552,11 @@ __acquires(mEp->lock)
 
        hw_ep_flush(mEp->num, mEp->dir);
 
-       while (!list_empty(&mEp->qh[mEp->dir].queue)) {
+       while (!list_empty(&mEp->qh.queue)) {
 
                /* pop oldest request */
                struct ci13xxx_req *mReq = \
-                       list_entry(mEp->qh[mEp->dir].queue.next,
+                       list_entry(mEp->qh.queue.next,
                                   struct ci13xxx_req, queue);
                list_del_init(&mReq->queue);
                mReq->req.status = -ESHUTDOWN;
@@ -1571,8 +1581,6 @@ static int _gadget_stop_activity(struct usb_gadget *gadget)
 {
        struct usb_ep *ep;
        struct ci13xxx    *udc = container_of(gadget, struct ci13xxx, gadget);
-       struct ci13xxx_ep *mEp = container_of(gadget->ep0,
-                                             struct ci13xxx_ep, ep);
 
        trace("%p", gadget);
 
@@ -1583,7 +1591,8 @@ static int _gadget_stop_activity(struct usb_gadget *gadget)
        gadget_for_each_ep(ep, gadget) {
                usb_ep_fifo_flush(ep);
        }
-       usb_ep_fifo_flush(gadget->ep0);
+       usb_ep_fifo_flush(&udc->ep0out.ep);
+       usb_ep_fifo_flush(&udc->ep0in.ep);
 
        udc->driver->disconnect(gadget);
 
@@ -1591,11 +1600,12 @@ static int _gadget_stop_activity(struct usb_gadget *gadget)
        gadget_for_each_ep(ep, gadget) {
                usb_ep_disable(ep);
        }
-       usb_ep_disable(gadget->ep0);
+       usb_ep_disable(&udc->ep0out.ep);
+       usb_ep_disable(&udc->ep0in.ep);
 
-       if (mEp->status != NULL) {
-               usb_ep_free_request(gadget->ep0, mEp->status);
-               mEp->status = NULL;
+       if (udc->status != NULL) {
+               usb_ep_free_request(&udc->ep0in.ep, udc->status);
+               udc->status = NULL;
        }
 
        return 0;
@@ -1614,7 +1624,6 @@ static void isr_reset_handler(struct ci13xxx *udc)
 __releases(udc->lock)
 __acquires(udc->lock)
 {
-       struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[0];
        int retval;
 
        trace("%p", udc);
@@ -1635,11 +1644,15 @@ __acquires(udc->lock)
        if (retval)
                goto done;
 
-       retval = usb_ep_enable(&mEp->ep, &ctrl_endpt_desc);
+       retval = usb_ep_enable(&udc->ep0out.ep, &ctrl_endpt_out_desc);
+       if (retval)
+               goto done;
+
+       retval = usb_ep_enable(&udc->ep0in.ep, &ctrl_endpt_in_desc);
        if (!retval) {
-               mEp->status = usb_ep_alloc_request(&mEp->ep, GFP_ATOMIC);
-               if (mEp->status == NULL) {
-                       usb_ep_disable(&mEp->ep);
+               udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_ATOMIC);
+               if (udc->status == NULL) {
+                       usb_ep_disable(&udc->ep0out.ep);
                        retval = -ENOMEM;
                }
        }
@@ -1672,16 +1685,17 @@ static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
 
 /**
  * isr_get_status_response: get_status request response
- * @ep:    endpoint
+ * @udc: udc struct
  * @setup: setup request packet
  *
  * This function returns an error code
  */
-static int isr_get_status_response(struct ci13xxx_ep *mEp,
+static int isr_get_status_response(struct ci13xxx *udc,
                                   struct usb_ctrlrequest *setup)
 __releases(mEp->lock)
 __acquires(mEp->lock)
 {
+       struct ci13xxx_ep *mEp = &udc->ep0in;
        struct usb_request *req = NULL;
        gfp_t gfp_flags = GFP_ATOMIC;
        int dir, num, retval;
@@ -1736,27 +1750,23 @@ __acquires(mEp->lock)
 
 /**
  * isr_setup_status_phase: queues the status phase of a setup transation
- * @mEp: endpoint
+ * @udc: udc struct
  *
  * This function returns an error code
  */
-static int isr_setup_status_phase(struct ci13xxx_ep *mEp)
+static int isr_setup_status_phase(struct ci13xxx *udc)
 __releases(mEp->lock)
 __acquires(mEp->lock)
 {
        int retval;
+       struct ci13xxx_ep *mEp;
 
-       trace("%p", mEp);
-
-       /* mEp is always valid & configured */
-
-       if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
-               mEp->dir = (mEp->dir == TX) ? RX : TX;
+       trace("%p", udc);
 
-       mEp->status->no_interrupt = 1;
+       mEp = (udc->ep0_dir == TX) ? &udc->ep0out : &udc->ep0in;
 
        spin_unlock(mEp->lock);
-       retval = usb_ep_queue(&mEp->ep, mEp->status, GFP_ATOMIC);
+       retval = usb_ep_queue(&mEp->ep, udc->status, GFP_ATOMIC);
        spin_lock(mEp->lock);
 
        return retval;
@@ -1778,11 +1788,11 @@ __acquires(mEp->lock)
 
        trace("%p", mEp);
 
-       if (list_empty(&mEp->qh[mEp->dir].queue))
+       if (list_empty(&mEp->qh.queue))
                return -EINVAL;
 
        /* pop oldest request */
-       mReq = list_entry(mEp->qh[mEp->dir].queue.next,
+       mReq = list_entry(mEp->qh.queue.next,
                          struct ci13xxx_req, queue);
        list_del_init(&mReq->queue);
 
@@ -1794,10 +1804,10 @@ __acquires(mEp->lock)
 
        dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
 
-       if (!list_empty(&mEp->qh[mEp->dir].queue)) {
+       if (!list_empty(&mEp->qh.queue)) {
                struct ci13xxx_req* mReqEnq;
 
-               mReqEnq = list_entry(mEp->qh[mEp->dir].queue.next,
+               mReqEnq = list_entry(mEp->qh.queue.next,
                                  struct ci13xxx_req, queue);
                _hardware_enqueue(mEp, mReqEnq);
        }
@@ -1836,16 +1846,14 @@ __acquires(udc->lock)
                int type, num, err = -EINVAL;
                struct usb_ctrlrequest req;
 
-
                if (mEp->desc == NULL)
                        continue;   /* not configured */
 
-               if ((mEp->dir == RX && hw_test_and_clear_complete(i)) ||
-                   (mEp->dir == TX && hw_test_and_clear_complete(i + 16))) {
+               if (hw_test_and_clear_complete(i)) {
                        err = isr_tr_complete_low(mEp);
                        if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
                                if (err > 0)   /* needs status phase */
-                                       err = isr_setup_status_phase(mEp);
+                                       err = isr_setup_status_phase(udc);
                                if (err < 0) {
                                        dbg_event(_usb_addr(mEp),
                                                  "ERROR", err);
@@ -1866,15 +1874,22 @@ __acquires(udc->lock)
                        continue;
                }
 
+               /*
+                * Flush data and handshake transactions of previous
+                * setup packet.
+                */
+               _ep_nuke(&udc->ep0out);
+               _ep_nuke(&udc->ep0in);
+
                /* read_setup_packet */
                do {
                        hw_test_and_set_setup_guard();
-                       memcpy(&req, &mEp->qh[RX].ptr->setup, sizeof(req));
+                       memcpy(&req, &mEp->qh.ptr->setup, sizeof(req));
                } while (!hw_test_and_clear_setup_guard());
 
                type = req.bRequestType;
 
-               mEp->dir = (type & USB_DIR_IN) ? TX : RX;
+               udc->ep0_dir = (type & USB_DIR_IN) ? TX : RX;
 
                dbg_setup(_usb_addr(mEp), &req);
 
@@ -1895,7 +1910,7 @@ __acquires(udc->lock)
                                if (err)
                                        break;
                        }
-                       err = isr_setup_status_phase(mEp);
+                       err = isr_setup_status_phase(udc);
                        break;
                case USB_REQ_GET_STATUS:
                        if (type != (USB_DIR_IN|USB_RECIP_DEVICE)   &&
@@ -1905,7 +1920,7 @@ __acquires(udc->lock)
                        if (le16_to_cpu(req.wLength) != 2 ||
                            le16_to_cpu(req.wValue)  != 0)
                                break;
-                       err = isr_get_status_response(mEp, &req);
+                       err = isr_get_status_response(udc, &req);
                        break;
                case USB_REQ_SET_ADDRESS:
                        if (type != (USB_DIR_OUT|USB_RECIP_DEVICE))
@@ -1916,7 +1931,7 @@ __acquires(udc->lock)
                        err = hw_usb_set_address((u8)le16_to_cpu(req.wValue));
                        if (err)
                                break;
-                       err = isr_setup_status_phase(mEp);
+                       err = isr_setup_status_phase(udc);
                        break;
                case USB_REQ_SET_FEATURE:
                        if (type != (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
@@ -1932,12 +1947,12 @@ __acquires(udc->lock)
                        spin_lock(udc->lock);
                        if (err)
                                break;
-                       err = isr_setup_status_phase(mEp);
+                       err = isr_setup_status_phase(udc);
                        break;
                default:
 delegate:
                        if (req.wLength == 0)   /* no data phase */
-                               mEp->dir = TX;
+                               udc->ep0_dir = TX;
 
                        spin_unlock(udc->lock);
                        err = udc->driver->setup(&udc->gadget, &req);
@@ -1968,7 +1983,7 @@ static int ep_enable(struct usb_ep *ep,
                     const struct usb_endpoint_descriptor *desc)
 {
        struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
-       int direction, retval = 0;
+       int retval = 0;
        unsigned long flags;
 
        trace("%p, %p", ep, desc);
@@ -1982,7 +1997,7 @@ static int ep_enable(struct usb_ep *ep,
 
        mEp->desc = desc;
 
-       if (!list_empty(&mEp->qh[mEp->dir].queue))
+       if (!list_empty(&mEp->qh.queue))
                warn("enabling a non-empty endpoint!");
 
        mEp->dir  = usb_endpoint_dir_in(desc) ? TX : RX;
@@ -1991,29 +2006,22 @@ static int ep_enable(struct usb_ep *ep,
 
        mEp->ep.maxpacket = __constant_le16_to_cpu(desc->wMaxPacketSize);
 
-       direction = mEp->dir;
-       do {
-               dbg_event(_usb_addr(mEp), "ENABLE", 0);
+       dbg_event(_usb_addr(mEp), "ENABLE", 0);
 
-               mEp->qh[mEp->dir].ptr->cap = 0;
+       mEp->qh.ptr->cap = 0;
 
-               if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
-                       mEp->qh[mEp->dir].ptr->cap |=  QH_IOS;
-               else if (mEp->type == USB_ENDPOINT_XFER_ISOC)
-                       mEp->qh[mEp->dir].ptr->cap &= ~QH_MULT;
-               else
-                       mEp->qh[mEp->dir].ptr->cap &= ~QH_ZLT;
-
-               mEp->qh[mEp->dir].ptr->cap |=
-                       (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
-               mEp->qh[mEp->dir].ptr->td.next |= TD_TERMINATE;   /* needed? */
-
-               retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type);
+       if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+               mEp->qh.ptr->cap |=  QH_IOS;
+       else if (mEp->type == USB_ENDPOINT_XFER_ISOC)
+               mEp->qh.ptr->cap &= ~QH_MULT;
+       else
+               mEp->qh.ptr->cap &= ~QH_ZLT;
 
-               if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
-                       mEp->dir = (mEp->dir == TX) ? RX : TX;
+       mEp->qh.ptr->cap |=
+               (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
+       mEp->qh.ptr->td.next |= TD_TERMINATE;   /* needed? */
 
-       } while (mEp->dir != direction);
+       retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type);
 
        spin_unlock_irqrestore(mEp->lock, flags);
        return retval;
@@ -2146,7 +2154,7 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
        spin_lock_irqsave(mEp->lock, flags);
 
        if (mEp->type == USB_ENDPOINT_XFER_CONTROL &&
-           !list_empty(&mEp->qh[mEp->dir].queue)) {
+           !list_empty(&mEp->qh.queue)) {
                _ep_nuke(mEp);
                retval = -EOVERFLOW;
                warn("endpoint ctrl %X nuked", _usb_addr(mEp));
@@ -2170,9 +2178,9 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
        /* push request */
        mReq->req.status = -EINPROGRESS;
        mReq->req.actual = 0;
-       list_add_tail(&mReq->queue, &mEp->qh[mEp->dir].queue);
+       list_add_tail(&mReq->queue, &mEp->qh.queue);
 
-       if (list_is_singular(&mEp->qh[mEp->dir].queue))
+       if (list_is_singular(&mEp->qh.queue))
                retval = _hardware_enqueue(mEp, mReq);
 
        if (retval == -EALREADY) {
@@ -2199,7 +2207,7 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
        trace("%p, %p", ep, req);
 
        if (ep == NULL || req == NULL || mEp->desc == NULL ||
-           list_empty(&mReq->queue)  || list_empty(&mEp->qh[mEp->dir].queue))
+           list_empty(&mReq->queue)  || list_empty(&mEp->qh.queue))
                return -EINVAL;
 
        spin_lock_irqsave(mEp->lock, flags);
@@ -2244,7 +2252,7 @@ static int ep_set_halt(struct usb_ep *ep, int value)
 #ifndef STALL_IN
        /* g_file_storage MS compliant but g_zero fails chapter 9 compliance */
        if (value && mEp->type == USB_ENDPOINT_XFER_BULK && mEp->dir == TX &&
-           !list_empty(&mEp->qh[mEp->dir].queue)) {
+           !list_empty(&mEp->qh.queue)) {
                spin_unlock_irqrestore(mEp->lock, flags);
                return -EAGAIN;
        }
@@ -2355,7 +2363,7 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
                if (is_active) {
                        pm_runtime_get_sync(&_gadget->dev);
                        hw_device_reset(udc);
-                       hw_device_state(udc->ci13xxx_ep[0].qh[RX].dma);
+                       hw_device_state(udc->ep0out.qh.dma);
                } else {
                        hw_device_state(0);
                        if (udc->udc_driver->notify_event)
@@ -2390,7 +2398,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
                int (*bind)(struct usb_gadget *))
 {
        struct ci13xxx *udc = _udc;
-       unsigned long i, k, flags;
+       unsigned long flags;
+       int i, j;
        int retval = -ENOMEM;
 
        trace("%p", driver);
@@ -2427,45 +2436,46 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 
        info("hw_ep_max = %d", hw_ep_max);
 
-       udc->driver = driver;
        udc->gadget.dev.driver = NULL;
 
        retval = 0;
-       for (i = 0; i < hw_ep_max; i++) {
-               struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
+       for (i = 0; i < hw_ep_max/2; i++) {
+               for (j = RX; j <= TX; j++) {
+                       int k = i + j * hw_ep_max/2;
+                       struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k];
 
-               scnprintf(mEp->name, sizeof(mEp->name), "ep%i", (int)i);
+                       scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i,
+                                       (j == TX)  ? "in" : "out");
 
-               mEp->lock         = udc->lock;
-               mEp->device       = &udc->gadget.dev;
-               mEp->td_pool      = udc->td_pool;
+                       mEp->lock         = udc->lock;
+                       mEp->device       = &udc->gadget.dev;
+                       mEp->td_pool      = udc->td_pool;
 
-               mEp->ep.name      = mEp->name;
-               mEp->ep.ops       = &usb_ep_ops;
-               mEp->ep.maxpacket = CTRL_PAYLOAD_MAX;
+                       mEp->ep.name      = mEp->name;
+                       mEp->ep.ops       = &usb_ep_ops;
+                       mEp->ep.maxpacket = CTRL_PAYLOAD_MAX;
 
-               /* this allocation cannot be random */
-               for (k = RX; k <= TX; k++) {
-                       INIT_LIST_HEAD(&mEp->qh[k].queue);
+                       INIT_LIST_HEAD(&mEp->qh.queue);
                        spin_unlock_irqrestore(udc->lock, flags);
-                       mEp->qh[k].ptr = dma_pool_alloc(udc->qh_pool,
-                                                       GFP_KERNEL,
-                                                       &mEp->qh[k].dma);
+                       mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL,
+                                       &mEp->qh.dma);
                        spin_lock_irqsave(udc->lock, flags);
-                       if (mEp->qh[k].ptr == NULL)
+                       if (mEp->qh.ptr == NULL)
                                retval = -ENOMEM;
                        else
-                               memset(mEp->qh[k].ptr, 0,
-                                      sizeof(*mEp->qh[k].ptr));
-               }
-               if (i == 0)
-                       udc->gadget.ep0 = &mEp->ep;
-               else
+                               memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr));
+
+                       /* skip ep0 out and in endpoints */
+                       if (i == 0)
+                               continue;
+
                        list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list);
+               }
        }
        if (retval)
                goto done;
 
+       udc->gadget.ep0 = &udc->ep0in.ep;
        /* bind gadget */
        driver->driver.bus     = NULL;
        udc->gadget.dev.driver = &driver->driver;
@@ -2479,6 +2489,7 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
                goto done;
        }
 
+       udc->driver = driver;
        pm_runtime_get_sync(&udc->gadget.dev);
        if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) {
                if (udc->vbus_active) {
@@ -2490,14 +2501,12 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
                }
        }
 
-       retval = hw_device_state(udc->ci13xxx_ep[0].qh[RX].dma);
+       retval = hw_device_state(udc->ep0out.qh.dma);
        if (retval)
                pm_runtime_put_sync(&udc->gadget.dev);
 
  done:
        spin_unlock_irqrestore(udc->lock, flags);
-       if (retval)
-               usb_gadget_unregister_driver(driver);
        return retval;
 }
 EXPORT_SYMBOL(usb_gadget_probe_driver);
@@ -2510,7 +2519,7 @@ EXPORT_SYMBOL(usb_gadget_probe_driver);
 int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 {
        struct ci13xxx *udc = _udc;
-       unsigned long i, k, flags;
+       unsigned long i, flags;
 
        trace("%p", driver);
 
@@ -2546,17 +2555,14 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
        for (i = 0; i < hw_ep_max; i++) {
                struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
 
-               if (i == 0)
-                       udc->gadget.ep0 = NULL;
-               else if (!list_empty(&mEp->ep.ep_list))
+               if (!list_empty(&mEp->ep.ep_list))
                        list_del_init(&mEp->ep.ep_list);
 
-               for (k = RX; k <= TX; k++)
-                       if (mEp->qh[k].ptr != NULL)
-                               dma_pool_free(udc->qh_pool,
-                                             mEp->qh[k].ptr, mEp->qh[k].dma);
+               if (mEp->qh.ptr != NULL)
+                       dma_pool_free(udc->qh_pool, mEp->qh.ptr, mEp->qh.dma);
        }
 
+       udc->gadget.ep0 = NULL;
        udc->driver = NULL;
 
        spin_unlock_irqrestore(udc->lock, flags);
index f61fed0..a2492b6 100644 (file)
@@ -20,7 +20,7 @@
  * DEFINE
  *****************************************************************************/
 #define CI13XXX_PAGE_SIZE  4096ul /* page size for TD's */
-#define ENDPT_MAX          (16)
+#define ENDPT_MAX          (32)
 #define CTRL_PAYLOAD_MAX   (64)
 #define RX        (0)  /* similar to USB_DIR_OUT but can be used as an index */
 #define TX        (1)  /* similar to USB_DIR_IN  but can be used as an index */
@@ -88,8 +88,7 @@ struct ci13xxx_ep {
                struct list_head   queue;
                struct ci13xxx_qh *ptr;
                dma_addr_t         dma;
-       }                                      qh[2];
-       struct usb_request                    *status;
+       }                                      qh;
        int                                    wedge;
 
        /* global resources */
@@ -119,9 +118,13 @@ struct ci13xxx {
 
        struct dma_pool           *qh_pool;   /* DMA pool for queue heads */
        struct dma_pool           *td_pool;   /* DMA pool for transfer descs */
+       struct usb_request        *status;    /* ep0 status request */
 
        struct usb_gadget          gadget;     /* USB slave device */
        struct ci13xxx_ep          ci13xxx_ep[ENDPT_MAX]; /* extended endpts */
+       u32                        ep0_dir;    /* ep0 direction */
+#define ep0out ci13xxx_ep[0]
+#define ep0in  ci13xxx_ep[16]
 
        struct usb_gadget_driver  *driver;     /* 3rd party gadget driver */
        struct ci13xxx_udc_driver *udc_driver; /* device controller driver */
index f6ff845..1ba4bef 100644 (file)
@@ -928,8 +928,9 @@ unknown:
                 */
                switch (ctrl->bRequestType & USB_RECIP_MASK) {
                case USB_RECIP_INTERFACE:
-                       if (cdev->config)
-                               f = cdev->config->interface[intf];
+                       if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES)
+                               break;
+                       f = cdev->config->interface[intf];
                        break;
 
                case USB_RECIP_ENDPOINT:
index b5dbb23..6d8e533 100644 (file)
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/composite.h>
 
 #include "gadget_chips.h"
 
@@ -2763,7 +2764,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
                        return ERR_PTR(-ENOMEM);
                common->free_storage_on_release = 1;
        } else {
-               memset(common, 0, sizeof common);
+               memset(common, 0, sizeof *common);
                common->free_storage_on_release = 0;
        }
 
index 3c6e1a0..5e14950 100644 (file)
@@ -346,14 +346,19 @@ static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req)
 
                if (unlikely(!skb))
                        break;
-               skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, 0,
-                               req->actual);
-               page = NULL;
 
-               if (req->actual < req->length) { /* Last fragment */
+               if (skb->len == 0) { /* First fragment */
                        skb->protocol = htons(ETH_P_PHONET);
                        skb_reset_mac_header(skb);
-                       pskb_pull(skb, 1);
+                       /* Can't use pskb_pull() on page in IRQ */
+                       memcpy(skb_put(skb, 1), page_address(page), 1);
+               }
+
+               skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
+                               skb->len == 0, req->actual);
+               page = NULL;
+
+               if (req->actual < req->length) { /* Last fragment */
                        skb->dev = dev;
                        dev->stats.rx_packets++;
                        dev->stats.rx_bytes += skb->len;
index 0c8dd81..b120dbb 100644 (file)
 #define PCH_UDC_BRLEN          0x0F    /* Burst length */
 #define PCH_UDC_THLEN          0x1F    /* Threshold length */
 /* Value of EP Buffer Size */
-#define UDC_EP0IN_BUFF_SIZE    64
-#define UDC_EPIN_BUFF_SIZE     512
-#define UDC_EP0OUT_BUFF_SIZE   64
-#define UDC_EPOUT_BUFF_SIZE    512
+#define UDC_EP0IN_BUFF_SIZE    16
+#define UDC_EPIN_BUFF_SIZE     256
+#define UDC_EP0OUT_BUFF_SIZE   16
+#define UDC_EPOUT_BUFF_SIZE    256
 /* Value of EP maximum packet size */
 #define UDC_EP0IN_MAX_PKT_SIZE 64
 #define UDC_EP0OUT_MAX_PKT_SIZE        64
@@ -351,7 +351,7 @@ struct pch_udc_dev {
        struct pci_pool         *data_requests;
        struct pci_pool         *stp_requests;
        dma_addr_t                      dma_addr;
-       unsigned long                   ep0out_buf[64];
+       void                            *ep0out_buf;
        struct usb_ctrlrequest          setup_data;
        unsigned long                   phys_addr;
        void __iomem                    *base_addr;
@@ -361,6 +361,8 @@ struct pch_udc_dev {
 
 #define PCH_UDC_PCI_BAR                        1
 #define PCI_DEVICE_ID_INTEL_EG20T_UDC  0x8808
+#define PCI_VENDOR_ID_ROHM             0x10DB
+#define PCI_DEVICE_ID_ML7213_IOH_UDC   0x801D
 
 static const char      ep0_string[] = "ep0in";
 static DEFINE_SPINLOCK(udc_stall_spinlock);    /* stall spin lock */
@@ -1219,11 +1221,11 @@ static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req,
        dev = ep->dev;
        if (req->dma_mapped) {
                if (ep->in)
-                       pci_unmap_single(dev->pdev, req->req.dma,
-                                        req->req.length, PCI_DMA_TODEVICE);
+                       dma_unmap_single(&dev->pdev->dev, req->req.dma,
+                                        req->req.length, DMA_TO_DEVICE);
                else
-                       pci_unmap_single(dev->pdev, req->req.dma,
-                                        req->req.length, PCI_DMA_FROMDEVICE);
+                       dma_unmap_single(&dev->pdev->dev, req->req.dma,
+                                        req->req.length, DMA_FROM_DEVICE);
                req->dma_mapped = 0;
                req->req.dma = DMA_ADDR_INVALID;
        }
@@ -1414,7 +1416,6 @@ static void pch_udc_start_rxrequest(struct pch_udc_ep *ep,
 
        pch_udc_clear_dma(ep->dev, DMA_DIR_RX);
        td_data = req->td_data;
-       ep->td_data = req->td_data;
        /* Set the status bits for all descriptors */
        while (1) {
                td_data->status = (td_data->status & ~PCH_UDC_BUFF_STS) |
@@ -1613,15 +1614,19 @@ static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq,
        if (usbreq->length &&
            ((usbreq->dma == DMA_ADDR_INVALID) || !usbreq->dma)) {
                if (ep->in)
-                       usbreq->dma = pci_map_single(dev->pdev, usbreq->buf,
-                                       usbreq->length, PCI_DMA_TODEVICE);
+                       usbreq->dma = dma_map_single(&dev->pdev->dev,
+                                                    usbreq->buf,
+                                                    usbreq->length,
+                                                    DMA_TO_DEVICE);
                else
-                       usbreq->dma = pci_map_single(dev->pdev, usbreq->buf,
-                                       usbreq->length, PCI_DMA_FROMDEVICE);
+                       usbreq->dma = dma_map_single(&dev->pdev->dev,
+                                                    usbreq->buf,
+                                                    usbreq->length,
+                                                    DMA_FROM_DEVICE);
                req->dma_mapped = 1;
        }
        if (usbreq->length > 0) {
-               retval = prepare_dma(ep, req, gfp);
+               retval = prepare_dma(ep, req, GFP_ATOMIC);
                if (retval)
                        goto probe_end;
        }
@@ -1646,7 +1651,6 @@ static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq,
                        pch_udc_wait_ep_stall(ep);
                        pch_udc_ep_clear_nak(ep);
                        pch_udc_enable_ep_interrupts(ep->dev, (1 << ep->num));
-                       pch_udc_set_dma(dev, DMA_DIR_TX);
                }
        }
        /* Now add this request to the ep's pending requests */
@@ -1926,6 +1930,7 @@ static void pch_udc_complete_receiver(struct pch_udc_ep *ep)
            PCH_UDC_BS_DMA_DONE)
                return;
        pch_udc_clear_dma(ep->dev, DMA_DIR_RX);
+       pch_udc_ep_set_ddptr(ep, 0);
        if ((req->td_data_last->status & PCH_UDC_RXTX_STS) !=
            PCH_UDC_RTS_SUCC) {
                dev_err(&dev->pdev->dev, "Invalid RXTX status (0x%08x) "
@@ -1963,7 +1968,7 @@ static void pch_udc_svc_data_in(struct pch_udc_dev *dev, int ep_num)
        u32     epsts;
        struct pch_udc_ep       *ep;
 
-       ep = &dev->ep[2*ep_num];
+       ep = &dev->ep[UDC_EPIN_IDX(ep_num)];
        epsts = ep->epsts;
        ep->epsts = 0;
 
@@ -2008,7 +2013,7 @@ static void pch_udc_svc_data_out(struct pch_udc_dev *dev, int ep_num)
        struct pch_udc_ep               *ep;
        struct pch_udc_request          *req = NULL;
 
-       ep = &dev->ep[2*ep_num + 1];
+       ep = &dev->ep[UDC_EPOUT_IDX(ep_num)];
        epsts = ep->epsts;
        ep->epsts = 0;
 
@@ -2025,10 +2030,11 @@ static void pch_udc_svc_data_out(struct pch_udc_dev *dev, int ep_num)
        }
        if (epsts & UDC_EPSTS_HE)
                return;
-       if (epsts & UDC_EPSTS_RSS)
+       if (epsts & UDC_EPSTS_RSS) {
                pch_udc_ep_set_stall(ep);
                pch_udc_enable_ep_interrupts(ep->dev,
                                             PCH_UDC_EPINT(ep->in, ep->num));
+       }
        if (epsts & UDC_EPSTS_RCS) {
                if (!dev->prot_stall) {
                        pch_udc_ep_clear_stall(ep);
@@ -2060,8 +2066,10 @@ static void pch_udc_svc_control_in(struct pch_udc_dev *dev)
 {
        u32     epsts;
        struct pch_udc_ep       *ep;
+       struct pch_udc_ep       *ep_out;
 
        ep = &dev->ep[UDC_EP0IN_IDX];
+       ep_out = &dev->ep[UDC_EP0OUT_IDX];
        epsts = ep->epsts;
        ep->epsts = 0;
 
@@ -2073,8 +2081,16 @@ static void pch_udc_svc_control_in(struct pch_udc_dev *dev)
                return;
        if (epsts & UDC_EPSTS_HE)
                return;
-       if ((epsts & UDC_EPSTS_TDC) && (!dev->stall))
+       if ((epsts & UDC_EPSTS_TDC) && (!dev->stall)) {
                pch_udc_complete_transfer(ep);
+               pch_udc_clear_dma(dev, DMA_DIR_RX);
+               ep_out->td_data->status = (ep_out->td_data->status &
+                                       ~PCH_UDC_BUFF_STS) |
+                                       PCH_UDC_BS_HST_RDY;
+               pch_udc_ep_clear_nak(ep_out);
+               pch_udc_set_dma(dev, DMA_DIR_RX);
+               pch_udc_ep_set_rrdy(ep_out);
+       }
        /* On IN interrupt, provide data if we have any */
        if ((epsts & UDC_EPSTS_IN) && !(epsts & UDC_EPSTS_TDC) &&
             !(epsts & UDC_EPSTS_TXEMPTY))
@@ -2102,11 +2118,9 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev)
                dev->stall = 0;
                dev->ep[UDC_EP0IN_IDX].halted = 0;
                dev->ep[UDC_EP0OUT_IDX].halted = 0;
-               /* In data not ready */
-               pch_udc_ep_set_nak(&(dev->ep[UDC_EP0IN_IDX]));
                dev->setup_data = ep->td_stp->request;
                pch_udc_init_setup_buff(ep->td_stp);
-               pch_udc_clear_dma(dev, DMA_DIR_TX);
+               pch_udc_clear_dma(dev, DMA_DIR_RX);
                pch_udc_ep_fifo_flush(&(dev->ep[UDC_EP0IN_IDX]),
                                      dev->ep[UDC_EP0IN_IDX].in);
                if ((dev->setup_data.bRequestType & USB_DIR_IN))
@@ -2122,14 +2136,23 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev)
                setup_supported = dev->driver->setup(&dev->gadget,
                                                     &dev->setup_data);
                spin_lock(&dev->lock);
+
+               if (dev->setup_data.bRequestType & USB_DIR_IN) {
+                       ep->td_data->status = (ep->td_data->status &
+                                               ~PCH_UDC_BUFF_STS) |
+                                               PCH_UDC_BS_HST_RDY;
+                       pch_udc_ep_set_ddptr(ep, ep->td_data_phys);
+               }
                /* ep0 in returns data on IN phase */
                if (setup_supported >= 0 && setup_supported <
                                            UDC_EP0IN_MAX_PKT_SIZE) {
                        pch_udc_ep_clear_nak(&(dev->ep[UDC_EP0IN_IDX]));
                        /* Gadget would have queued a request when
                         * we called the setup */
-                       pch_udc_set_dma(dev, DMA_DIR_RX);
-                       pch_udc_ep_clear_nak(ep);
+                       if (!(dev->setup_data.bRequestType & USB_DIR_IN)) {
+                               pch_udc_set_dma(dev, DMA_DIR_RX);
+                               pch_udc_ep_clear_nak(ep);
+                       }
                } else if (setup_supported < 0) {
                        /* if unsupported request, then stall */
                        pch_udc_ep_set_stall(&(dev->ep[UDC_EP0IN_IDX]));
@@ -2142,22 +2165,13 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev)
                }
        } else if ((((stat & UDC_EPSTS_OUT_MASK) >> UDC_EPSTS_OUT_SHIFT) ==
                     UDC_EPSTS_OUT_DATA) && !dev->stall) {
-               if (list_empty(&ep->queue)) {
-                       dev_err(&dev->pdev->dev, "%s: No request\n", __func__);
-                       ep->td_data->status = (ep->td_data->status &
-                                              ~PCH_UDC_BUFF_STS) |
-                                              PCH_UDC_BS_HST_RDY;
-                       pch_udc_set_dma(dev, DMA_DIR_RX);
-               } else {
-                       /* control write */
-                       /* next function will pickuo an clear the status */
+               pch_udc_clear_dma(dev, DMA_DIR_RX);
+               pch_udc_ep_set_ddptr(ep, 0);
+               if (!list_empty(&ep->queue)) {
                        ep->epsts = stat;
-
-                       pch_udc_svc_data_out(dev, 0);
-                       /* re-program desc. pointer for possible ZLPs */
-                       pch_udc_ep_set_ddptr(ep, ep->td_data_phys);
-                       pch_udc_set_dma(dev, DMA_DIR_RX);
+                       pch_udc_svc_data_out(dev, PCH_UDC_EP0);
                }
+               pch_udc_set_dma(dev, DMA_DIR_RX);
        }
        pch_udc_ep_set_rrdy(ep);
 }
@@ -2174,7 +2188,7 @@ static void pch_udc_postsvc_epinters(struct pch_udc_dev *dev, int ep_num)
        struct pch_udc_ep       *ep;
        struct pch_udc_request *req;
 
-       ep = &dev->ep[2*ep_num];
+       ep = &dev->ep[UDC_EPIN_IDX(ep_num)];
        if (!list_empty(&ep->queue)) {
                req = list_entry(ep->queue.next, struct pch_udc_request, queue);
                pch_udc_enable_ep_interrupts(ep->dev,
@@ -2196,13 +2210,13 @@ static void pch_udc_read_all_epstatus(struct pch_udc_dev *dev, u32 ep_intr)
        for (i = 0; i < PCH_UDC_USED_EP_NUM; i++) {
                /* IN */
                if (ep_intr & (0x1 << i)) {
-                       ep = &dev->ep[2*i];
+                       ep = &dev->ep[UDC_EPIN_IDX(i)];
                        ep->epsts = pch_udc_read_ep_status(ep);
                        pch_udc_clear_ep_status(ep, ep->epsts);
                }
                /* OUT */
                if (ep_intr & (0x10000 << i)) {
-                       ep = &dev->ep[2*i+1];
+                       ep = &dev->ep[UDC_EPOUT_IDX(i)];
                        ep->epsts = pch_udc_read_ep_status(ep);
                        pch_udc_clear_ep_status(ep, ep->epsts);
                }
@@ -2563,9 +2577,6 @@ static void pch_udc_pcd_reinit(struct pch_udc_dev *dev)
        dev->ep[UDC_EP0IN_IDX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE;
        dev->ep[UDC_EP0OUT_IDX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE;
 
-       dev->dma_addr = pci_map_single(dev->pdev, dev->ep0out_buf, 256,
-                                 PCI_DMA_FROMDEVICE);
-
        /* remove ep0 in and out from the list.  They have own pointer */
        list_del_init(&dev->ep[UDC_EP0IN_IDX].ep.ep_list);
        list_del_init(&dev->ep[UDC_EP0OUT_IDX].ep.ep_list);
@@ -2637,6 +2648,13 @@ static int init_dma_pools(struct pch_udc_dev *dev)
        dev->ep[UDC_EP0IN_IDX].td_stp_phys = 0;
        dev->ep[UDC_EP0IN_IDX].td_data = NULL;
        dev->ep[UDC_EP0IN_IDX].td_data_phys = 0;
+
+       dev->ep0out_buf = kzalloc(UDC_EP0OUT_BUFF_SIZE * 4, GFP_KERNEL);
+       if (!dev->ep0out_buf)
+               return -ENOMEM;
+       dev->dma_addr = dma_map_single(&dev->pdev->dev, dev->ep0out_buf,
+                                      UDC_EP0OUT_BUFF_SIZE * 4,
+                                      DMA_FROM_DEVICE);
        return 0;
 }
 
@@ -2700,7 +2718,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 
        pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK);
 
-       /* Assues that there are no pending requets with this driver */
+       /* Assures that there are no pending requests with this driver */
+       driver->disconnect(&dev->gadget);
        driver->unbind(&dev->gadget);
        dev->gadget.dev.driver = NULL;
        dev->driver = NULL;
@@ -2750,6 +2769,11 @@ static void pch_udc_remove(struct pci_dev *pdev)
                pci_pool_destroy(dev->stp_requests);
        }
 
+       if (dev->dma_addr)
+               dma_unmap_single(&dev->pdev->dev, dev->dma_addr,
+                                UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE);
+       kfree(dev->ep0out_buf);
+
        pch_udc_exit(dev);
 
        if (dev->irq_registered)
@@ -2792,11 +2816,7 @@ static int pch_udc_resume(struct pci_dev *pdev)
        int ret;
 
        pci_set_power_state(pdev, PCI_D0);
-       ret = pci_restore_state(pdev);
-       if (ret) {
-               dev_err(&pdev->dev, "%s: pci_restore_state failed\n", __func__);
-               return ret;
-       }
+       pci_restore_state(pdev);
        ret = pci_enable_device(pdev);
        if (ret) {
                dev_err(&pdev->dev, "%s: pci_enable_device failed\n", __func__);
@@ -2914,6 +2934,11 @@ static DEFINE_PCI_DEVICE_TABLE(pch_udc_pcidev_id) = {
                .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
                .class_mask = 0xffffffff,
        },
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_ROHM, PCI_DEVICE_ID_ML7213_IOH_UDC),
+               .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
+               .class_mask = 0xffffffff,
+       },
        { 0 },
 };
 
index 2fc8636..12ff6cf 100644 (file)
@@ -131,31 +131,31 @@ static struct printer_dev usb_printer_gadget;
  * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
  */
 
-static ushort __initdata idVendor;
+static ushort idVendor;
 module_param(idVendor, ushort, S_IRUGO);
 MODULE_PARM_DESC(idVendor, "USB Vendor ID");
 
-static ushort __initdata idProduct;
+static ushort idProduct;
 module_param(idProduct, ushort, S_IRUGO);
 MODULE_PARM_DESC(idProduct, "USB Product ID");
 
-static ushort __initdata bcdDevice;
+static ushort bcdDevice;
 module_param(bcdDevice, ushort, S_IRUGO);
 MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
 
-static char *__initdata iManufacturer;
+static char *iManufacturer;
 module_param(iManufacturer, charp, S_IRUGO);
 MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
 
-static char *__initdata iProduct;
+static char *iProduct;
 module_param(iProduct, charp, S_IRUGO);
 MODULE_PARM_DESC(iProduct, "USB Product string");
 
-static char *__initdata iSerialNum;
+static char *iSerialNum;
 module_param(iSerialNum, charp, S_IRUGO);
 MODULE_PARM_DESC(iSerialNum, "1");
 
-static char *__initdata iPNPstring;
+static char *iPNPstring;
 module_param(iPNPstring, charp, S_IRUGO);
 MODULE_PARM_DESC(iPNPstring, "MFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;");
 
@@ -1596,13 +1596,12 @@ cleanup(void)
        int status;
 
        mutex_lock(&usb_printer_gadget.lock_printer_io);
-       class_destroy(usb_gadget_class);
-       unregister_chrdev_region(g_printer_devno, 2);
-
        status = usb_gadget_unregister_driver(&printer_driver);
        if (status)
                ERROR(dev, "usb_gadget_unregister_driver %x\n", status);
 
+       unregister_chrdev_region(g_printer_devno, 2);
+       class_destroy(usb_gadget_class);
        mutex_unlock(&usb_printer_gadget.lock_printer_io);
 }
 module_exit(cleanup);
index 20d43da..0151185 100644 (file)
@@ -258,7 +258,7 @@ static int pipe_buffer_setting(struct r8a66597 *r8a66597,
                break;
        case R8A66597_BULK:
                /* isochronous pipes may be used as bulk pipes */
-               if (info->pipe > R8A66597_BASE_PIPENUM_BULK)
+               if (info->pipe >= R8A66597_BASE_PIPENUM_BULK)
                        bufnum = info->pipe - R8A66597_BASE_PIPENUM_BULK;
                else
                        bufnum = info->pipe - R8A66597_BASE_PIPENUM_ISOC;
index 24046c0..0e6afa2 100644 (file)
@@ -151,6 +151,8 @@ config USB_EHCI_MSM
          Qualcomm chipsets. Root Hub has inbuilt TT.
          This driver depends on OTG driver for PHY initialization,
          clock management, powering up VBUS, and power management.
+         This driver is not supported on boards like trout which
+         has an external PHY.
 
 config USB_EHCI_HCD_PPC_OF
        bool "EHCI support for PPC USB controller on OF platform bus"
index 2baf8a8..a869e3c 100644 (file)
@@ -227,8 +227,8 @@ static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
         * mark HW unaccessible.  The PM and USB cores make sure that
         * the root hub is either suspended or stopped.
         */
-       spin_lock_irqsave(&ehci->lock, flags);
        ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
+       spin_lock_irqsave(&ehci->lock, flags);
        ehci_writel(ehci, 0, &ehci->regs->intr_enable);
        (void)ehci_readl(ehci, &ehci->regs->intr_enable);
 
index 86e4289..5c761df 100644 (file)
@@ -52,7 +52,6 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
        struct resource *res;
        int irq;
        int retval;
-       unsigned int temp;
 
        pr_debug("initializing FSL-SOC USB Controller\n");
 
@@ -126,18 +125,6 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
                goto err3;
        }
 
-       /*
-        * Check if it is MPC5121 SoC, otherwise set pdata->have_sysif_regs
-        * flag for 83xx or 8536 system interface registers.
-        */
-       if (pdata->big_endian_mmio)
-               temp = in_be32(hcd->regs + FSL_SOC_USB_ID);
-       else
-               temp = in_le32(hcd->regs + FSL_SOC_USB_ID);
-
-       if ((temp & ID_MSK) != (~((temp & NID_MSK) >> 8) & ID_MSK))
-               pdata->have_sysif_regs = 1;
-
        /* Enable USB controller, 83xx or 8536 */
        if (pdata->have_sysif_regs)
                setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4);
index 2c83537..3fabed3 100644 (file)
@@ -19,9 +19,6 @@
 #define _EHCI_FSL_H
 
 /* offsets for the non-ehci registers in the FSL SOC USB controller */
-#define FSL_SOC_USB_ID         0x0
-#define ID_MSK                 0x3f
-#define NID_MSK                        0x3f00
 #define FSL_SOC_USB_ULPIVP     0x170
 #define FSL_SOC_USB_PORTSC1    0x184
 #define PORT_PTS_MSK           (3<<30)
index 6fee3cd..74dcf49 100644 (file)
@@ -572,6 +572,8 @@ static int ehci_init(struct usb_hcd *hcd)
        ehci->iaa_watchdog.function = ehci_iaa_watchdog;
        ehci->iaa_watchdog.data = (unsigned long) ehci;
 
+       hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
+
        /*
         * hw default: 1K periodic list heads, one per frame.
         * periodic_size can shrink by USBCMD update if hcc_params allows.
@@ -579,11 +581,20 @@ static int ehci_init(struct usb_hcd *hcd)
        ehci->periodic_size = DEFAULT_I_TDPS;
        INIT_LIST_HEAD(&ehci->cached_itd_list);
        INIT_LIST_HEAD(&ehci->cached_sitd_list);
+
+       if (HCC_PGM_FRAMELISTLEN(hcc_params)) {
+               /* periodic schedule size can be smaller than default */
+               switch (EHCI_TUNE_FLS) {
+               case 0: ehci->periodic_size = 1024; break;
+               case 1: ehci->periodic_size = 512; break;
+               case 2: ehci->periodic_size = 256; break;
+               default:        BUG();
+               }
+       }
        if ((retval = ehci_mem_init(ehci, GFP_KERNEL)) < 0)
                return retval;
 
        /* controllers may cache some of the periodic schedule ... */
-       hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
        if (HCC_ISOC_CACHE(hcc_params))         // full frame cache
                ehci->i_thresh = 2 + 8;
        else                                    // N microframes cached
@@ -637,12 +648,6 @@ static int ehci_init(struct usb_hcd *hcd)
                /* periodic schedule size can be smaller than default */
                temp &= ~(3 << 2);
                temp |= (EHCI_TUNE_FLS << 2);
-               switch (EHCI_TUNE_FLS) {
-               case 0: ehci->periodic_size = 1024; break;
-               case 1: ehci->periodic_size = 512; break;
-               case 2: ehci->periodic_size = 256; break;
-               default:        BUG();
-               }
        }
        if (HCC_LPM(hcc_params)) {
                /* support link power management EHCI 1.1 addendum */
index 796ea0c..8a515f0 100644 (file)
@@ -111,6 +111,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
 {
        int             port;
        u32             temp;
+       unsigned long   flags;
 
        /* If remote wakeup is enabled for the root hub but disabled
         * for the controller, we must adjust all the port wakeup flags
@@ -120,6 +121,8 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
        if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup || do_wakeup)
                return;
 
+       spin_lock_irqsave(&ehci->lock, flags);
+
        /* clear phy low-power mode before changing wakeup flags */
        if (ehci->has_hostpc) {
                port = HCS_N_PORTS(ehci->hcs_params);
@@ -131,7 +134,9 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
                        temp = ehci_readl(ehci, hostpc_reg);
                        ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg);
                }
+               spin_unlock_irqrestore(&ehci->lock, flags);
                msleep(5);
+               spin_lock_irqsave(&ehci->lock, flags);
        }
 
        port = HCS_N_PORTS(ehci->hcs_params);
@@ -170,6 +175,8 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
        /* Does the root hub have a port wakeup pending? */
        if (!suspending && (ehci_readl(ehci, &ehci->regs->status) & STS_PCD))
                usb_hcd_resume_root_hub(ehci_to_hcd(ehci));
+
+       spin_unlock_irqrestore(&ehci->lock, flags);
 }
 
 static int ehci_bus_suspend (struct usb_hcd *hcd)
index fa59b26..c8e360d 100644 (file)
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
 #include <linux/slab.h>
 
 #include <mach/mxc_ehci.h>
 
+#include <asm/mach-types.h>
+
 #define ULPI_VIEWPORT_OFFSET   0x170
 
 struct ehci_mxc_priv {
@@ -114,6 +117,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
        struct usb_hcd *hcd;
        struct resource *res;
        int irq, ret;
+       unsigned int flags;
        struct ehci_mxc_priv *priv;
        struct device *dev = &pdev->dev;
        struct ehci_hcd *ehci;
@@ -177,8 +181,8 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
                clk_enable(priv->ahbclk);
        }
 
-       /* "dr" device has its own clock */
-       if (pdev->id == 0) {
+       /* "dr" device has its own clock on i.MX51 */
+       if (cpu_is_mx51() && (pdev->id == 0)) {
                priv->phy1clk = clk_get(dev, "usb_phy1");
                if (IS_ERR(priv->phy1clk)) {
                        ret = PTR_ERR(priv->phy1clk);
@@ -240,6 +244,23 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
        if (ret)
                goto err_add;
 
+       if (pdata->otg) {
+               /*
+                * efikamx and efikasb have some hardware bug which is
+                * preventing usb to work unless CHRGVBUS is set.
+                * It's in violation of USB specs
+                */
+               if (machine_is_mx51_efikamx() || machine_is_mx51_efikasb()) {
+                       flags = otg_io_read(pdata->otg, ULPI_OTG_CTRL);
+                       flags |= ULPI_OTG_CTRL_CHRGVBUS;
+                       ret = otg_io_write(pdata->otg, flags, ULPI_OTG_CTRL);
+                       if (ret) {
+                               dev_err(dev, "unable to set CHRVBUS\n");
+                               goto err_add;
+                       }
+               }
+       }
+
        return 0;
 
 err_add:
index 680f2ef..f784ceb 100644 (file)
@@ -796,7 +796,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
        hcd = usb_create_hcd(&ehci_omap_hc_driver, &pdev->dev,
                        dev_name(&pdev->dev));
        if (!hcd) {
-               dev_dbg(&pdev->dev, "failed to create hcd with err %d\n", ret);
+               dev_err(&pdev->dev, "failed to create hcd with err %d\n", ret);
                ret = -ENOMEM;
                goto err_create_hcd;
        }
@@ -864,7 +864,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
 
        ret = omap_start_ehc(omap, hcd);
        if (ret) {
-               dev_dbg(&pdev->dev, "failed to start ehci\n");
+               dev_err(&pdev->dev, "failed to start ehci with err %d\n", ret);
                goto err_start;
        }
 
@@ -879,7 +879,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
 
        ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
        if (ret) {
-               dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
+               dev_err(&pdev->dev, "failed to add hcd with err %d\n", ret);
                goto err_add_hcd;
        }
 
index 76179c3..07bb982 100644 (file)
@@ -44,28 +44,35 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
        return 0;
 }
 
-static int ehci_quirk_amd_SB800(struct ehci_hcd *ehci)
+static int ehci_quirk_amd_hudson(struct ehci_hcd *ehci)
 {
        struct pci_dev *amd_smbus_dev;
        u8 rev = 0;
 
        amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL);
-       if (!amd_smbus_dev)
-               return 0;
-
-       pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev);
-       if (rev < 0x40) {
-               pci_dev_put(amd_smbus_dev);
-               amd_smbus_dev = NULL;
-               return 0;
+       if (amd_smbus_dev) {
+               pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev);
+               if (rev < 0x40) {
+                       pci_dev_put(amd_smbus_dev);
+                       amd_smbus_dev = NULL;
+                       return 0;
+               }
+       } else {
+               amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x780b, NULL);
+               if (!amd_smbus_dev)
+                       return 0;
+               pci_read_config_byte(amd_smbus_dev, PCI_REVISION_ID, &rev);
+               if (rev < 0x11 || rev > 0x18) {
+                       pci_dev_put(amd_smbus_dev);
+                       amd_smbus_dev = NULL;
+                       return 0;
+               }
        }
 
        if (!amd_nb_dev)
                amd_nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1510, NULL);
-       if (!amd_nb_dev)
-               ehci_err(ehci, "QUIRK: unable to get AMD NB device\n");
 
-       ehci_info(ehci, "QUIRK: Enable AMD SB800 L1 fix\n");
+       ehci_info(ehci, "QUIRK: Enable exception for AMD Hudson ASPM\n");
 
        pci_dev_put(amd_smbus_dev);
        amd_smbus_dev = NULL;
@@ -131,7 +138,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
        /* cache this readonly data; minimize chip reads */
        ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
-       if (ehci_quirk_amd_SB800(ehci))
+       if (ehci_quirk_amd_hudson(ehci))
                ehci->amd_l1_fix = 1;
 
        retval = ehci_halt(ehci);
@@ -360,8 +367,8 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
         * mark HW unaccessible.  The PM and USB cores make sure that
         * the root hub is either suspended or stopped.
         */
-       spin_lock_irqsave (&ehci->lock, flags);
        ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup);
+       spin_lock_irqsave (&ehci->lock, flags);
        ehci_writel(ehci, 0, &ehci->regs->intr_enable);
        (void)ehci_readl(ehci, &ehci->regs->intr_enable);
 
index e8f4f36..a6f21b8 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <linux/of.h>
 #include <linux/of_platform.h>
+#include <linux/of_address.h>
 
 /**
  * ehci_xilinx_of_setup - Initialize the device for ehci_reset()
index 574b99e..79a66d6 100644 (file)
@@ -262,19 +262,24 @@ static void fsl_usb2_mpc5121_exit(struct platform_device *pdev)
        }
 }
 
-struct fsl_usb2_platform_data fsl_usb2_mpc5121_pd = {
+static struct fsl_usb2_platform_data fsl_usb2_mpc5121_pd = {
        .big_endian_desc = 1,
        .big_endian_mmio = 1,
        .es = 1,
+       .have_sysif_regs = 0,
        .le_setup_buf = 1,
        .init = fsl_usb2_mpc5121_init,
        .exit = fsl_usb2_mpc5121_exit,
 };
 #endif /* CONFIG_PPC_MPC512x */
 
+static struct fsl_usb2_platform_data fsl_usb2_mpc8xxx_pd = {
+       .have_sysif_regs = 1,
+};
+
 static const struct of_device_id fsl_usb2_mph_dr_of_match[] = {
-       { .compatible = "fsl-usb2-mph", },
-       { .compatible = "fsl-usb2-dr", },
+       { .compatible = "fsl-usb2-mph", .data = &fsl_usb2_mpc8xxx_pd, },
+       { .compatible = "fsl-usb2-dr", .data = &fsl_usb2_mpc8xxx_pd, },
 #ifdef CONFIG_PPC_MPC512x
        { .compatible = "fsl,mpc5121-usb2-dr", .data = &fsl_usb2_mpc5121_pd, },
 #endif
index 990f06b..2e9602a 100644 (file)
@@ -861,6 +861,7 @@ static int sl811h_urb_enqueue(
                        DBG("dev %d ep%d maxpacket %d\n",
                                udev->devnum, epnum, ep->maxpacket);
                        retval = -EINVAL;
+                       kfree(ep);
                        goto fail;
                }
 
index fcbf4ab..0231814 100644 (file)
@@ -169,9 +169,10 @@ static void xhci_print_ports(struct xhci_hcd *xhci)
        }
 }
 
-void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num)
+void xhci_print_ir_set(struct xhci_hcd *xhci, int set_num)
 {
-       void *addr;
+       struct xhci_intr_reg __iomem *ir_set = &xhci->run_regs->ir_set[set_num];
+       void __iomem *addr;
        u32 temp;
        u64 temp_64;
 
@@ -449,7 +450,7 @@ char *xhci_get_slot_state(struct xhci_hcd *xhci,
        }
 }
 
-void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx)
+static void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx)
 {
        /* Fields are 32 bits wide, DMA addresses are in bytes */
        int field_size = 32 / 8;
@@ -488,7 +489,7 @@ void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx)
                dbg_rsvd64(xhci, (u64 *)slot_ctx, dma);
 }
 
-void xhci_dbg_ep_ctx(struct xhci_hcd *xhci,
+static void xhci_dbg_ep_ctx(struct xhci_hcd *xhci,
                     struct xhci_container_ctx *ctx,
                     unsigned int last_ep)
 {
index 1d0f45f..a953439 100644 (file)
@@ -307,7 +307,7 @@ struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci,
 
 /***************** Streams structures manipulation *************************/
 
-void xhci_free_stream_ctx(struct xhci_hcd *xhci,
+static void xhci_free_stream_ctx(struct xhci_hcd *xhci,
                unsigned int num_stream_ctxs,
                struct xhci_stream_ctx *stream_ctx, dma_addr_t dma)
 {
@@ -335,7 +335,7 @@ void xhci_free_stream_ctx(struct xhci_hcd *xhci,
  * The stream context array must be a power of 2, and can be as small as
  * 64 bytes or as large as 1MB.
  */
-struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci,
+static struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci,
                unsigned int num_stream_ctxs, dma_addr_t *dma,
                gfp_t mem_flags)
 {
@@ -1900,11 +1900,11 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
        val &= DBOFF_MASK;
        xhci_dbg(xhci, "// Doorbell array is located at offset 0x%x"
                        " from cap regs base addr\n", val);
-       xhci->dba = (void *) xhci->cap_regs + val;
+       xhci->dba = (void __iomem *) xhci->cap_regs + val;
        xhci_dbg_regs(xhci);
        xhci_print_run_regs(xhci);
        /* Set ir_set to interrupt register set 0 */
-       xhci->ir_set = (void *) xhci->run_regs->ir_set;
+       xhci->ir_set = &xhci->run_regs->ir_set[0];
 
        /*
         * Event ring setup: Allocate a normal ring, but also setup
@@ -1961,7 +1961,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
        /* Set the event ring dequeue address */
        xhci_set_hc_event_deq(xhci);
        xhci_dbg(xhci, "Wrote ERST address to ir_set 0.\n");
-       xhci_print_ir_set(xhci, xhci->ir_set, 0);
+       xhci_print_ir_set(xhci, 0);
 
        /*
         * XXX: Might need to set the Interrupter Moderation Register to
index df558f6..3289bf4 100644 (file)
@@ -308,11 +308,8 @@ static int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring,
 /* Ring the host controller doorbell after placing a command on the ring */
 void xhci_ring_cmd_db(struct xhci_hcd *xhci)
 {
-       u32 temp;
-
        xhci_dbg(xhci, "// Ding dong!\n");
-       temp = xhci_readl(xhci, &xhci->dba->doorbell[0]) & DB_MASK;
-       xhci_writel(xhci, temp | DB_TARGET_HOST, &xhci->dba->doorbell[0]);
+       xhci_writel(xhci, DB_VALUE_HOST, &xhci->dba->doorbell[0]);
        /* Flush PCI posted writes */
        xhci_readl(xhci, &xhci->dba->doorbell[0]);
 }
@@ -322,26 +319,24 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,
                unsigned int ep_index,
                unsigned int stream_id)
 {
-       struct xhci_virt_ep *ep;
-       unsigned int ep_state;
-       u32 field;
        __u32 __iomem *db_addr = &xhci->dba->doorbell[slot_id];
+       struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index];
+       unsigned int ep_state = ep->ep_state;
 
-       ep = &xhci->devs[slot_id]->eps[ep_index];
-       ep_state = ep->ep_state;
        /* Don't ring the doorbell for this endpoint if there are pending
-        * cancellations because the we don't want to interrupt processing.
+        * cancellations because we don't want to interrupt processing.
         * We don't want to restart any stream rings if there's a set dequeue
         * pointer command pending because the device can choose to start any
         * stream once the endpoint is on the HW schedule.
         * FIXME - check all the stream rings for pending cancellations.
         */
-       if (!(ep_state & EP_HALT_PENDING) && !(ep_state & SET_DEQ_PENDING)
-                       && !(ep_state & EP_HALTED)) {
-               field = xhci_readl(xhci, db_addr) & DB_MASK;
-               field |= EPI_TO_DB(ep_index) | STREAM_ID_TO_DB(stream_id);
-               xhci_writel(xhci, field, db_addr);
-       }
+       if ((ep_state & EP_HALT_PENDING) || (ep_state & SET_DEQ_PENDING) ||
+           (ep_state & EP_HALTED))
+               return;
+       xhci_writel(xhci, DB_VALUE(ep_index, stream_id), db_addr);
+       /* The CPU has better things to do at this point than wait for a
+        * write-posting flush.  It'll get there soon enough.
+        */
 }
 
 /* Ring the doorbell for any rings with pending URBs */
@@ -479,8 +474,11 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
        state->new_deq_seg = find_trb_seg(cur_td->start_seg,
                        dev->eps[ep_index].stopped_trb,
                        &state->new_cycle_state);
-       if (!state->new_deq_seg)
-               BUG();
+       if (!state->new_deq_seg) {
+               WARN_ON(1);
+               return;
+       }
+
        /* Dig out the cycle state saved by the xHC during the stop ep cmd */
        xhci_dbg(xhci, "Finding endpoint context\n");
        ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index);
@@ -491,8 +489,10 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
        state->new_deq_seg = find_trb_seg(state->new_deq_seg,
                        state->new_deq_ptr,
                        &state->new_cycle_state);
-       if (!state->new_deq_seg)
-               BUG();
+       if (!state->new_deq_seg) {
+               WARN_ON(1);
+               return;
+       }
 
        trb = &state->new_deq_ptr->generic;
        if ((trb->field[3] & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK) &&
@@ -1188,7 +1188,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
 
        addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS * (port_id - 1);
        temp = xhci_readl(xhci, addr);
-       if ((temp & PORT_CONNECT) && (hcd->state == HC_STATE_SUSPENDED)) {
+       if (hcd->state == HC_STATE_SUSPENDED) {
                xhci_dbg(xhci, "resume root hub\n");
                usb_hcd_resume_root_hub(hcd);
        }
@@ -1710,8 +1710,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
                /* Others already handled above */
                break;
        }
-       dev_dbg(&td->urb->dev->dev,
-                       "ep %#x - asked for %d bytes, "
+       xhci_dbg(xhci, "ep %#x - asked for %d bytes, "
                        "%d bytes untransferred\n",
                        td->urb->ep->desc.bEndpointAddress,
                        td->urb->transfer_buffer_length,
@@ -2369,12 +2368,13 @@ static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb)
 
                /* Scatter gather list entries may cross 64KB boundaries */
                running_total = TRB_MAX_BUFF_SIZE -
-                       (sg_dma_address(sg) & ((1 << TRB_MAX_BUFF_SHIFT) - 1));
+                       (sg_dma_address(sg) & (TRB_MAX_BUFF_SIZE - 1));
+               running_total &= TRB_MAX_BUFF_SIZE - 1;
                if (running_total != 0)
                        num_trbs++;
 
                /* How many more 64KB chunks to transfer, how many more TRBs? */
-               while (running_total < sg_dma_len(sg)) {
+               while (running_total < sg_dma_len(sg) && running_total < temp) {
                        num_trbs++;
                        running_total += TRB_MAX_BUFF_SIZE;
                }
@@ -2389,7 +2389,8 @@ static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb)
        }
        xhci_dbg(xhci, "\n");
        if (!in_interrupt())
-               dev_dbg(&urb->dev->dev, "ep %#x - urb len = %d, sglist used, num_trbs = %d\n",
+               xhci_dbg(xhci, "ep %#x - urb len = %d, sglist used, "
+                               "num_trbs = %d\n",
                                urb->ep->desc.bEndpointAddress,
                                urb->transfer_buffer_length,
                                num_trbs);
@@ -2399,11 +2400,11 @@ static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb)
 static void check_trb_math(struct urb *urb, int num_trbs, int running_total)
 {
        if (num_trbs != 0)
-               dev_dbg(&urb->dev->dev, "%s - ep %#x - Miscalculated number of "
+               dev_err(&urb->dev->dev, "%s - ep %#x - Miscalculated number of "
                                "TRBs, %d left\n", __func__,
                                urb->ep->desc.bEndpointAddress, num_trbs);
        if (running_total != urb->transfer_buffer_length)
-               dev_dbg(&urb->dev->dev, "%s - ep %#x - Miscalculated tx length, "
+               dev_err(&urb->dev->dev, "%s - ep %#x - Miscalculated tx length, "
                                "queued %#x (%d), asked for %#x (%d)\n",
                                __func__,
                                urb->ep->desc.bEndpointAddress,
@@ -2414,14 +2415,17 @@ static void check_trb_math(struct urb *urb, int num_trbs, int running_total)
 
 static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id,
                unsigned int ep_index, unsigned int stream_id, int start_cycle,
-               struct xhci_generic_trb *start_trb, struct xhci_td *td)
+               struct xhci_generic_trb *start_trb)
 {
        /*
         * Pass all the TRBs to the hardware at once and make sure this write
         * isn't reordered.
         */
        wmb();
-       start_trb->field[3] |= start_cycle;
+       if (start_cycle)
+               start_trb->field[3] |= start_cycle;
+       else
+               start_trb->field[3] &= ~0x1;
        xhci_ring_ep_doorbell(xhci, slot_id, ep_index, stream_id);
 }
 
@@ -2449,7 +2453,7 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
         * to set the polling interval (once the API is added).
         */
        if (xhci_interval != ep_interval) {
-               if (!printk_ratelimit())
+               if (printk_ratelimit())
                        dev_dbg(&urb->dev->dev, "Driver uses different interval"
                                        " (%d microframe%s) than xHCI "
                                        "(%d microframe%s)\n",
@@ -2535,8 +2539,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
        sg = urb->sg;
        addr = (u64) sg_dma_address(sg);
        this_sg_len = sg_dma_len(sg);
-       trb_buff_len = TRB_MAX_BUFF_SIZE -
-               (addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1));
+       trb_buff_len = TRB_MAX_BUFF_SIZE - (addr & (TRB_MAX_BUFF_SIZE - 1));
        trb_buff_len = min_t(int, trb_buff_len, this_sg_len);
        if (trb_buff_len > urb->transfer_buffer_length)
                trb_buff_len = urb->transfer_buffer_length;
@@ -2551,9 +2554,11 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                u32 remainder = 0;
 
                /* Don't change the cycle bit of the first TRB until later */
-               if (first_trb)
+               if (first_trb) {
                        first_trb = false;
-               else
+                       if (start_cycle == 0)
+                               field |= 0x1;
+               } else
                        field |= ep_ring->cycle_state;
 
                /* Chain all the TRBs together; clear the chain bit in the last
@@ -2572,7 +2577,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                                (unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1),
                                (unsigned int) addr + trb_buff_len);
                if (TRB_MAX_BUFF_SIZE -
-                               (addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1)) < trb_buff_len) {
+                               (addr & (TRB_MAX_BUFF_SIZE - 1)) < trb_buff_len) {
                        xhci_warn(xhci, "WARN: sg dma xfer crosses 64KB boundaries!\n");
                        xhci_dbg(xhci, "Next boundary at %#x, end dma = %#x\n",
                                        (unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1),
@@ -2616,7 +2621,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                }
 
                trb_buff_len = TRB_MAX_BUFF_SIZE -
-                       (addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1));
+                       (addr & (TRB_MAX_BUFF_SIZE - 1));
                trb_buff_len = min_t(int, trb_buff_len, this_sg_len);
                if (running_total + trb_buff_len > urb->transfer_buffer_length)
                        trb_buff_len =
@@ -2625,7 +2630,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
 
        check_trb_math(urb, num_trbs, running_total);
        giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
-                       start_cycle, start_trb, td);
+                       start_cycle, start_trb);
        return 0;
 }
 
@@ -2656,7 +2661,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
        num_trbs = 0;
        /* How much data is (potentially) left before the 64KB boundary? */
        running_total = TRB_MAX_BUFF_SIZE -
-               (urb->transfer_dma & ((1 << TRB_MAX_BUFF_SHIFT) - 1));
+               (urb->transfer_dma & (TRB_MAX_BUFF_SIZE - 1));
+       running_total &= TRB_MAX_BUFF_SIZE - 1;
 
        /* If there's some data on this 64KB chunk, or we have to send a
         * zero-length transfer, we need at least one TRB
@@ -2671,7 +2677,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
        /* FIXME: this doesn't deal with URB_ZERO_PACKET - need one more */
 
        if (!in_interrupt())
-               dev_dbg(&urb->dev->dev, "ep %#x - urb len = %#x (%d), addr = %#llx, num_trbs = %d\n",
+               xhci_dbg(xhci, "ep %#x - urb len = %#x (%d), "
+                               "addr = %#llx, num_trbs = %d\n",
                                urb->ep->desc.bEndpointAddress,
                                urb->transfer_buffer_length,
                                urb->transfer_buffer_length,
@@ -2699,8 +2706,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
        /* How much data is in the first TRB? */
        addr = (u64) urb->transfer_dma;
        trb_buff_len = TRB_MAX_BUFF_SIZE -
-               (urb->transfer_dma & ((1 << TRB_MAX_BUFF_SHIFT) - 1));
-       if (urb->transfer_buffer_length < trb_buff_len)
+               (urb->transfer_dma & (TRB_MAX_BUFF_SIZE - 1));
+       if (trb_buff_len > urb->transfer_buffer_length)
                trb_buff_len = urb->transfer_buffer_length;
 
        first_trb = true;
@@ -2711,9 +2718,11 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                field = 0;
 
                /* Don't change the cycle bit of the first TRB until later */
-               if (first_trb)
+               if (first_trb) {
                        first_trb = false;
-               else
+                       if (start_cycle == 0)
+                               field |= 0x1;
+               } else
                        field |= ep_ring->cycle_state;
 
                /* Chain all the TRBs together; clear the chain bit in the last
@@ -2757,7 +2766,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
 
        check_trb_math(urb, num_trbs, running_total);
        giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
-                       start_cycle, start_trb, td);
+                       start_cycle, start_trb);
        return 0;
 }
 
@@ -2818,13 +2827,17 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
        /* Queue setup TRB - see section 6.4.1.2.1 */
        /* FIXME better way to translate setup_packet into two u32 fields? */
        setup = (struct usb_ctrlrequest *) urb->setup_packet;
+       field = 0;
+       field |= TRB_IDT | TRB_TYPE(TRB_SETUP);
+       if (start_cycle == 0)
+               field |= 0x1;
        queue_trb(xhci, ep_ring, false, true,
                        /* FIXME endianness is probably going to bite my ass here. */
                        setup->bRequestType | setup->bRequest << 8 | setup->wValue << 16,
                        setup->wIndex | setup->wLength << 16,
                        TRB_LEN(8) | TRB_INTR_TARGET(0),
                        /* Immediate data in pointer */
-                       TRB_IDT | TRB_TYPE(TRB_SETUP));
+                       field);
 
        /* If there's data, queue data TRBs */
        field = 0;
@@ -2859,7 +2872,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                        field | TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state);
 
        giveback_first_trb(xhci, slot_id, ep_index, 0,
-                       start_cycle, start_trb, td);
+                       start_cycle, start_trb);
        return 0;
 }
 
@@ -2872,8 +2885,8 @@ static int count_isoc_trbs_needed(struct xhci_hcd *xhci,
        addr = (u64) (urb->transfer_dma + urb->iso_frame_desc[i].offset);
        td_len = urb->iso_frame_desc[i].length;
 
-       running_total = TRB_MAX_BUFF_SIZE -
-                       (addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1));
+       running_total = TRB_MAX_BUFF_SIZE - (addr & (TRB_MAX_BUFF_SIZE - 1));
+       running_total &= TRB_MAX_BUFF_SIZE - 1;
        if (running_total != 0)
                num_trbs++;
 
@@ -2900,6 +2913,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
        int running_total, trb_buff_len, td_len, td_remain_len, ret;
        u64 start_addr, addr;
        int i, j;
+       bool more_trbs_coming;
 
        ep_ring = xhci->devs[slot_id]->eps[ep_index].ring;
 
@@ -2910,7 +2924,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
        }
 
        if (!in_interrupt())
-               dev_dbg(&urb->dev->dev, "ep %#x - urb len = %#x (%d),"
+               xhci_dbg(xhci, "ep %#x - urb len = %#x (%d),"
                                " addr = %#llx, num_tds = %d\n",
                                urb->ep->desc.bEndpointAddress,
                                urb->transfer_buffer_length,
@@ -2950,7 +2964,10 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                                field |= TRB_TYPE(TRB_ISOC);
                                /* Assume URB_ISO_ASAP is set */
                                field |= TRB_SIA;
-                               if (i > 0)
+                               if (i == 0) {
+                                       if (start_cycle == 0)
+                                               field |= 0x1;
+                               } else
                                        field |= ep_ring->cycle_state;
                                first_trb = false;
                        } else {
@@ -2965,9 +2982,11 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                         */
                        if (j < trbs_per_td - 1) {
                                field |= TRB_CHAIN;
+                               more_trbs_coming = true;
                        } else {
                                td->last_trb = ep_ring->enqueue;
                                field |= TRB_IOC;
+                               more_trbs_coming = false;
                        }
 
                        /* Calculate TRB length */
@@ -2980,7 +2999,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                        length_field = TRB_LEN(trb_buff_len) |
                                remainder |
                                TRB_INTR_TARGET(0);
-                       queue_trb(xhci, ep_ring, false, false,
+                       queue_trb(xhci, ep_ring, false, more_trbs_coming,
                                lower_32_bits(addr),
                                upper_32_bits(addr),
                                length_field,
@@ -3003,10 +3022,8 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                }
        }
 
-       wmb();
-       start_trb->field[3] |= start_cycle;
-
-       xhci_ring_ep_doorbell(xhci, slot_id, ep_index, urb->stream_id);
+       giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
+                       start_cycle, start_trb);
        return 0;
 }
 
@@ -3064,7 +3081,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
         * to set the polling interval (once the API is added).
         */
        if (xhci_interval != ep_interval) {
-               if (!printk_ratelimit())
+               if (printk_ratelimit())
                        dev_dbg(&urb->dev->dev, "Driver uses different interval"
                                        " (%d microframe%s) than xHCI "
                                        "(%d microframe%s)\n",
index 45e4a31..2083fc2 100644 (file)
@@ -109,7 +109,7 @@ int xhci_halt(struct xhci_hcd *xhci)
 /*
  * Set the run bit and wait for the host to be running.
  */
-int xhci_start(struct xhci_hcd *xhci)
+static int xhci_start(struct xhci_hcd *xhci)
 {
        u32 temp;
        int ret;
@@ -226,7 +226,8 @@ static int xhci_setup_msi(struct xhci_hcd *xhci)
 static int xhci_setup_msix(struct xhci_hcd *xhci)
 {
        int i, ret = 0;
-       struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
+       struct usb_hcd *hcd = xhci_to_hcd(xhci);
+       struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
 
        /*
         * calculate number of msi-x vectors supported.
@@ -265,6 +266,7 @@ static int xhci_setup_msix(struct xhci_hcd *xhci)
                        goto disable_msix;
        }
 
+       hcd->msix_enabled = 1;
        return ret;
 
 disable_msix:
@@ -280,7 +282,8 @@ free_entries:
 /* Free any IRQs and disable MSI-X */
 static void xhci_cleanup_msix(struct xhci_hcd *xhci)
 {
-       struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
+       struct usb_hcd *hcd = xhci_to_hcd(xhci);
+       struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
 
        xhci_free_irq(xhci);
 
@@ -292,6 +295,7 @@ static void xhci_cleanup_msix(struct xhci_hcd *xhci)
                pci_disable_msi(pdev);
        }
 
+       hcd->msix_enabled = 0;
        return;
 }
 
@@ -325,7 +329,7 @@ int xhci_init(struct usb_hcd *hcd)
 
 
 #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-void xhci_event_ring_work(unsigned long arg)
+static void xhci_event_ring_work(unsigned long arg)
 {
        unsigned long flags;
        int temp;
@@ -469,7 +473,7 @@ int xhci_run(struct usb_hcd *hcd)
                        xhci->ir_set, (unsigned int) ER_IRQ_ENABLE(temp));
        xhci_writel(xhci, ER_IRQ_ENABLE(temp),
                        &xhci->ir_set->irq_pending);
-       xhci_print_ir_set(xhci, xhci->ir_set, 0);
+       xhci_print_ir_set(xhci, 0);
 
        if (NUM_TEST_NOOPS > 0)
                doorbell = xhci_setup_one_noop(xhci);
@@ -508,9 +512,10 @@ void xhci_stop(struct usb_hcd *hcd)
        spin_lock_irq(&xhci->lock);
        xhci_halt(xhci);
        xhci_reset(xhci);
-       xhci_cleanup_msix(xhci);
        spin_unlock_irq(&xhci->lock);
 
+       xhci_cleanup_msix(xhci);
+
 #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
        /* Tell the event ring poll function not to reschedule */
        xhci->zombie = 1;
@@ -523,7 +528,7 @@ void xhci_stop(struct usb_hcd *hcd)
        temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
        xhci_writel(xhci, ER_IRQ_DISABLE(temp),
                        &xhci->ir_set->irq_pending);
-       xhci_print_ir_set(xhci, xhci->ir_set, 0);
+       xhci_print_ir_set(xhci, 0);
 
        xhci_dbg(xhci, "cleaning up memory\n");
        xhci_mem_cleanup(xhci);
@@ -544,9 +549,10 @@ void xhci_shutdown(struct usb_hcd *hcd)
 
        spin_lock_irq(&xhci->lock);
        xhci_halt(xhci);
-       xhci_cleanup_msix(xhci);
        spin_unlock_irq(&xhci->lock);
 
+       xhci_cleanup_msix(xhci);
+
        xhci_dbg(xhci, "xhci_shutdown completed - status = %x\n",
                    xhci_readl(xhci, &xhci->op_regs->status));
 }
@@ -647,6 +653,7 @@ int xhci_suspend(struct xhci_hcd *xhci)
        int                     rc = 0;
        struct usb_hcd          *hcd = xhci_to_hcd(xhci);
        u32                     command;
+       int                     i;
 
        spin_lock_irq(&xhci->lock);
        clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
@@ -677,10 +684,15 @@ int xhci_suspend(struct xhci_hcd *xhci)
                spin_unlock_irq(&xhci->lock);
                return -ETIMEDOUT;
        }
-       /* step 5: remove core well power */
-       xhci_cleanup_msix(xhci);
        spin_unlock_irq(&xhci->lock);
 
+       /* step 5: remove core well power */
+       /* synchronize irq when using MSI-X */
+       if (xhci->msix_entries) {
+               for (i = 0; i < xhci->msix_count; i++)
+                       synchronize_irq(xhci->msix_entries[i].vector);
+       }
+
        return rc;
 }
 
@@ -694,7 +706,6 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
 {
        u32                     command, temp = 0;
        struct usb_hcd          *hcd = xhci_to_hcd(xhci);
-       struct pci_dev          *pdev = to_pci_dev(hcd->self.controller);
        int     old_state, retval;
 
        old_state = hcd->state;
@@ -729,9 +740,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
                xhci_dbg(xhci, "Stop HCD\n");
                xhci_halt(xhci);
                xhci_reset(xhci);
-               if (hibernated)
-                       xhci_cleanup_msix(xhci);
                spin_unlock_irq(&xhci->lock);
+               xhci_cleanup_msix(xhci);
 
 #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
                /* Tell the event ring poll function not to reschedule */
@@ -745,7 +755,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
                temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
                xhci_writel(xhci, ER_IRQ_DISABLE(temp),
                                &xhci->ir_set->irq_pending);
-               xhci_print_ir_set(xhci, xhci->ir_set, 0);
+               xhci_print_ir_set(xhci, 0);
 
                xhci_dbg(xhci, "cleaning up memory\n");
                xhci_mem_cleanup(xhci);
@@ -765,30 +775,6 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
                return retval;
        }
 
-       spin_unlock_irq(&xhci->lock);
-       /* Re-setup MSI-X */
-       if (hcd->irq)
-               free_irq(hcd->irq, hcd);
-       hcd->irq = -1;
-
-       retval = xhci_setup_msix(xhci);
-       if (retval)
-               /* fall back to msi*/
-               retval = xhci_setup_msi(xhci);
-
-       if (retval) {
-               /* fall back to legacy interrupt*/
-               retval = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED,
-                                       hcd->irq_descr, hcd);
-               if (retval) {
-                       xhci_err(xhci, "request interrupt %d failed\n",
-                                       pdev->irq);
-                       return retval;
-               }
-               hcd->irq = pdev->irq;
-       }
-
-       spin_lock_irq(&xhci->lock);
        /* step 4: set Run/Stop bit */
        command = xhci_readl(xhci, &xhci->op_regs->command);
        command |= CMD_RUN;
@@ -871,7 +857,7 @@ unsigned int xhci_last_valid_endpoint(u32 added_ctxs)
 /* Returns 1 if the arguments are OK;
  * returns 0 this is a root hub; returns -EINVAL for NULL pointers.
  */
-int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
+static int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
                struct usb_host_endpoint *ep, int check_ep, bool check_virt_dev,
                const char *func) {
        struct xhci_hcd *xhci;
@@ -1707,7 +1693,7 @@ static void xhci_setup_input_ctx_for_config_ep(struct xhci_hcd *xhci,
        xhci_dbg_ctx(xhci, in_ctx, xhci_last_valid_endpoint(add_flags));
 }
 
-void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci,
+static void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci,
                unsigned int slot_id, unsigned int ep_index,
                struct xhci_dequeue_state *deq_state)
 {
@@ -2445,8 +2431,12 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
                xhci_err(xhci, "Error while assigning device slot ID\n");
                return 0;
        }
-       /* xhci_alloc_virt_device() does not touch rings; no need to lock */
-       if (!xhci_alloc_virt_device(xhci, xhci->slot_id, udev, GFP_KERNEL)) {
+       /* xhci_alloc_virt_device() does not touch rings; no need to lock.
+        * Use GFP_NOIO, since this function can be called from
+        * xhci_discover_or_reset_device(), which may be called as part of
+        * mass storage driver error handling.
+        */
+       if (!xhci_alloc_virt_device(xhci, xhci->slot_id, udev, GFP_NOIO)) {
                /* Disable slot, if we can do it without mem alloc */
                xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n");
                spin_lock_irqsave(&xhci->lock, flags);
index 170c367..7f127df 100644 (file)
@@ -436,22 +436,18 @@ struct xhci_run_regs {
 /**
  * struct doorbell_array
  *
+ * Bits  0 -  7: Endpoint target
+ * Bits  8 - 15: RsvdZ
+ * Bits 16 - 31: Stream ID
+ *
  * Section 5.6
  */
 struct xhci_doorbell_array {
        u32     doorbell[256];
 };
 
-#define        DB_TARGET_MASK          0xFFFFFF00
-#define        DB_STREAM_ID_MASK       0x0000FFFF
-#define        DB_TARGET_HOST          0x0
-#define        DB_STREAM_ID_HOST       0x0
-#define        DB_MASK                 (0xff << 8)
-
-/* Endpoint Target - bits 0:7 */
-#define EPI_TO_DB(p)           (((p) + 1) & 0xff)
-#define STREAM_ID_TO_DB(p)     (((p) & 0xffff) << 16)
-
+#define DB_VALUE(ep, stream)   ((((ep) + 1) & 0xff) | ((stream) << 16))
+#define DB_VALUE_HOST          0x00000000
 
 /**
  * struct xhci_protocol_caps
@@ -1352,7 +1348,7 @@ static inline int xhci_link_trb_quirk(struct xhci_hcd *xhci)
 }
 
 /* xHCI debugging */
-void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num);
+void xhci_print_ir_set(struct xhci_hcd *xhci, int set_num);
 void xhci_print_registers(struct xhci_hcd *xhci);
 void xhci_dbg_regs(struct xhci_hcd *xhci);
 void xhci_print_run_regs(struct xhci_hcd *xhci);
index 1732d9b..1616ad1 100644 (file)
@@ -45,7 +45,7 @@ struct usb_led {
 
 static void change_color(struct usb_led *led)
 {
-       int retval;
+       int retval = 0;
        unsigned char *buffer;
 
        buffer = kmalloc(8, GFP_KERNEL);
index 4ff2158..f7a2057 100644 (file)
@@ -776,7 +776,6 @@ static const struct usb_device_id uss720_table[] = {
        { USB_DEVICE(0x0557, 0x2001) },
        { USB_DEVICE(0x0729, 0x1284) },
        { USB_DEVICE(0x1293, 0x0002) },
-       { USB_DEVICE(0x1293, 0x0002) },
        { USB_DEVICE(0x050d, 0x0002) },
        { }                                             /* Terminating entry */
 };
index eeba228..9d49d1c 100644 (file)
@@ -404,6 +404,7 @@ static int bfin_musb_init(struct musb *musb)
                musb->xceiv->set_power = bfin_musb_set_power;
 
        musb->isr = blackfin_interrupt;
+       musb->double_buffer_not_ok = true;
 
        return 0;
 }
index 07cf394..c292d5c 100644 (file)
@@ -128,12 +128,7 @@ MODULE_ALIAS("platform:" MUSB_DRIVER_NAME);
 
 static inline struct musb *dev_to_musb(struct device *dev)
 {
-#ifdef CONFIG_USB_MUSB_HDRC_HCD
-       /* usbcore insists dev->driver_data is a "struct hcd *" */
-       return hcd_to_musb(dev_get_drvdata(dev));
-#else
        return dev_get_drvdata(dev);
-#endif
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1869,6 +1864,7 @@ allocate_instance(struct device *dev,
        INIT_LIST_HEAD(&musb->out_bulk);
 
        hcd->uses_new_polling = 1;
+       hcd->has_tt = 1;
 
        musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
        musb->a_wait_bcon = OTG_TIME_A_WAIT_BCON;
@@ -1876,10 +1872,9 @@ allocate_instance(struct device *dev,
        musb = kzalloc(sizeof *musb, GFP_KERNEL);
        if (!musb)
                return NULL;
-       dev_set_drvdata(dev, musb);
 
 #endif
-
+       dev_set_drvdata(dev, musb);
        musb->mregs = mbase;
        musb->ctrl_base = mbase;
        musb->nIrq = -ENODEV;
@@ -2191,7 +2186,7 @@ static int __init musb_probe(struct platform_device *pdev)
        void __iomem    *base;
 
        iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!iomem || irq == 0)
+       if (!iomem || irq <= 0)
                return -ENODEV;
 
        base = ioremap(iomem->start, resource_size(iomem));
index d0c236f..e6400be 100644 (file)
@@ -497,6 +497,19 @@ struct musb {
        struct usb_gadget_driver *gadget_driver;        /* its driver */
 #endif
 
+       /*
+        * FIXME: Remove this flag.
+        *
+        * This is only added to allow Blackfin to work
+        * with current driver. For some unknown reason
+        * Blackfin doesn't work with double buffering
+        * and that's enabled by default.
+        *
+        * We added this flag to forcefully disable double
+        * buffering until we get it working.
+        */
+       unsigned                double_buffer_not_ok:1 __deprecated;
+
        struct musb_hdrc_config *config;
 
 #ifdef MUSB_CONFIG_PROC_FS
index 916065b..3a97c4e 100644 (file)
@@ -169,6 +169,9 @@ struct dma_controller {
                                                        dma_addr_t dma_addr,
                                                        u32 length);
        int                     (*channel_abort)(struct dma_channel *);
+       int                     (*is_compatible)(struct dma_channel *channel,
+                                                       u16 maxpacket,
+                                                       void *buf, u32 length);
 };
 
 /* called after channel_program(), may indicate a fault */
index ed58c6c..2fe3046 100644 (file)
 
 /* ----------------------------------------------------------------------- */
 
+#define is_buffer_mapped(req) (is_dma_capable() && \
+                                       (req->map_state != UN_MAPPED))
+
 /* Maps the buffer to dma  */
 
 static inline void map_dma_buffer(struct musb_request *request,
-                               struct musb *musb)
+                       struct musb *musb, struct musb_ep *musb_ep)
 {
+       int compatible = true;
+       struct dma_controller *dma = musb->dma_controller;
+
+       request->map_state = UN_MAPPED;
+
+       if (!is_dma_capable() || !musb_ep->dma)
+               return;
+
+       /* Check if DMA engine can handle this request.
+        * DMA code must reject the USB request explicitly.
+        * Default behaviour is to map the request.
+        */
+       if (dma->is_compatible)
+               compatible = dma->is_compatible(musb_ep->dma,
+                               musb_ep->packet_sz, request->request.buf,
+                               request->request.length);
+       if (!compatible)
+               return;
+
        if (request->request.dma == DMA_ADDR_INVALID) {
                request->request.dma = dma_map_single(
                                musb->controller,
@@ -105,7 +127,7 @@ static inline void map_dma_buffer(struct musb_request *request,
                                request->tx
                                        ? DMA_TO_DEVICE
                                        : DMA_FROM_DEVICE);
-               request->mapped = 1;
+               request->map_state = MUSB_MAPPED;
        } else {
                dma_sync_single_for_device(musb->controller,
                        request->request.dma,
@@ -113,7 +135,7 @@ static inline void map_dma_buffer(struct musb_request *request,
                        request->tx
                                ? DMA_TO_DEVICE
                                : DMA_FROM_DEVICE);
-               request->mapped = 0;
+               request->map_state = PRE_MAPPED;
        }
 }
 
@@ -121,11 +143,14 @@ static inline void map_dma_buffer(struct musb_request *request,
 static inline void unmap_dma_buffer(struct musb_request *request,
                                struct musb *musb)
 {
+       if (!is_buffer_mapped(request))
+               return;
+
        if (request->request.dma == DMA_ADDR_INVALID) {
                DBG(20, "not unmapping a never mapped buffer\n");
                return;
        }
-       if (request->mapped) {
+       if (request->map_state == MUSB_MAPPED) {
                dma_unmap_single(musb->controller,
                        request->request.dma,
                        request->request.length,
@@ -133,16 +158,15 @@ static inline void unmap_dma_buffer(struct musb_request *request,
                                ? DMA_TO_DEVICE
                                : DMA_FROM_DEVICE);
                request->request.dma = DMA_ADDR_INVALID;
-               request->mapped = 0;
-       } else {
+       } else { /* PRE_MAPPED */
                dma_sync_single_for_cpu(musb->controller,
                        request->request.dma,
                        request->request.length,
                        request->tx
                                ? DMA_TO_DEVICE
                                : DMA_FROM_DEVICE);
-
        }
+       request->map_state = UN_MAPPED;
 }
 
 /*
@@ -172,8 +196,7 @@ __acquires(ep->musb->lock)
 
        ep->busy = 1;
        spin_unlock(&musb->lock);
-       if (is_dma_capable() && ep->dma)
-               unmap_dma_buffer(req, musb);
+       unmap_dma_buffer(req, musb);
        if (request->status == 0)
                DBG(5, "%s done request %p,  %d/%d\n",
                                ep->end_point.name, request,
@@ -335,7 +358,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
                        csr);
 
 #ifndef        CONFIG_MUSB_PIO_ONLY
-       if (is_dma_capable() && musb_ep->dma) {
+       if (is_buffer_mapped(req)) {
                struct dma_controller   *c = musb->dma_controller;
                size_t request_size;
 
@@ -436,8 +459,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
                 * Unmap the dma buffer back to cpu if dma channel
                 * programming fails
                 */
-               if (is_dma_capable() && musb_ep->dma)
-                       unmap_dma_buffer(req, musb);
+               unmap_dma_buffer(req, musb);
 
                musb_write_fifo(musb_ep->hw_ep, fifo_count,
                                (u8 *) (request->buf + request->actual));
@@ -627,7 +649,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                return;
        }
 
-       if (is_cppi_enabled() && musb_ep->dma) {
+       if (is_cppi_enabled() && is_buffer_mapped(req)) {
                struct dma_controller   *c = musb->dma_controller;
                struct dma_channel      *channel = musb_ep->dma;
 
@@ -658,7 +680,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                len = musb_readw(epio, MUSB_RXCOUNT);
                if (request->actual < request->length) {
 #ifdef CONFIG_USB_INVENTRA_DMA
-                       if (is_dma_capable() && musb_ep->dma) {
+                       if (is_buffer_mapped(req)) {
                                struct dma_controller   *c;
                                struct dma_channel      *channel;
                                int                     use_dma = 0;
@@ -742,7 +764,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                        fifo_count = min_t(unsigned, len, fifo_count);
 
 #ifdef CONFIG_USB_TUSB_OMAP_DMA
-                       if (tusb_dma_omap() && musb_ep->dma) {
+                       if (tusb_dma_omap() && is_buffer_mapped(req)) {
                                struct dma_controller *c = musb->dma_controller;
                                struct dma_channel *channel = musb_ep->dma;
                                u32 dma_addr = request->dma + request->actual;
@@ -762,7 +784,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                         * programming fails. This buffer is mapped if the
                         * channel allocation is successful
                         */
-                        if (is_dma_capable() && musb_ep->dma) {
+                        if (is_buffer_mapped(req)) {
                                unmap_dma_buffer(req, musb);
 
                                /*
@@ -989,7 +1011,11 @@ static int musb_gadget_enable(struct usb_ep *ep,
                /* Set TXMAXP with the FIFO size of the endpoint
                 * to disable double buffering mode.
                 */
-               musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
+               if (musb->double_buffer_not_ok)
+                       musb_writew(regs, MUSB_TXMAXP, hw_ep->max_packet_sz_tx);
+               else
+                       musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz
+                                       | (musb_ep->hb_mult << 11));
 
                csr = MUSB_TXCSR_MODE | MUSB_TXCSR_CLRDATATOG;
                if (musb_readw(regs, MUSB_TXCSR)
@@ -1025,7 +1051,11 @@ static int musb_gadget_enable(struct usb_ep *ep,
                /* Set RXMAXP with the FIFO size of the endpoint
                 * to disable double buffering mode.
                 */
-               musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz | (musb_ep->hb_mult << 11));
+               if (musb->double_buffer_not_ok)
+                       musb_writew(regs, MUSB_RXMAXP, hw_ep->max_packet_sz_tx);
+               else
+                       musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz
+                                       | (musb_ep->hb_mult << 11));
 
                /* force shared fifo to OUT-only mode */
                if (hw_ep->is_shared_fifo) {
@@ -1214,10 +1244,7 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
        request->epnum = musb_ep->current_epnum;
        request->tx = musb_ep->is_in;
 
-       if (is_dma_capable() && musb_ep->dma)
-               map_dma_buffer(request, musb);
-       else
-               request->mapped = 0;
+       map_dma_buffer(request, musb, musb_ep);
 
        spin_lock_irqsave(&musb->lock, lockflags);
 
index dec8dc0..a55354f 100644 (file)
 #ifndef __MUSB_GADGET_H
 #define __MUSB_GADGET_H
 
+enum buffer_map_state {
+       UN_MAPPED = 0,
+       PRE_MAPPED,
+       MUSB_MAPPED
+};
+
 struct musb_request {
        struct usb_request      request;
        struct musb_ep          *ep;
        struct musb             *musb;
        u8 tx;                  /* endpoint direction */
        u8 epnum;
-       u8 mapped;
+       enum buffer_map_state map_state;
 };
 
 static inline struct musb_request *to_musb_request(struct usb_request *req)
index 4d5bcb4..0f523d7 100644 (file)
@@ -609,7 +609,7 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
        /* Set RXMAXP with the FIFO size of the endpoint
         * to disable double buffer mode.
         */
-       if (musb->hwvers < MUSB_HWVERS_2000)
+       if (musb->double_buffer_not_ok)
                musb_writew(ep->regs, MUSB_RXMAXP, ep->max_packet_sz_rx);
        else
                musb_writew(ep->regs, MUSB_RXMAXP,
@@ -784,14 +784,13 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
                /* protocol/endpoint/interval/NAKlimit */
                if (epnum) {
                        musb_writeb(epio, MUSB_TXTYPE, qh->type_reg);
-                       if (can_bulk_split(musb, qh->type))
+                       if (musb->double_buffer_not_ok)
                                musb_writew(epio, MUSB_TXMAXP,
-                                       packet_sz
-                                       | ((hw_ep->max_packet_sz_tx /
-                                               packet_sz) - 1) << 11);
+                                               hw_ep->max_packet_sz_tx);
                        else
                                musb_writew(epio, MUSB_TXMAXP,
-                                       packet_sz);
+                                               qh->maxpacket |
+                                               ((qh->hb_mult - 1) << 11));
                        musb_writeb(epio, MUSB_TXINTERVAL, qh->intv_reg);
                } else {
                        musb_writeb(epio, MUSB_NAKLIMIT0, qh->intv_reg);
index f763d62..21056c9 100644 (file)
@@ -94,24 +94,33 @@ static inline void musb_write_hsdma_addr(void __iomem *mbase,
 {
        musb_writew(mbase,
                MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDR_LOW),
-               ((u16)((u32) dma_addr & 0xFFFF)));
+               dma_addr);
        musb_writew(mbase,
                MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDR_HIGH),
-               ((u16)(((u32) dma_addr >> 16) & 0xFFFF)));
+               (dma_addr >> 16));
 }
 
 static inline u32 musb_read_hsdma_count(void __iomem *mbase, u8 bchannel)
 {
-       return musb_readl(mbase,
+       u32 count = musb_readw(mbase,
                MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_HIGH));
+
+       count = count << 16;
+
+       count |= musb_readw(mbase,
+               MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_LOW));
+
+       return count;
 }
 
 static inline void musb_write_hsdma_count(void __iomem *mbase,
                                u8 bchannel, u32 len)
 {
-       musb_writel(mbase,
+       musb_writew(mbase,
+               MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_LOW),len);
+       musb_writew(mbase,
                MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_HIGH),
-               len);
+               (len >> 16));
 }
 
 #endif /* CONFIG_BLACKFIN */
index a3f1233..bc8badd 100644 (file)
@@ -362,6 +362,7 @@ static int omap2430_musb_init(struct musb *musb)
 
 static int omap2430_musb_exit(struct musb *musb)
 {
+       del_timer_sync(&musb_idle_timer);
 
        omap2430_low_level_exit(musb);
        otg_put_transceiver(musb->xceiv);
index 9fb875d..9ffc823 100644 (file)
@@ -103,6 +103,8 @@ config USB_MSM_OTG_72K
          required after resetting the hardware and power management.
          This driver is required even for peripheral only or host only
          mode configurations.
+         This driver is not supported on boards like trout which
+         has an external PHY.
 
 config AB8500_USB
         tristate "AB8500 USB Transceiver Driver"
index e70014a..8acf165 100644 (file)
@@ -132,6 +132,8 @@ static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, nop);
 
+       BLOCKING_INIT_NOTIFIER_HEAD(&nop->otg.notifier);
+
        return 0;
 exit:
        kfree(nop);
index 059d9ac..770d799 100644 (file)
@@ -45,7 +45,7 @@ struct ulpi_info {
 /* ULPI hardcoded IDs, used for probing */
 static struct ulpi_info ulpi_ids[] = {
        ULPI_INFO(ULPI_ID(0x04cc, 0x1504), "NXP ISP1504"),
-       ULPI_INFO(ULPI_ID(0x0424, 0x0006), "SMSC USB3319"),
+       ULPI_INFO(ULPI_ID(0x0424, 0x0006), "SMSC USB331x"),
 };
 
 static int ulpi_set_otg_flags(struct otg_transceiver *otg)
index 63f7cc4..7b8815d 100644 (file)
@@ -486,12 +486,22 @@ static void ch341_read_int_callback(struct urb *urb)
        if (actual_length >= 4) {
                struct ch341_private *priv = usb_get_serial_port_data(port);
                unsigned long flags;
+               u8 prev_line_status = priv->line_status;
 
                spin_lock_irqsave(&priv->lock, flags);
                priv->line_status = (~(data[2])) & CH341_BITS_MODEM_STAT;
                if ((data[1] & CH341_MULT_STAT))
                        priv->multi_status_change = 1;
                spin_unlock_irqrestore(&priv->lock, flags);
+
+               if ((priv->line_status ^ prev_line_status) & CH341_BIT_DCD) {
+                       struct tty_struct *tty = tty_port_tty_get(&port->port);
+                       if (tty)
+                               usb_serial_handle_dcd_change(port, tty,
+                                           priv->line_status & CH341_BIT_DCD);
+                       tty_kref_put(tty);
+               }
+
                wake_up_interruptible(&priv->delta_msr_wait);
        }
 
index 8d7731d..735ea03 100644 (file)
@@ -49,7 +49,6 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *,
 static void cp210x_break_ctl(struct tty_struct *, int);
 static int cp210x_startup(struct usb_serial *);
 static void cp210x_dtr_rts(struct usb_serial_port *p, int on);
-static int cp210x_carrier_raised(struct usb_serial_port *p);
 
 static int debug;
 
@@ -87,7 +86,6 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */
        { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */
        { USB_DEVICE(0x10C4, 0x813F) }, /* Tams Master Easy Control */
-       { USB_DEVICE(0x10C4, 0x8149) }, /* West Mountain Radio Computerized Battery Analyzer */
        { USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */
        { USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */
        { USB_DEVICE(0x10C4, 0x8156) }, /* B&G H3000 link cable */
@@ -110,7 +108,9 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
        { USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */
        { USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */
+       { USB_DEVICE(0x10C4, 0x83D8) }, /* DekTec DTA Plus VHF/UHF Booster/Attenuator */
        { USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */
+       { USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */
        { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */
        { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */
        { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
@@ -165,8 +165,7 @@ static struct usb_serial_driver cp210x_device = {
        .tiocmget               = cp210x_tiocmget,
        .tiocmset               = cp210x_tiocmset,
        .attach                 = cp210x_startup,
-       .dtr_rts                = cp210x_dtr_rts,
-       .carrier_raised         = cp210x_carrier_raised
+       .dtr_rts                = cp210x_dtr_rts
 };
 
 /* Config request types */
@@ -765,15 +764,6 @@ static int cp210x_tiocmget (struct tty_struct *tty, struct file *file)
        return result;
 }
 
-static int cp210x_carrier_raised(struct usb_serial_port *p)
-{
-       unsigned int control;
-       cp210x_get_config(p, CP210X_GET_MDMSTS, &control, 1);
-       if (control & CONTROL_DCD)
-               return 1;
-       return 0;
-}
-
 static void cp210x_break_ctl (struct tty_struct *tty, int break_state)
 {
        struct usb_serial_port *port = tty->driver_data;
index b92070c..666e5a6 100644 (file)
@@ -455,7 +455,6 @@ static int digi_write_room(struct tty_struct *tty);
 static int digi_chars_in_buffer(struct tty_struct *tty);
 static int digi_open(struct tty_struct *tty, struct usb_serial_port *port);
 static void digi_close(struct usb_serial_port *port);
-static int digi_carrier_raised(struct usb_serial_port *port);
 static void digi_dtr_rts(struct usb_serial_port *port, int on);
 static int digi_startup_device(struct usb_serial *serial);
 static int digi_startup(struct usb_serial *serial);
@@ -511,7 +510,6 @@ static struct usb_serial_driver digi_acceleport_2_device = {
        .open =                         digi_open,
        .close =                        digi_close,
        .dtr_rts =                      digi_dtr_rts,
-       .carrier_raised =               digi_carrier_raised,
        .write =                        digi_write,
        .write_room =                   digi_write_room,
        .write_bulk_callback =          digi_write_bulk_callback,
@@ -1339,14 +1337,6 @@ static void digi_dtr_rts(struct usb_serial_port *port, int on)
        digi_set_modem_signals(port, on * (TIOCM_DTR|TIOCM_RTS), 1);
 }
 
-static int digi_carrier_raised(struct usb_serial_port *port)
-{
-       struct digi_port *priv = usb_get_serial_port_data(port);
-       if (priv->dp_modem_signals & TIOCM_CD)
-               return 1;
-       return 0;
-}
-
 static int digi_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
        int ret;
index a2668d0..f349a36 100644 (file)
@@ -100,6 +100,7 @@ struct ftdi_sio_quirk {
 static int   ftdi_jtag_probe(struct usb_serial *serial);
 static int   ftdi_mtxorb_hack_setup(struct usb_serial *serial);
 static int   ftdi_NDI_device_setup(struct usb_serial *serial);
+static int   ftdi_stmclite_probe(struct usb_serial *serial);
 static void  ftdi_USB_UIRT_setup(struct ftdi_private *priv);
 static void  ftdi_HE_TIRA1_setup(struct ftdi_private *priv);
 
@@ -123,6 +124,10 @@ static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = {
        .port_probe = ftdi_HE_TIRA1_setup,
 };
 
+static struct ftdi_sio_quirk ftdi_stmclite_quirk = {
+       .probe  = ftdi_stmclite_probe,
+};
+
 /*
  * The 8U232AM has the same API as the sio except for:
  * - it can support MUCH higher baudrates; up to:
@@ -616,6 +621,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_OCEANIC_PID) },
        { USB_DEVICE(TTI_VID, TTI_QL355P_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
+       { USB_DEVICE(ACTON_VID, ACTON_SPECTRAPRO_PID) },
        { USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) },
        { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },
        { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
@@ -676,7 +682,17 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_RRCIRKITS_LOCOBUFFER_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ASK_RDR400_PID) },
-       { USB_DEVICE(ICOM_ID1_VID, ICOM_ID1_PID) },
+       { USB_DEVICE(ICOM_VID, ICOM_ID_1_PID) },
+       { USB_DEVICE(ICOM_VID, ICOM_OPC_U_UC_PID) },
+       { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C1_PID) },
+       { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C2_PID) },
+       { USB_DEVICE(ICOM_VID, ICOM_ID_RP2D_PID) },
+       { USB_DEVICE(ICOM_VID, ICOM_ID_RP2VT_PID) },
+       { USB_DEVICE(ICOM_VID, ICOM_ID_RP2VR_PID) },
+       { USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVT_PID) },
+       { USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVR_PID) },
+       { USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVT_PID) },
+       { USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVR_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) },
@@ -800,6 +816,8 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) },
        { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID),
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(ST_VID, ST_STMCLT1030_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_stmclite_quirk },
        { },                                    /* Optional parameter entry */
        { }                                     /* Terminating entry */
 };
@@ -1698,6 +1716,25 @@ static int ftdi_jtag_probe(struct usb_serial *serial)
        return 0;
 }
 
+/*
+ * First and second port on STMCLiteadaptors is reserved for JTAG interface
+ * and the forth port for pio
+ */
+static int ftdi_stmclite_probe(struct usb_serial *serial)
+{
+       struct usb_device *udev = serial->dev;
+       struct usb_interface *interface = serial->interface;
+
+       dbg("%s", __func__);
+
+       if (interface == udev->actconfig->interface[2])
+               return 0;
+
+       dev_info(&udev->dev, "Ignoring serial port reserved for JTAG\n");
+
+       return -ENODEV;
+}
+
 /*
  * The Matrix Orbital VK204-25-USB has an invalid IN endpoint.
  * We have to correct it if we want to read from it.
index bf08672..117e8e6 100644 (file)
 #define RATOC_VENDOR_ID                0x0584
 #define RATOC_PRODUCT_ID_USB60F        0xb020
 
+/*
+ * Acton Research Corp.
+ */
+#define ACTON_VID              0x0647  /* Vendor ID */
+#define ACTON_SPECTRAPRO_PID   0x0100
+
 /*
  * Contec products (http://www.contec.com)
  * Submitted by Daniel Sangorrin
 #define OCT_US101_PID          0x0421  /* OCT US101 USB to RS-232 */
 
 /*
- * Icom ID-1 digital transceiver
+ * Definitions for Icom Inc. devices
  */
-
-#define ICOM_ID1_VID            0x0C26
-#define ICOM_ID1_PID            0x0004
+#define ICOM_VID               0x0C26 /* Icom vendor ID */
+/* Note: ID-1 is a communications tranceiver for HAM-radio operators */
+#define ICOM_ID_1_PID          0x0004 /* ID-1 USB to RS-232 */
+/* Note: OPC is an Optional cable to connect an Icom Tranceiver */
+#define ICOM_OPC_U_UC_PID      0x0018 /* OPC-478UC, OPC-1122U cloning cable */
+/* Note: ID-RP* devices are Icom Repeater Devices for HAM-radio */
+#define ICOM_ID_RP2C1_PID      0x0009 /* ID-RP2C Asset 1 to RS-232 */
+#define ICOM_ID_RP2C2_PID      0x000A /* ID-RP2C Asset 2 to RS-232 */
+#define ICOM_ID_RP2D_PID       0x000B /* ID-RP2D configuration port*/
+#define ICOM_ID_RP2VT_PID      0x000C /* ID-RP2V Transmit config port */
+#define ICOM_ID_RP2VR_PID      0x000D /* ID-RP2V Receive config port */
+#define ICOM_ID_RP4KVT_PID     0x0010 /* ID-RP4000V Transmit config port */
+#define ICOM_ID_RP4KVR_PID     0x0011 /* ID-RP4000V Receive config port */
+#define ICOM_ID_RP2KVT_PID     0x0012 /* ID-RP2000V Transmit config port */
+#define ICOM_ID_RP2KVR_PID     0x0013 /* ID-RP2000V Receive config port */
 
 /*
  * GN Otometrics (http://www.otometrics.com)
 #define STB_PID                        0x0001 /* Sensor Terminal Board */
 #define WHT_PID                        0x0004 /* Wireless Handheld Terminal */
 
+/*
+ * STMicroelectonics
+ */
+#define ST_VID                 0x0483
+#define ST_STMCLT1030_PID      0x3747 /* ST Micro Connect Lite STMCLT1030 */
+
 /*
  * Papouch products (http://www.papouch.com/)
  * Submitted by Folkert van Heusden
index e6833e2..e4db5ad 100644 (file)
@@ -479,6 +479,26 @@ int usb_serial_handle_break(struct usb_serial_port *port)
 }
 EXPORT_SYMBOL_GPL(usb_serial_handle_break);
 
+/**
+ *     usb_serial_handle_dcd_change - handle a change of carrier detect state
+ *     @port: usb_serial_port structure for the open port
+ *     @tty: tty_struct structure for the port
+ *     @status: new carrier detect status, nonzero if active
+ */
+void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port,
+                               struct tty_struct *tty, unsigned int status)
+{
+       struct tty_port *port = &usb_port->port;
+
+       dbg("%s - port %d, status %d", __func__, usb_port->number, status);
+
+       if (status)
+               wake_up_interruptible(&port->open_wait);
+       else if (tty && !C_CLOCAL(tty))
+               tty_hangup(tty);
+}
+EXPORT_SYMBOL_GPL(usb_serial_handle_dcd_change);
+
 int usb_serial_generic_resume(struct usb_serial *serial)
 {
        struct usb_serial_port *port;
index cd769ef..3b246d9 100644 (file)
@@ -2889,8 +2889,8 @@ static void load_application_firmware(struct edgeport_serial *edge_serial)
 
        dbg("%s %d.%d.%d", fw_info, rec->data[0], rec->data[1], build);
 
-       edge_serial->product_info.FirmwareMajorVersion = fw->data[0];
-       edge_serial->product_info.FirmwareMinorVersion = fw->data[1];
+       edge_serial->product_info.FirmwareMajorVersion = rec->data[0];
+       edge_serial->product_info.FirmwareMinorVersion = rec->data[1];
        edge_serial->product_info.FirmwareBuildNumber = cpu_to_le16(build);
 
        for (rec = ihex_next_binrec(rec); rec;
index 6ab2a3f..178b22e 100644 (file)
@@ -199,6 +199,7 @@ static struct usb_serial_driver epic_device = {
                .name           = "epic",
        },
        .description            = "EPiC device",
+       .usb_driver             = &io_driver,
        .id_table               = Epic_port_id_table,
        .num_ports              = 1,
        .open                   = edge_open,
index 12ed594..99b97c0 100644 (file)
@@ -1275,6 +1275,7 @@ static struct usb_serial_driver iuu_device = {
                   .name = "iuu_phoenix",
                   },
        .id_table = id_table,
+       .usb_driver = &iuu_driver,
        .num_ports = 1,
        .bulk_in_size = 512,
        .bulk_out_size = 512,
index 2d8baf6..ce134dc 100644 (file)
@@ -546,6 +546,7 @@ static struct usb_serial_driver keyspan_pre_device = {
                .name           = "keyspan_no_firm",
        },
        .description            = "Keyspan - (without firmware)",
+       .usb_driver             = &keyspan_driver,
        .id_table               = keyspan_pre_ids,
        .num_ports              = 1,
        .attach                 = keyspan_fake_startup,
@@ -557,6 +558,7 @@ static struct usb_serial_driver keyspan_1port_device = {
                .name           = "keyspan_1",
        },
        .description            = "Keyspan 1 port adapter",
+       .usb_driver             = &keyspan_driver,
        .id_table               = keyspan_1port_ids,
        .num_ports              = 1,
        .open                   = keyspan_open,
@@ -579,6 +581,7 @@ static struct usb_serial_driver keyspan_2port_device = {
                .name           = "keyspan_2",
        },
        .description            = "Keyspan 2 port adapter",
+       .usb_driver             = &keyspan_driver,
        .id_table               = keyspan_2port_ids,
        .num_ports              = 2,
        .open                   = keyspan_open,
@@ -601,6 +604,7 @@ static struct usb_serial_driver keyspan_4port_device = {
                .name           = "keyspan_4",
        },
        .description            = "Keyspan 4 port adapter",
+       .usb_driver             = &keyspan_driver,
        .id_table               = keyspan_4port_ids,
        .num_ports              = 4,
        .open                   = keyspan_open,
index a10dd56..554a869 100644 (file)
@@ -679,22 +679,6 @@ static void keyspan_pda_dtr_rts(struct usb_serial_port *port, int on)
        }
 }
 
-static int keyspan_pda_carrier_raised(struct usb_serial_port *port)
-{
-       struct usb_serial *serial = port->serial;
-       unsigned char modembits;
-
-       /* If we can read the modem status and the DCD is low then
-          carrier is not raised yet */
-       if (keyspan_pda_get_modem_info(serial, &modembits) >= 0) {
-               if (!(modembits & (1>>6)))
-                       return 0;
-       }
-       /* Carrier raised, or we failed (eg disconnected) so
-          progress accordingly */
-       return 1;
-}
-
 
 static int keyspan_pda_open(struct tty_struct *tty,
                                        struct usb_serial_port *port)
@@ -881,7 +865,6 @@ static struct usb_serial_driver keyspan_pda_device = {
        .id_table =             id_table_std,
        .num_ports =            1,
        .dtr_rts =              keyspan_pda_dtr_rts,
-       .carrier_raised =       keyspan_pda_carrier_raised,
        .open =                 keyspan_pda_open,
        .close =                keyspan_pda_close,
        .write =                keyspan_pda_write,
index cf17183..653465f 100644 (file)
@@ -44,6 +44,7 @@ static struct usb_serial_driver moto_device = {
                .name =         "moto-modem",
        },
        .id_table =             id_table,
+       .usb_driver =           &moto_driver,
        .num_ports =            1,
 };
 
index 7487782..5f46838 100644 (file)
@@ -382,7 +382,16 @@ static void option_instat_callback(struct urb *urb);
 #define HAIER_VENDOR_ID                                0x201e
 #define HAIER_PRODUCT_CE100                    0x2009
 
-#define CINTERION_VENDOR_ID                    0x0681
+/* Cinterion (formerly Siemens) products */
+#define SIEMENS_VENDOR_ID                              0x0681
+#define CINTERION_VENDOR_ID                            0x1e2d
+#define CINTERION_PRODUCT_HC25_MDM             0x0047
+#define CINTERION_PRODUCT_HC25_MDMNET  0x0040
+#define CINTERION_PRODUCT_HC28_MDM             0x004C
+#define CINTERION_PRODUCT_HC28_MDMNET  0x004A /* same for HC28J */
+#define CINTERION_PRODUCT_EU3_E                        0x0051
+#define CINTERION_PRODUCT_EU3_P                        0x0052
+#define CINTERION_PRODUCT_PH8                  0x0053
 
 /* Olivetti products */
 #define OLIVETTI_VENDOR_ID                     0x0b3c
@@ -944,7 +953,17 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100F) },
        { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1011)},
        { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1012)},
-       { USB_DEVICE(CINTERION_VENDOR_ID, 0x0047) },
+       /* Cinterion */
+       { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_E) },
+       { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) },
+       { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8) },
+       { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, 
+       { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) },
+       { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDM) },
+       { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDMNET) },
+       { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, /* HC28 enumerates with Siemens or Cinterion VID depending on FW revision */
+       { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) },
+
        { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) },
        { USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */
        { USB_DEVICE(ONDA_VENDOR_ID, ONDA_MT825UP) }, /* ONDA MT825UP modem */
index 5be866b..7361320 100644 (file)
@@ -157,6 +157,7 @@ static struct usb_serial_driver oti6858_device = {
                .name =         "oti6858",
        },
        .id_table =             id_table,
+       .usb_driver =           &oti6858_driver,
        .num_ports =            1,
        .open =                 oti6858_open,
        .close =                oti6858_close,
index 8ae4c6c..08c9181 100644 (file)
@@ -50,6 +50,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) },
+       { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) },
        { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
        { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
        { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
@@ -677,9 +678,11 @@ static void pl2303_update_line_status(struct usb_serial_port *port,
 {
 
        struct pl2303_private *priv = usb_get_serial_port_data(port);
+       struct tty_struct *tty;
        unsigned long flags;
        u8 status_idx = UART_STATE;
        u8 length = UART_STATE + 1;
+       u8 prev_line_status;
        u16 idv, idp;
 
        idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
@@ -701,11 +704,20 @@ static void pl2303_update_line_status(struct usb_serial_port *port,
 
        /* Save off the uart status for others to look at */
        spin_lock_irqsave(&priv->lock, flags);
+       prev_line_status = priv->line_status;
        priv->line_status = data[status_idx];
        spin_unlock_irqrestore(&priv->lock, flags);
        if (priv->line_status & UART_BREAK_ERROR)
                usb_serial_handle_break(port);
        wake_up_interruptible(&priv->delta_msr_wait);
+
+       tty = tty_port_tty_get(&port->port);
+       if (!tty)
+               return;
+       if ((priv->line_status ^ prev_line_status) & UART_DCD)
+               usb_serial_handle_dcd_change(port, tty,
+                               priv->line_status & UART_DCD);
+       tty_kref_put(tty);
 }
 
 static void pl2303_read_int_callback(struct urb *urb)
index 43eb9bd..1b025f7 100644 (file)
@@ -21,6 +21,7 @@
 #define PL2303_PRODUCT_ID_MMX          0x0612
 #define PL2303_PRODUCT_ID_GPRS         0x0609
 #define PL2303_PRODUCT_ID_HCR331       0x331a
+#define PL2303_PRODUCT_ID_MOTOROLA     0x0307
 
 #define ATEN_VENDOR_ID         0x0557
 #define ATEN_VENDOR_ID2                0x0547
index 214a3e5..30b73e6 100644 (file)
@@ -36,6 +36,7 @@
 #define UTSTARCOM_PRODUCT_UM175_V1             0x3712
 #define UTSTARCOM_PRODUCT_UM175_V2             0x3714
 #define UTSTARCOM_PRODUCT_UM175_ALLTEL         0x3715
+#define PANTECH_PRODUCT_UML290_VZW             0x3718
 
 /* CMOTECH devices */
 #define CMOTECH_VENDOR_ID                      0x16d8
@@ -66,6 +67,7 @@ static struct usb_device_id id_table[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(LG_VENDOR_ID, LG_PRODUCT_VX4400_6000, 0xff, 0xff, 0x00) },
        { USB_DEVICE_AND_INTERFACE_INFO(SANYO_VENDOR_ID, SANYO_PRODUCT_KATANA_LX, 0xff, 0xff, 0x00) },
        { USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_U520, 0xff, 0x00, 0x00) },
+       { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xff, 0xff) },
        { },
 };
 MODULE_DEVICE_TABLE(usb, id_table);
@@ -84,6 +86,7 @@ static struct usb_serial_driver qcaux_device = {
                .name =         "qcaux",
        },
        .id_table =             id_table,
+       .usb_driver =           &qcaux_driver,
        .num_ports =            1,
 };
 
index cb8195c..74cd4cc 100644 (file)
@@ -42,6 +42,7 @@ static struct usb_serial_driver siemens_usb_mpi_device = {
                .name =         "siemens_mpi",
        },
        .id_table =             id_table,
+       .usb_driver =           &siemens_usb_mpi_driver,
        .num_ports =            1,
 };
 
index 7481ff8..0457813 100644 (file)
@@ -301,6 +301,9 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x1199, 0x68A3),   /* Sierra Wireless Direct IP modems */
          .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
        },
+       { USB_DEVICE(0x0f3d, 0x68A3),   /* Airprime/Sierra Wireless Direct IP modems */
+         .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
+       },
        { USB_DEVICE(0x413C, 0x08133) }, /* Dell Computer Corp. Wireless 5720 VZW Mobile Broadband (EVDO Rev-A) Minicard GPS Port */
 
        { }
index 765aa98..cbfb70b 100644 (file)
@@ -133,7 +133,7 @@ struct spcp8x5_usb_ctrl_arg {
 
 /* how come ??? */
 #define UART_STATE                     0x08
-#define UART_STATE_TRANSIENT_MASK      0x74
+#define UART_STATE_TRANSIENT_MASK      0x75
 #define UART_DCD                       0x01
 #define UART_DSR                       0x02
 #define UART_BREAK_ERROR               0x04
@@ -525,6 +525,10 @@ static void spcp8x5_process_read_urb(struct urb *urb)
                /* overrun is special, not associated with a char */
                if (status & UART_OVERRUN_ERROR)
                        tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+
+               if (status & UART_DCD)
+                       usb_serial_handle_dcd_change(port, tty,
+                                  priv->line_status & MSR_STATUS_LINE_DCD);
        }
 
        tty_insert_flip_string_fixed_flag(tty, data, tty_flag,
@@ -645,6 +649,7 @@ static struct usb_serial_driver spcp8x5_device = {
                .name =         "SPCP8x5",
        },
        .id_table               = id_table,
+       .usb_driver             = &spcp8x5_driver,
        .num_ports              = 1,
        .open                   = spcp8x5_open,
        .dtr_rts                = spcp8x5_dtr_rts,
index b2902f3..a910004 100644 (file)
@@ -369,9 +369,9 @@ failed_1port:
 
 static void __exit ti_exit(void)
 {
+       usb_deregister(&ti_usb_driver);
        usb_serial_deregister(&ti_1port_device);
        usb_serial_deregister(&ti_2port_device);
-       usb_deregister(&ti_usb_driver);
 }
 
 
index 6954de5..546a521 100644 (file)
@@ -1344,11 +1344,15 @@ int usb_serial_register(struct usb_serial_driver *driver)
                return -ENODEV;
 
        fixup_generic(driver);
-       if (driver->usb_driver)
-               driver->usb_driver->supports_autosuspend = 1;
 
        if (!driver->description)
                driver->description = driver->driver.name;
+       if (!driver->usb_driver) {
+               WARN(1, "Serial driver %s has no usb_driver\n",
+                               driver->description);
+               return -EINVAL;
+       }
+       driver->usb_driver->supports_autosuspend = 1;
 
        /* Add this device to our list of devices */
        mutex_lock(&table_lock);
index f2ed6a3..95a8214 100644 (file)
@@ -75,6 +75,7 @@ static struct usb_serial_driver debug_device = {
                .name =         "debug",
        },
        .id_table =             id_table,
+       .usb_driver =           &debug_driver,
        .num_ports =            1,
        .bulk_out_size =        USB_DEBUG_MAX_PACKET_SIZE,
        .break_ctl =            usb_debug_break_ctl,
index b004b2a..9c014e2 100644 (file)
@@ -295,12 +295,15 @@ static void usb_wwan_indat_callback(struct urb *urb)
                    __func__, status, endpoint);
        } else {
                tty = tty_port_tty_get(&port->port);
-               if (urb->actual_length) {
-                       tty_insert_flip_string(tty, data, urb->actual_length);
-                       tty_flip_buffer_push(tty);
-               } else
-                       dbg("%s: empty read urb received", __func__);
-               tty_kref_put(tty);
+               if (tty) {
+                       if (urb->actual_length) {
+                               tty_insert_flip_string(tty, data,
+                                               urb->actual_length);
+                               tty_flip_buffer_push(tty);
+                       } else
+                               dbg("%s: empty read urb received", __func__);
+                       tty_kref_put(tty);
+               }
 
                /* Resubmit urb so we continue receiving */
                if (status != -ESHUTDOWN) {
index 15a5d89..1c11959 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/uaccess.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
+#include <linux/usb/cdc.h>
 #include "visor.h"
 
 /*
@@ -479,6 +480,17 @@ static int visor_probe(struct usb_serial *serial,
 
        dbg("%s", __func__);
 
+       /*
+        * some Samsung Android phones in modem mode have the same ID
+        * as SPH-I500, but they are ACM devices, so dont bind to them
+        */
+       if (id->idVendor == SAMSUNG_VENDOR_ID &&
+               id->idProduct == SAMSUNG_SPH_I500_ID &&
+               serial->dev->descriptor.bDeviceClass == USB_CLASS_COMM &&
+               serial->dev->descriptor.bDeviceSubClass ==
+                       USB_CDC_SUBCLASS_ACM)
+               return -ENODEV;
+
        if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
                dev_err(&serial->dev->dev, "active config #%d != 1 ??\n",
                        serial->dev->actconfig->desc.bConfigurationValue);
index c854fde..2c85530 100644 (file)
@@ -31,4 +31,9 @@ UNUSUAL_DEV(  0x04b4, 0x6831, 0x0000, 0x9999,
                "Cypress ISD-300LP",
                USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0),
 
+UNUSUAL_DEV( 0x14cd, 0x6116, 0x0000, 0x9999,
+               "Super Top",
+               "USB 2.0  SATA BRIDGE",
+               USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0),
+
 #endif /* defined(CONFIG_USB_STORAGE_CYPRESS_ATACB) || ... */
index fcc1e32..c1602b8 100644 (file)
@@ -1044,6 +1044,15 @@ UNUSUAL_DEV(  0x084d, 0x0011, 0x0110, 0x0110,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_BULK32),
 
+/* Reported by <ttkspam@free.fr>
+ * The device reports a vendor-specific device class, requiring an
+ * explicit vendor/product match.
+ */
+UNUSUAL_DEV(  0x0851, 0x1542, 0x0002, 0x0002,
+               "MagicPixel",
+               "FW_Omega2",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL, 0),
+
 /* Andrew Lunn <andrew@lunn.ch>
  * PanDigital Digital Picture Frame. Does not like ALLOW_MEDIUM_REMOVAL
  * on LUN 4.
@@ -1388,6 +1397,13 @@ UNUSUAL_DEV(  0x0f19, 0x0105, 0x0100, 0x0100,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_IGNORE_RESIDUE ),
 
+/* Submitted by Nick Holloway */
+UNUSUAL_DEV( 0x0f88, 0x042e, 0x0100, 0x0100,
+               "VTech",
+               "Kidizoom",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_FIX_CAPACITY ),
+
 /* Reported by Michael Stattmann <michael@stattmann.com> */
 UNUSUAL_DEV(  0x0fce, 0xd008, 0x0000, 0x0000,
                "Sony Ericsson",
@@ -1872,6 +1888,22 @@ UNUSUAL_DEV( 0x1908, 0x3335, 0x0200, 0x0200,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_NO_READ_DISC_INFO ),
 
+/* Patch by Richard Schütz <r.schtz@t-online.de>
+ * This external hard drive enclosure uses a JMicron chip which
+ * needs the US_FL_IGNORE_RESIDUE flag to work properly. */
+UNUSUAL_DEV(  0x1e68, 0x001b, 0x0000, 0x0000,
+               "TrekStor GmbH & Co. KG",
+               "DataStation maxi g.u",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_IGNORE_RESIDUE | US_FL_SANE_SENSE ),
+
+/* Reported by Jasper Mackenzie <scarletpimpernal@hotmail.com> */
+UNUSUAL_DEV( 0x1e74, 0x4621, 0x0000, 0x0000,
+               "Coby Electronics",
+               "MP3 Player",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_BULK_IGNORE_TAG | US_FL_MAX_SECTORS_64 ),
+
 UNUSUAL_DEV( 0x2116, 0x0320, 0x0001, 0x0001,
                "ST",
                "2A",
index 9b3ca10..f616cef 100644 (file)
@@ -128,8 +128,7 @@ static void handle_tx(struct vhost_net *net)
        size_t hdr_size;
        struct socket *sock;
 
-       /* TODO: check that we are running from vhost_worker?
-        * Not sure it's worth it, it's straight-forward enough. */
+       /* TODO: check that we are running from vhost_worker? */
        sock = rcu_dereference_check(vq->private_data, 1);
        if (!sock)
                return;
@@ -306,7 +305,8 @@ static void handle_rx_big(struct vhost_net *net)
        size_t len, total_len = 0;
        int err;
        size_t hdr_size;
-       struct socket *sock = rcu_dereference(vq->private_data);
+       /* TODO: check that we are running from vhost_worker? */
+       struct socket *sock = rcu_dereference_check(vq->private_data, 1);
        if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
                return;
 
@@ -415,7 +415,8 @@ static void handle_rx_mergeable(struct vhost_net *net)
        int err, headcount;
        size_t vhost_hlen, sock_hlen;
        size_t vhost_len, sock_len;
-       struct socket *sock = rcu_dereference(vq->private_data);
+       /* TODO: check that we are running from vhost_worker? */
+       struct socket *sock = rcu_dereference_check(vq->private_data, 1);
        if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
                return;
 
index 2af44b7..b3363ae 100644 (file)
@@ -173,9 +173,9 @@ static inline int vhost_has_feature(struct vhost_dev *dev, int bit)
 {
        unsigned acked_features;
 
-       acked_features =
-               rcu_dereference_index_check(dev->acked_features,
-                                           lockdep_is_held(&dev->mutex));
+       /* TODO: check that we are running from vhost_worker or dev mutex is
+        * held? */
+       acked_features = rcu_dereference_index_check(dev->acked_features, 1);
        return acked_features & (1 << bit);
 }
 
index d583bea..391ac93 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/svga.h>
 #include <linux/init.h>
 #include <linux/pci.h>
-#include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */
+#include <linux/console.h> /* Why should fb driver call console functions? because console_lock() */
 #include <video/vga.h>
 
 #ifdef CONFIG_MTRR
@@ -1091,12 +1091,12 @@ static int ark_pci_suspend (struct pci_dev* dev, pm_message_t state)
 
        dev_info(info->device, "suspend\n");
 
-       acquire_console_sem();
+       console_lock();
        mutex_lock(&(par->open_lock));
 
        if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) {
                mutex_unlock(&(par->open_lock));
-               release_console_sem();
+               console_unlock();
                return 0;
        }
 
@@ -1107,7 +1107,7 @@ static int ark_pci_suspend (struct pci_dev* dev, pm_message_t state)
        pci_set_power_state(dev, pci_choose_state(dev, state));
 
        mutex_unlock(&(par->open_lock));
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
@@ -1122,7 +1122,7 @@ static int ark_pci_resume (struct pci_dev* dev)
 
        dev_info(info->device, "resume\n");
 
-       acquire_console_sem();
+       console_lock();
        mutex_lock(&(par->open_lock));
 
        if (par->ref_count == 0)
@@ -1141,7 +1141,7 @@ static int ark_pci_resume (struct pci_dev* dev)
 
 fail:
        mutex_unlock(&(par->open_lock));
-       release_console_sem();
+       console_unlock();
        return 0;
 }
 #else
index dd9de2e..4cb6a57 100644 (file)
@@ -1860,11 +1860,11 @@ static void aty128_early_resume(void *data)
 {
         struct aty128fb_par *par = data;
 
-       if (try_acquire_console_sem())
+       if (!console_trylock())
                return;
        pci_restore_state(par->pdev);
        aty128_do_resume(par->pdev);
-       release_console_sem();
+       console_unlock();
 }
 #endif /* CONFIG_PPC_PMAC */
 
@@ -2438,7 +2438,7 @@ static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 
        printk(KERN_DEBUG "aty128fb: suspending...\n");
        
-       acquire_console_sem();
+       console_lock();
 
        fb_set_suspend(info, 1);
 
@@ -2470,7 +2470,7 @@ static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        if (state.event != PM_EVENT_ON)
                aty128_set_suspend(par, 1);
 
-       release_console_sem();
+       console_unlock();
 
        pdev->dev.power.power_state = state;
 
@@ -2527,9 +2527,9 @@ static int aty128_pci_resume(struct pci_dev *pdev)
 {
        int rc;
 
-       acquire_console_sem();
+       console_lock();
        rc = aty128_do_resume(pdev);
-       release_console_sem();
+       console_unlock();
 
        return rc;
 }
index 767ab4f..94e293f 100644 (file)
@@ -2069,7 +2069,7 @@ static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        if (state.event == pdev->dev.power.power_state.event)
                return 0;
 
-       acquire_console_sem();
+       console_lock();
 
        fb_set_suspend(info, 1);
 
@@ -2097,14 +2097,14 @@ static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
                par->lock_blank = 0;
                atyfb_blank(FB_BLANK_UNBLANK, info);
                fb_set_suspend(info, 0);
-               release_console_sem();
+               console_unlock();
                return -EIO;
        }
 #else
        pci_set_power_state(pdev, pci_choose_state(pdev, state));
 #endif
 
-       release_console_sem();
+       console_unlock();
 
        pdev->dev.power.power_state = state;
 
@@ -2133,7 +2133,7 @@ static int atyfb_pci_resume(struct pci_dev *pdev)
        if (pdev->dev.power.power_state.event == PM_EVENT_ON)
                return 0;
 
-       acquire_console_sem();
+       console_lock();
 
        /*
         * PCI state will have been restored by the core, so
@@ -2161,7 +2161,7 @@ static int atyfb_pci_resume(struct pci_dev *pdev)
        par->lock_blank = 0;
        atyfb_blank(FB_BLANK_UNBLANK, info);
 
-       release_console_sem();
+       console_unlock();
 
        pdev->dev.power.power_state = PMSG_ON;
 
index c4e1764..92bda58 100644 (file)
@@ -2626,7 +2626,7 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
                goto done;
        }
 
-       acquire_console_sem();
+       console_lock();
 
        fb_set_suspend(info, 1);
 
@@ -2690,7 +2690,7 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
        if (rinfo->pm_mode & radeon_pm_d2)
                radeon_set_suspend(rinfo, 1);
 
-       release_console_sem();
+       console_unlock();
 
  done:
        pdev->dev.power.power_state = mesg;
@@ -2715,10 +2715,10 @@ int radeonfb_pci_resume(struct pci_dev *pdev)
                return 0;
 
        if (rinfo->no_schedule) {
-               if (try_acquire_console_sem())
+               if (!console_trylock())
                        return 0;
        } else
-               acquire_console_sem();
+               console_lock();
 
        printk(KERN_DEBUG "radeonfb (%s): resuming from state: %d...\n",
               pci_name(pdev), pdev->dev.power.power_state.event);
@@ -2783,7 +2783,7 @@ int radeonfb_pci_resume(struct pci_dev *pdev)
        pdev->dev.power.power_state = PMSG_ON;
 
  bail:
-       release_console_sem();
+       console_unlock();
 
        return rc;
 }
index 8010aae..dd0e84a 100644 (file)
@@ -239,11 +239,15 @@ static int __devinit ltv350qv_probe(struct spi_device *spi)
        lcd->spi = spi;
        lcd->power = FB_BLANK_POWERDOWN;
        lcd->buffer = kzalloc(8, GFP_KERNEL);
+       if (!lcd->buffer) {
+               ret = -ENOMEM;
+               goto out_free_lcd;
+       }
 
        ld = lcd_device_register("ltv350qv", &spi->dev, lcd, &ltv_ops);
        if (IS_ERR(ld)) {
                ret = PTR_ERR(ld);
-               goto out_free_lcd;
+               goto out_free_buffer;
        }
        lcd->ld = ld;
 
@@ -257,6 +261,8 @@ static int __devinit ltv350qv_probe(struct spi_device *spi)
 
 out_unregister:
        lcd_device_unregister(ld);
+out_free_buffer:
+       kfree(lcd->buffer);
 out_free_lcd:
        kfree(lcd);
        return ret;
@@ -268,6 +274,7 @@ static int __devexit ltv350qv_remove(struct spi_device *spi)
 
        ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
        lcd_device_unregister(lcd->ld);
+       kfree(lcd->buffer);
        kfree(lcd);
 
        return 0;
index 18c5078..47c21fb 100644 (file)
@@ -696,6 +696,7 @@ static int __devinit bfin_lq035_probe(struct platform_device *pdev)
 {
        struct backlight_properties props;
        dma_addr_t dma_handle;
+       int ret;
 
        if (request_dma(CH_PPI, KBUILD_MODNAME)) {
                pr_err("couldn't request PPI DMA\n");
@@ -704,17 +705,16 @@ static int __devinit bfin_lq035_probe(struct platform_device *pdev)
 
        if (request_ports()) {
                pr_err("couldn't request gpio port\n");
-               free_dma(CH_PPI);
-               return -EFAULT;
+               ret = -EFAULT;
+               goto out_ports;
        }
 
        fb_buffer = dma_alloc_coherent(NULL, TOTAL_VIDEO_MEM_SIZE,
                                       &dma_handle, GFP_KERNEL);
        if (fb_buffer == NULL) {
                pr_err("couldn't allocate dma buffer\n");
-               free_dma(CH_PPI);
-               free_ports();
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out_dma_coherent;
        }
 
        if (L1_DATA_A_LENGTH)
@@ -725,10 +725,8 @@ static int __devinit bfin_lq035_probe(struct platform_device *pdev)
 
        if (dma_desc_table == NULL) {
                pr_err("couldn't allocate dma descriptor\n");
-               free_dma(CH_PPI);
-               free_ports();
-               dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out_table;
        }
 
        bfin_lq035_fb.screen_base = (void *)fb_buffer;
@@ -771,31 +769,21 @@ static int __devinit bfin_lq035_probe(struct platform_device *pdev)
        bfin_lq035_fb.pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL);
        if (bfin_lq035_fb.pseudo_palette == NULL) {
                pr_err("failed to allocate pseudo_palette\n");
-               free_dma(CH_PPI);
-               free_ports();
-               dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out_palette;
        }
 
        if (fb_alloc_cmap(&bfin_lq035_fb.cmap, NBR_PALETTE, 0) < 0) {
                pr_err("failed to allocate colormap (%d entries)\n",
                        NBR_PALETTE);
-               free_dma(CH_PPI);
-               free_ports();
-               dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0);
-               kfree(bfin_lq035_fb.pseudo_palette);
-               return -EFAULT;
+               ret = -EFAULT;
+               goto out_cmap;
        }
 
        if (register_framebuffer(&bfin_lq035_fb) < 0) {
                pr_err("unable to register framebuffer\n");
-               free_dma(CH_PPI);
-               free_ports();
-               dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0);
-               fb_buffer = NULL;
-               kfree(bfin_lq035_fb.pseudo_palette);
-               fb_dealloc_cmap(&bfin_lq035_fb.cmap);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out_reg;
        }
 
        i2c_add_driver(&ad5280_driver);
@@ -807,11 +795,31 @@ static int __devinit bfin_lq035_probe(struct platform_device *pdev)
 
        lcd_dev = lcd_device_register(KBUILD_MODNAME, &pdev->dev, NULL,
                                      &bfin_lcd_ops);
+       if (IS_ERR(lcd_dev)) {
+               pr_err("unable to register lcd\n");
+               ret = PTR_ERR(lcd_dev);
+               goto out_lcd;
+       }
        lcd_dev->props.max_contrast = 255,
 
        pr_info("initialized");
 
        return 0;
+out_lcd:
+       unregister_framebuffer(&bfin_lq035_fb);
+out_reg:
+       fb_dealloc_cmap(&bfin_lq035_fb.cmap);
+out_cmap:
+       kfree(bfin_lq035_fb.pseudo_palette);
+out_palette:
+out_table:
+       dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0);
+       fb_buffer = NULL;
+out_dma_coherent:
+       free_ports();
+out_ports:
+       free_dma(CH_PPI);
+       return ret;
 }
 
 static int __devexit bfin_lq035_remove(struct platform_device *pdev)
index d637e1f..cff742a 100644 (file)
@@ -460,10 +460,10 @@ static int chipsfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        if (!(state.event & PM_EVENT_SLEEP))
                goto done;
 
-       acquire_console_sem();
+       console_lock();
        chipsfb_blank(1, p);
        fb_set_suspend(p, 1);
-       release_console_sem();
+       console_unlock();
  done:
        pdev->dev.power.power_state = state;
        return 0;
@@ -473,10 +473,10 @@ static int chipsfb_pci_resume(struct pci_dev *pdev)
 {
         struct fb_info *p = pci_get_drvdata(pdev);
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(p, 0);
        chipsfb_blank(0, p);
-       release_console_sem();
+       console_unlock();
 
        pdev->dev.power.power_state = PMSG_ON;
        return 0;
index 7ccc967..9c092b8 100644 (file)
@@ -375,14 +375,14 @@ static void fb_flashcursor(struct work_struct *work)
        int c;
        int mode;
 
-       acquire_console_sem();
+       console_lock();
        if (ops && ops->currcon != -1)
                vc = vc_cons[ops->currcon].d;
 
        if (!vc || !CON_IS_VISIBLE(vc) ||
            registered_fb[con2fb_map[vc->vc_num]] != info ||
            vc->vc_deccm != 1) {
-               release_console_sem();
+               console_unlock();
                return;
        }
 
@@ -392,7 +392,7 @@ static void fb_flashcursor(struct work_struct *work)
                CM_ERASE : CM_DRAW;
        ops->cursor(vc, info, mode, softback_lines, get_color(vc, info, c, 1),
                    get_color(vc, info, c, 0));
-       release_console_sem();
+       console_unlock();
 }
 
 static void cursor_timer_handler(unsigned long dev_addr)
@@ -836,7 +836,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
 
        found = search_fb_in_map(newidx);
 
-       acquire_console_sem();
+       console_lock();
        con2fb_map[unit] = newidx;
        if (!err && !found)
                err = con2fb_acquire_newinfo(vc, info, unit, oldidx);
@@ -863,7 +863,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
        if (!search_fb_in_map(info_idx))
                info_idx = newidx;
 
-       release_console_sem();
+       console_unlock();
        return err;
 }
 
@@ -3321,7 +3321,7 @@ static ssize_t store_rotate(struct device *device,
        if (fbcon_has_exited)
                return count;
 
-       acquire_console_sem();
+       console_lock();
        idx = con2fb_map[fg_console];
 
        if (idx == -1 || registered_fb[idx] == NULL)
@@ -3331,7 +3331,7 @@ static ssize_t store_rotate(struct device *device,
        rotate = simple_strtoul(buf, last, 0);
        fbcon_rotate(info, rotate);
 err:
-       release_console_sem();
+       console_unlock();
        return count;
 }
 
@@ -3346,7 +3346,7 @@ static ssize_t store_rotate_all(struct device *device,
        if (fbcon_has_exited)
                return count;
 
-       acquire_console_sem();
+       console_lock();
        idx = con2fb_map[fg_console];
 
        if (idx == -1 || registered_fb[idx] == NULL)
@@ -3356,7 +3356,7 @@ static ssize_t store_rotate_all(struct device *device,
        rotate = simple_strtoul(buf, last, 0);
        fbcon_rotate_all(info, rotate);
 err:
-       release_console_sem();
+       console_unlock();
        return count;
 }
 
@@ -3369,7 +3369,7 @@ static ssize_t show_rotate(struct device *device,
        if (fbcon_has_exited)
                return 0;
 
-       acquire_console_sem();
+       console_lock();
        idx = con2fb_map[fg_console];
 
        if (idx == -1 || registered_fb[idx] == NULL)
@@ -3378,7 +3378,7 @@ static ssize_t show_rotate(struct device *device,
        info = registered_fb[idx];
        rotate = fbcon_get_rotate(info);
 err:
-       release_console_sem();
+       console_unlock();
        return snprintf(buf, PAGE_SIZE, "%d\n", rotate);
 }
 
@@ -3392,7 +3392,7 @@ static ssize_t show_cursor_blink(struct device *device,
        if (fbcon_has_exited)
                return 0;
 
-       acquire_console_sem();
+       console_lock();
        idx = con2fb_map[fg_console];
 
        if (idx == -1 || registered_fb[idx] == NULL)
@@ -3406,7 +3406,7 @@ static ssize_t show_cursor_blink(struct device *device,
 
        blink = (ops->flags & FBCON_FLAGS_CURSOR_TIMER) ? 1 : 0;
 err:
-       release_console_sem();
+       console_unlock();
        return snprintf(buf, PAGE_SIZE, "%d\n", blink);
 }
 
@@ -3421,7 +3421,7 @@ static ssize_t store_cursor_blink(struct device *device,
        if (fbcon_has_exited)
                return count;
 
-       acquire_console_sem();
+       console_lock();
        idx = con2fb_map[fg_console];
 
        if (idx == -1 || registered_fb[idx] == NULL)
@@ -3443,7 +3443,7 @@ static ssize_t store_cursor_blink(struct device *device,
        }
 
 err:
-       release_console_sem();
+       console_unlock();
        return count;
 }
 
@@ -3482,7 +3482,7 @@ static void fbcon_start(void)
        if (num_registered_fb) {
                int i;
 
-               acquire_console_sem();
+               console_lock();
 
                for (i = 0; i < FB_MAX; i++) {
                        if (registered_fb[i] != NULL) {
@@ -3491,7 +3491,7 @@ static void fbcon_start(void)
                        }
                }
 
-               release_console_sem();
+               console_unlock();
                fbcon_takeover(0);
        }
 }
@@ -3552,7 +3552,7 @@ static int __init fb_console_init(void)
 {
        int i;
 
-       acquire_console_sem();
+       console_lock();
        fb_register_client(&fbcon_event_notifier);
        fbcon_device = device_create(fb_class, NULL, MKDEV(0, 0), NULL,
                                     "fbcon");
@@ -3568,7 +3568,7 @@ static int __init fb_console_init(void)
        for (i = 0; i < MAX_NR_CONSOLES; i++)
                con2fb_map[i] = -1;
 
-       release_console_sem();
+       console_unlock();
        fbcon_start();
        return 0;
 }
@@ -3591,12 +3591,12 @@ static void __exit fbcon_deinit_device(void)
 
 static void __exit fb_console_exit(void)
 {
-       acquire_console_sem();
+       console_lock();
        fb_unregister_client(&fbcon_event_notifier);
        fbcon_deinit_device();
        device_destroy(fb_class, MKDEV(0, 0));
        fbcon_exit();
-       release_console_sem();
+       console_unlock();
        unregister_con_driver(&fb_con);
 }      
 
index c97491b..915fd74 100644 (file)
@@ -202,11 +202,7 @@ static void vgacon_scrollback_init(int pitch)
        }
 }
 
-/*
- * Called only duing init so call of alloc_bootmen is ok.
- * Marked __init_refok to silence modpost.
- */
-static void __init_refok vgacon_scrollback_startup(void)
+static void vgacon_scrollback_startup(void)
 {
        vgacon_scrollback = kcalloc(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE, 1024, GFP_NOWAIT);
        vgacon_scrollback_init(vga_video_num_columns * 2);
index c265aed..8d61ef9 100644 (file)
@@ -1092,9 +1092,10 @@ static int __init fb_probe(struct platform_device *device)
 
 irq_freq:
 #ifdef CONFIG_CPU_FREQ
+       lcd_da8xx_cpufreq_deregister(par);
+#endif
 err_cpu_freq:
        unregister_framebuffer(da8xx_fb_info);
-#endif
 
 err_dealloc_cmap:
        fb_dealloc_cmap(&da8xx_fb_info->cmap);
@@ -1130,14 +1131,14 @@ static int fb_suspend(struct platform_device *dev, pm_message_t state)
        struct fb_info *info = platform_get_drvdata(dev);
        struct da8xx_fb_par *par = info->par;
 
-       acquire_console_sem();
+       console_lock();
        if (par->panel_power_ctrl)
                par->panel_power_ctrl(0);
 
        fb_set_suspend(info, 1);
        lcd_disable_raster();
        clk_disable(par->lcdc_clk);
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
@@ -1146,14 +1147,14 @@ static int fb_resume(struct platform_device *dev)
        struct fb_info *info = platform_get_drvdata(dev);
        struct da8xx_fb_par *par = info->par;
 
-       acquire_console_sem();
+       console_lock();
        if (par->panel_power_ctrl)
                par->panel_power_ctrl(1);
 
        clk_enable(par->lcdc_clk);
        lcd_enable_raster();
        fb_set_suspend(info, 0);
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
index 4ac1201..e2bf953 100644 (file)
@@ -1036,11 +1036,11 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
                        return -EFAULT;
                if (!lock_fb_info(info))
                        return -ENODEV;
-               acquire_console_sem();
+               console_lock();
                info->flags |= FBINFO_MISC_USEREVENT;
                ret = fb_set_var(info, &var);
                info->flags &= ~FBINFO_MISC_USEREVENT;
-               release_console_sem();
+               console_unlock();
                unlock_fb_info(info);
                if (!ret && copy_to_user(argp, &var, sizeof(var)))
                        ret = -EFAULT;
@@ -1072,9 +1072,9 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
                        return -EFAULT;
                if (!lock_fb_info(info))
                        return -ENODEV;
-               acquire_console_sem();
+               console_lock();
                ret = fb_pan_display(info, &var);
-               release_console_sem();
+               console_unlock();
                unlock_fb_info(info);
                if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))
                        return -EFAULT;
@@ -1119,11 +1119,11 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
        case FBIOBLANK:
                if (!lock_fb_info(info))
                        return -ENODEV;
-               acquire_console_sem();
+               console_lock();
                info->flags |= FBINFO_MISC_USEREVENT;
                ret = fb_blank(info, arg);
                info->flags &= ~FBINFO_MISC_USEREVENT;
-               release_console_sem();
+               console_unlock();
                unlock_fb_info(info);
                break;
        default:
index 0a08f13..f4a3277 100644 (file)
@@ -90,11 +90,11 @@ static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var)
        int err;
 
        var->activate |= FB_ACTIVATE_FORCE;
-       acquire_console_sem();
+       console_lock();
        fb_info->flags |= FBINFO_MISC_USEREVENT;
        err = fb_set_var(fb_info, var);
        fb_info->flags &= ~FBINFO_MISC_USEREVENT;
-       release_console_sem();
+       console_unlock();
        if (err)
                return err;
        return 0;
@@ -175,7 +175,7 @@ static ssize_t store_modes(struct device *device,
        if (i * sizeof(struct fb_videomode) != count)
                return -EINVAL;
 
-       acquire_console_sem();
+       console_lock();
        list_splice(&fb_info->modelist, &old_list);
        fb_videomode_to_modelist((const struct fb_videomode *)buf, i,
                                 &fb_info->modelist);
@@ -185,7 +185,7 @@ static ssize_t store_modes(struct device *device,
        } else
                fb_destroy_modelist(&old_list);
 
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
@@ -301,11 +301,11 @@ static ssize_t store_blank(struct device *device,
        char *last = NULL;
        int err;
 
-       acquire_console_sem();
+       console_lock();
        fb_info->flags |= FBINFO_MISC_USEREVENT;
        err = fb_blank(fb_info, simple_strtoul(buf, &last, 0));
        fb_info->flags &= ~FBINFO_MISC_USEREVENT;
-       release_console_sem();
+       console_unlock();
        if (err < 0)
                return err;
        return count;
@@ -364,9 +364,9 @@ static ssize_t store_pan(struct device *device,
                return -EINVAL;
        var.yoffset = simple_strtoul(last, &last, 0);
 
-       acquire_console_sem();
+       console_lock();
        err = fb_pan_display(fb_info, &var);
-       release_console_sem();
+       console_unlock();
 
        if (err < 0)
                return err;
@@ -399,9 +399,9 @@ static ssize_t store_fbstate(struct device *device,
 
        state = simple_strtoul(buf, &last, 0);
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(fb_info, (int)state);
-       release_console_sem();
+       console_unlock();
 
        return count;
 }
index 70b1d9d..b4f19db 100644 (file)
@@ -344,10 +344,10 @@ static int gxfb_suspend(struct pci_dev *pdev, pm_message_t state)
        struct fb_info *info = pci_get_drvdata(pdev);
 
        if (state.event == PM_EVENT_SUSPEND) {
-               acquire_console_sem();
+               console_lock();
                gx_powerdown(info);
                fb_set_suspend(info, 1);
-               release_console_sem();
+               console_unlock();
        }
 
        /* there's no point in setting PCI states; we emulate PCI, so
@@ -361,7 +361,7 @@ static int gxfb_resume(struct pci_dev *pdev)
        struct fb_info *info = pci_get_drvdata(pdev);
        int ret;
 
-       acquire_console_sem();
+       console_lock();
        ret = gx_powerup(info);
        if (ret) {
                printk(KERN_ERR "gxfb:  power up failed!\n");
@@ -369,7 +369,7 @@ static int gxfb_resume(struct pci_dev *pdev)
        }
 
        fb_set_suspend(info, 0);
-       release_console_sem();
+       console_unlock();
        return 0;
 }
 #endif
index 39bdbed..416851c 100644 (file)
@@ -465,10 +465,10 @@ static int lxfb_suspend(struct pci_dev *pdev, pm_message_t state)
        struct fb_info *info = pci_get_drvdata(pdev);
 
        if (state.event == PM_EVENT_SUSPEND) {
-               acquire_console_sem();
+               console_lock();
                lx_powerdown(info);
                fb_set_suspend(info, 1);
-               release_console_sem();
+               console_unlock();
        }
 
        /* there's no point in setting PCI states; we emulate PCI, so
@@ -482,7 +482,7 @@ static int lxfb_resume(struct pci_dev *pdev)
        struct fb_info *info = pci_get_drvdata(pdev);
        int ret;
 
-       acquire_console_sem();
+       console_lock();
        ret = lx_powerup(info);
        if (ret) {
                printk(KERN_ERR "lxfb:  power up failed!\n");
@@ -490,7 +490,7 @@ static int lxfb_resume(struct pci_dev *pdev)
        }
 
        fb_set_suspend(info, 0);
-       release_console_sem();
+       console_unlock();
        return 0;
 }
 #else
index 5743ea2..318f6fb 100644 (file)
@@ -1574,7 +1574,7 @@ static int i810fb_suspend(struct pci_dev *dev, pm_message_t mesg)
                return 0;
        }
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(info, 1);
 
        if (info->fbops->fb_sync)
@@ -1587,7 +1587,7 @@ static int i810fb_suspend(struct pci_dev *dev, pm_message_t mesg)
        pci_save_state(dev);
        pci_disable_device(dev);
        pci_set_power_state(dev, pci_choose_state(dev, mesg));
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
@@ -1605,7 +1605,7 @@ static int i810fb_resume(struct pci_dev *dev)
                return 0;
        }
 
-       acquire_console_sem();
+       console_lock();
        pci_set_power_state(dev, PCI_D0);
        pci_restore_state(dev);
 
@@ -1621,7 +1621,7 @@ static int i810fb_resume(struct pci_dev *dev)
        fb_set_suspend (info, 0);
        info->fbops->fb_blank(VESA_NO_BLANKING, info);
 fail:
-       release_console_sem();
+       console_unlock();
        return 0;
 }
 /***********************************************************************
index 670ecaa..de36693 100644 (file)
@@ -778,9 +778,9 @@ static int jzfb_suspend(struct device *dev)
 {
        struct jzfb *jzfb = dev_get_drvdata(dev);
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(jzfb->fb, 1);
-       release_console_sem();
+       console_unlock();
 
        mutex_lock(&jzfb->lock);
        if (jzfb->is_enabled)
@@ -800,9 +800,9 @@ static int jzfb_resume(struct device *dev)
                jzfb_enable(jzfb);
        mutex_unlock(&jzfb->lock);
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(jzfb->fb, 0);
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
index cb01391..7e3a490 100644 (file)
@@ -1177,9 +1177,9 @@ static int mx3fb_suspend(struct platform_device *pdev, pm_message_t state)
        struct mx3fb_data *mx3fb = platform_get_drvdata(pdev);
        struct mx3fb_info *mx3_fbi = mx3fb->fbi->par;
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(mx3fb->fbi, 1);
-       release_console_sem();
+       console_unlock();
 
        if (mx3_fbi->blank == FB_BLANK_UNBLANK) {
                sdc_disable_channel(mx3_fbi);
@@ -1202,9 +1202,9 @@ static int mx3fb_resume(struct platform_device *pdev)
                sdc_set_brightness(mx3fb, mx3fb->backlight_level);
        }
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(mx3fb->fbi, 0);
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
index 62498bd..f838d9e 100644 (file)
@@ -696,6 +696,8 @@ static int nuc900fb_remove(struct platform_device *pdev)
        nuc900fb_stop_lcd(fbinfo);
        msleep(1);
 
+       unregister_framebuffer(fbinfo);
+       nuc900fb_cpufreq_deregister(fbi);
        nuc900fb_unmap_video_memory(fbinfo);
 
        iounmap(fbi->io);
@@ -723,7 +725,7 @@ static int nuc900fb_suspend(struct platform_device *dev, pm_message_t state)
        struct fb_info     *fbinfo = platform_get_drvdata(dev);
        struct nuc900fb_info *info = fbinfo->par;
 
-       nuc900fb_stop_lcd();
+       nuc900fb_stop_lcd(fbinfo);
        msleep(1);
        clk_disable(info->clk);
        return 0;
@@ -740,7 +742,7 @@ static int nuc900fb_resume(struct platform_device *dev)
        msleep(1);
 
        nuc900fb_init_registers(fbinfo);
-       nuc900fb_activate_var(bfinfo);
+       nuc900fb_activate_var(fbinfo);
 
        return 0;
 }
index efe10ff..081dc47 100644 (file)
@@ -1057,7 +1057,7 @@ static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t mesg)
 
        if (mesg.event == PM_EVENT_PRETHAW)
                mesg.event = PM_EVENT_FREEZE;
-       acquire_console_sem();
+       console_lock();
        par->pm_state = mesg.event;
 
        if (mesg.event & PM_EVENT_SLEEP) {
@@ -1070,7 +1070,7 @@ static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t mesg)
        }
        dev->dev.power.power_state = mesg;
 
-       release_console_sem();
+       console_unlock();
        return 0;
 }
 
@@ -1079,7 +1079,7 @@ static int nvidiafb_resume(struct pci_dev *dev)
        struct fb_info *info = pci_get_drvdata(dev);
        struct nvidia_par *par = info->par;
 
-       acquire_console_sem();
+       console_lock();
        pci_set_power_state(dev, PCI_D0);
 
        if (par->pm_state != PM_EVENT_FREEZE) {
@@ -1097,7 +1097,7 @@ static int nvidiafb_resume(struct pci_dev *dev)
        nvidiafb_blank(FB_BLANK_UNBLANK, info);
 
 fail:
-       release_console_sem();
+       console_unlock();
        return 0;
 }
 #else
index 9c0144e..65560a1 100644 (file)
@@ -513,9 +513,9 @@ static int ps3fb_release(struct fb_info *info, int user)
        if (atomic_dec_and_test(&ps3fb.f_count)) {
                if (atomic_read(&ps3fb.ext_flip)) {
                        atomic_set(&ps3fb.ext_flip, 0);
-                       if (!try_acquire_console_sem()) {
+                       if (console_trylock()) {
                                ps3fb_sync(info, 0);    /* single buffer */
-                               release_console_sem();
+                               console_unlock();
                        }
                }
        }
@@ -830,14 +830,14 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
                        if (vmode) {
                                var = info->var;
                                fb_videomode_to_var(&var, vmode);
-                               acquire_console_sem();
+                               console_lock();
                                info->flags |= FBINFO_MISC_USEREVENT;
                                /* Force, in case only special bits changed */
                                var.activate |= FB_ACTIVATE_FORCE;
                                par->new_mode_id = val;
                                retval = fb_set_var(info, &var);
                                info->flags &= ~FBINFO_MISC_USEREVENT;
-                               release_console_sem();
+                               console_unlock();
                        }
                        break;
                }
@@ -881,9 +881,9 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
                        break;
 
                dev_dbg(info->device, "PS3FB_IOCTL_FSEL:%d\n", val);
-               acquire_console_sem();
+               console_lock();
                retval = ps3fb_sync(info, val);
-               release_console_sem();
+               console_unlock();
                break;
 
        default:
@@ -903,9 +903,9 @@ static int ps3fbd(void *arg)
                set_current_state(TASK_INTERRUPTIBLE);
                if (ps3fb.is_kicked) {
                        ps3fb.is_kicked = 0;
-                       acquire_console_sem();
+                       console_lock();
                        ps3fb_sync(info, 0);    /* single buffer */
-                       release_console_sem();
+                       console_unlock();
                }
                schedule();
        }
index cea6403..35f61dd 100644 (file)
@@ -701,16 +701,12 @@ static int __devinit pxa168fb_probe(struct platform_device *pdev)
         */
        pxa168fb_init_mode(info, mi);
 
-       ret = pxa168fb_check_var(&info->var, info);
-       if (ret)
-               goto failed_free_fbmem;
-
        /*
         * Fill in sane defaults.
         */
        ret = pxa168fb_check_var(&info->var, info);
        if (ret)
-               goto failed;
+               goto failed_free_fbmem;
 
        /*
         * enable controller clock
index b81168d..cf4beb9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  pxa3xx-gc.c - Linux kernel module for PXA3xx graphics controllers
+ *  pxa3xx-gcu.c - Linux kernel module for PXA3xx graphics controllers
  *
  *  This driver needs a DirectFB counterpart in user space, communication
  *  is handled via mmap()ed memory areas and an ioctl.
@@ -421,7 +421,7 @@ pxa3xx_gcu_misc_write(struct file *filp, const char *buff,
                buffer->next = priv->free;
                priv->free = buffer;
                spin_unlock_irqrestore(&priv->spinlock, flags);
-               return ret;
+               return -EFAULT;
        }
 
        buffer->length = words;
index dce8c97..75738a9 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/svga.h>
 #include <linux/init.h>
 #include <linux/pci.h>
-#include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */
+#include <linux/console.h> /* Why should fb driver call console functions? because console_lock() */
 #include <video/vga.h>
 
 #ifdef CONFIG_MTRR
@@ -1113,12 +1113,12 @@ static int s3_pci_suspend(struct pci_dev* dev, pm_message_t state)
 
        dev_info(info->device, "suspend\n");
 
-       acquire_console_sem();
+       console_lock();
        mutex_lock(&(par->open_lock));
 
        if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) {
                mutex_unlock(&(par->open_lock));
-               release_console_sem();
+               console_unlock();
                return 0;
        }
 
@@ -1129,7 +1129,7 @@ static int s3_pci_suspend(struct pci_dev* dev, pm_message_t state)
        pci_set_power_state(dev, pci_choose_state(dev, state));
 
        mutex_unlock(&(par->open_lock));
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
@@ -1145,12 +1145,12 @@ static int s3_pci_resume(struct pci_dev* dev)
 
        dev_info(info->device, "resume\n");
 
-       acquire_console_sem();
+       console_lock();
        mutex_lock(&(par->open_lock));
 
        if (par->ref_count == 0) {
                mutex_unlock(&(par->open_lock));
-               release_console_sem();
+               console_unlock();
                return 0;
        }
 
@@ -1159,7 +1159,7 @@ static int s3_pci_resume(struct pci_dev* dev)
        err = pci_enable_device(dev);
        if (err) {
                mutex_unlock(&(par->open_lock));
-               release_console_sem();
+               console_unlock();
                dev_err(info->device, "error %d enabling device for resume\n", err);
                return err;
        }
@@ -1169,7 +1169,7 @@ static int s3_pci_resume(struct pci_dev* dev)
        fb_set_suspend(info, 0);
 
        mutex_unlock(&(par->open_lock));
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
index 842d157..487911e 100644 (file)
@@ -2373,7 +2373,7 @@ static int savagefb_suspend(struct pci_dev *dev, pm_message_t mesg)
        if (mesg.event == PM_EVENT_FREEZE)
                return 0;
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(info, 1);
 
        if (info->fbops->fb_sync)
@@ -2385,7 +2385,7 @@ static int savagefb_suspend(struct pci_dev *dev, pm_message_t mesg)
        pci_save_state(dev);
        pci_disable_device(dev);
        pci_set_power_state(dev, pci_choose_state(dev, mesg));
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
@@ -2409,7 +2409,7 @@ static int savagefb_resume(struct pci_dev* dev)
                return 0;
        }
 
-       acquire_console_sem();
+       console_lock();
 
        pci_set_power_state(dev, PCI_D0);
        pci_restore_state(dev);
@@ -2423,7 +2423,7 @@ static int savagefb_resume(struct pci_dev* dev)
        savagefb_set_par(info);
        fb_set_suspend(info, 0);
        savagefb_blank(FB_BLANK_UNBLANK, info);
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
index 74d9f54..2b9e56a 100644 (file)
@@ -1151,7 +1151,7 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
 
                ch = info->par;
 
-               acquire_console_sem();
+               console_lock();
 
                /* HDMI plug in */
                if (!sh_hdmi_must_reconfigure(hdmi) &&
@@ -1171,7 +1171,7 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
                        fb_set_suspend(info, 0);
                }
 
-               release_console_sem();
+               console_unlock();
        } else {
                ret = 0;
                if (!hdmi->info)
@@ -1181,12 +1181,12 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
                fb_destroy_modedb(hdmi->monspec.modedb);
                hdmi->monspec.modedb = NULL;
 
-               acquire_console_sem();
+               console_lock();
 
                /* HDMI disconnect */
                fb_set_suspend(hdmi->info, 1);
 
-               release_console_sem();
+               console_unlock();
                pm_runtime_put(hdmi->dev);
        }
 
index bd4840a..bf12e53 100644 (file)
@@ -912,9 +912,9 @@ static int sh_mobile_release(struct fb_info *info, int user)
 
        /* Nothing to reconfigure, when called from fbcon */
        if (user) {
-               acquire_console_sem();
+               console_lock();
                sh_mobile_fb_reconfig(info);
-               release_console_sem();
+               console_unlock();
        }
 
        mutex_unlock(&ch->open_lock);
index b7dc180..bcb44a5 100644 (file)
@@ -2010,9 +2010,9 @@ static int sm501fb_suspend_fb(struct sm501fb_info *info,
 
        /* tell console/fb driver we are suspending */
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(fbi, 1);
-       release_console_sem();
+       console_unlock();
 
        /* backup copies in case chip is powered down over suspend */
 
@@ -2069,9 +2069,9 @@ static void sm501fb_resume_fb(struct sm501fb_info *info,
                memcpy_toio(par->cursor.k_addr, par->store_cursor,
                            par->cursor.size);
 
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(fbi, 0);
-       release_console_sem();
+       console_unlock();
 
        vfree(par->store_fb);
        vfree(par->store_cursor);
index 6913fe1..dfef88c 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/fb.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-/* Why should fb driver call console functions? because acquire_console_sem() */
+/* Why should fb driver call console functions? because console_lock() */
 #include <linux/console.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/tmio.h>
@@ -944,7 +944,7 @@ static int tmiofb_suspend(struct platform_device *dev, pm_message_t state)
        struct mfd_cell *cell = dev->dev.platform_data;
        int retval = 0;
 
-       acquire_console_sem();
+       console_lock();
 
        fb_set_suspend(info, 1);
 
@@ -965,7 +965,7 @@ static int tmiofb_suspend(struct platform_device *dev, pm_message_t state)
        if (cell->suspend)
                retval = cell->suspend(dev);
 
-       release_console_sem();
+       console_unlock();
 
        return retval;
 }
@@ -976,7 +976,7 @@ static int tmiofb_resume(struct platform_device *dev)
        struct mfd_cell *cell = dev->dev.platform_data;
        int retval = 0;
 
-       acquire_console_sem();
+       console_lock();
 
        if (cell->resume) {
                retval = cell->resume(dev);
@@ -992,7 +992,7 @@ static int tmiofb_resume(struct platform_device *dev)
 
        fb_set_suspend(info, 0);
 out:
-       release_console_sem();
+       console_unlock();
        return retval;
 }
 #else
index 289edd5..4e66349 100644 (file)
@@ -1674,17 +1674,17 @@ static int parse_mode(const char *str, u32 *xres, u32 *yres)
 #ifdef CONFIG_PM
 static int viafb_suspend(void *unused)
 {
-       acquire_console_sem();
+       console_lock();
        fb_set_suspend(viafbinfo, 1);
        viafb_sync(viafbinfo);
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
 
 static int viafb_resume(void *unused)
 {
-       acquire_console_sem();
+       console_lock();
        if (viaparinfo->shared->vdev->engine_mmio)
                viafb_reset_engine(viaparinfo);
        viafb_set_par(viafbinfo);
@@ -1692,7 +1692,7 @@ static int viafb_resume(void *unused)
                viafb_set_par(viafbinfo1);
        fb_set_suspend(viafbinfo, 0);
 
-       release_console_sem();
+       console_unlock();
        return 0;
 }
 
index 85d76ec..a2965ab 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/svga.h>
 #include <linux/init.h>
 #include <linux/pci.h>
-#include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */
+#include <linux/console.h> /* Why should fb driver call console functions? because console_lock() */
 #include <video/vga.h>
 
 #ifdef CONFIG_MTRR
@@ -819,12 +819,12 @@ static int vt8623_pci_suspend(struct pci_dev* dev, pm_message_t state)
 
        dev_info(info->device, "suspend\n");
 
-       acquire_console_sem();
+       console_lock();
        mutex_lock(&(par->open_lock));
 
        if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) {
                mutex_unlock(&(par->open_lock));
-               release_console_sem();
+               console_unlock();
                return 0;
        }
 
@@ -835,7 +835,7 @@ static int vt8623_pci_suspend(struct pci_dev* dev, pm_message_t state)
        pci_set_power_state(dev, pci_choose_state(dev, state));
 
        mutex_unlock(&(par->open_lock));
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
@@ -850,7 +850,7 @@ static int vt8623_pci_resume(struct pci_dev* dev)
 
        dev_info(info->device, "resume\n");
 
-       acquire_console_sem();
+       console_lock();
        mutex_lock(&(par->open_lock));
 
        if (par->ref_count == 0)
@@ -869,7 +869,7 @@ static int vt8623_pci_resume(struct pci_dev* dev)
 
 fail:
        mutex_unlock(&(par->open_lock));
-       release_console_sem();
+       console_unlock();
 
        return 0;
 }
index 3e6934d..a20218c 100644 (file)
@@ -491,12 +491,12 @@ xenfb_make_preferred_console(void)
        if (console_set_on_cmdline)
                return;
 
-       acquire_console_sem();
+       console_lock();
        for_each_console(c) {
                if (!strcmp(c->name, "tty") && c->index == 0)
                        break;
        }
-       release_console_sem();
+       console_unlock();
        if (c) {
                unregister_console(c);
                c->flags |= CON_CONSDEV;
index 3a7e9ff..38e96ab 100644 (file)
@@ -593,19 +593,17 @@ static int __devinit omap_hdq_probe(struct platform_device *pdev)
 
        /* get interface & functional clock objects */
        hdq_data->hdq_ick = clk_get(&pdev->dev, "ick");
-       hdq_data->hdq_fck = clk_get(&pdev->dev, "fck");
+       if (IS_ERR(hdq_data->hdq_ick)) {
+               dev_dbg(&pdev->dev, "Can't get HDQ ick clock object\n");
+               ret = PTR_ERR(hdq_data->hdq_ick);
+               goto err_ick;
+       }
 
-       if (IS_ERR(hdq_data->hdq_ick) || IS_ERR(hdq_data->hdq_fck)) {
-               dev_dbg(&pdev->dev, "Can't get HDQ clock objects\n");
-               if (IS_ERR(hdq_data->hdq_ick)) {
-                       ret = PTR_ERR(hdq_data->hdq_ick);
-                       goto err_clk;
-               }
-               if (IS_ERR(hdq_data->hdq_fck)) {
-                       ret = PTR_ERR(hdq_data->hdq_fck);
-                       clk_put(hdq_data->hdq_ick);
-                       goto err_clk;
-               }
+       hdq_data->hdq_fck = clk_get(&pdev->dev, "fck");
+       if (IS_ERR(hdq_data->hdq_fck)) {
+               dev_dbg(&pdev->dev, "Can't get HDQ fck clock object\n");
+               ret = PTR_ERR(hdq_data->hdq_fck);
+               goto err_fck;
        }
 
        hdq_data->hdq_usecount = 0;
@@ -665,10 +663,12 @@ err_fnclk:
        clk_disable(hdq_data->hdq_ick);
 
 err_intfclk:
-       clk_put(hdq_data->hdq_ick);
        clk_put(hdq_data->hdq_fck);
 
-err_clk:
+err_fck:
+       clk_put(hdq_data->hdq_ick);
+
+err_ick:
        iounmap(hdq_data->hdq_base);
 
 err_ioremap:
index 2e2400e..31649b7 100644 (file)
@@ -862,12 +862,12 @@ config SBC_EPX_C3_WATCHDOG
 
 # M68K Architecture
 
-config M548x_WATCHDOG
-       tristate "MCF548x watchdog support"
+config M54xx_WATCHDOG
+       tristate "MCF54xx watchdog support"
        depends on M548x
        help
          To compile this driver as a module, choose M here: the
-         module will be called m548x_wdt.
+         module will be called m54xx_wdt.
 
 # MIPS Architecture
 
index dd77665..20e44c4 100644 (file)
@@ -106,7 +106,7 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
 # M32R Architecture
 
 # M68K Architecture
-obj-$(CONFIG_M548x_WATCHDOG) += m548x_wdt.o
+obj-$(CONFIG_M54xx_WATCHDOG) += m54xx_wdt.o
 
 # MIPS Architecture
 obj-$(CONFIG_ATH79_WDT) += ath79_wdt.o
index eca855a..3de4ba0 100644 (file)
@@ -646,7 +646,7 @@ static int __devexit cpwd_remove(struct platform_device *op)
        struct cpwd *p = dev_get_drvdata(&op->dev);
        int i;
 
-       for (i = 0; i < 4; i++) {
+       for (i = 0; i < WD_NUMDEVS; i++) {
                misc_deregister(&p->devs[i].misc);
 
                if (!p->enabled) {
index 24b966d..204a560 100644 (file)
@@ -710,7 +710,7 @@ static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev)
        return 0;
 }
 
-static void __devexit hpwdt_exit_nmi_decoding(void)
+static void hpwdt_exit_nmi_decoding(void)
 {
        unregister_die_notifier(&die_notifier);
        if (cru_rom_addr)
@@ -726,7 +726,7 @@ static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev)
        return 0;
 }
 
-static void __devexit hpwdt_exit_nmi_decoding(void)
+static void hpwdt_exit_nmi_decoding(void)
 {
 }
 #endif /* CONFIG_HPWDT_NMI_DECODING */
diff --git a/drivers/watchdog/m548x_wdt.c b/drivers/watchdog/m548x_wdt.c
deleted file mode 100644 (file)
index cabbcfe..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * drivers/watchdog/m548x_wdt.c
- *
- * Watchdog driver for ColdFire MCF548x processors
- * Copyright 2010 (c) Philippe De Muyter <phdm@macqel.be>
- *
- * Adapted from the IXP4xx watchdog driver, which carries these notices:
- *
- *  Author: Deepak Saxena <dsaxena@plexity.net>
- *
- *  Copyright 2004 (c) MontaVista, Software, Inc.
- *  Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
- *
- * 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/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/ioport.h>
-#include <linux/uaccess.h>
-
-#include <asm/coldfire.h>
-#include <asm/m548xsim.h>
-#include <asm/m548xgpt.h>
-
-static int nowayout = WATCHDOG_NOWAYOUT;
-static unsigned int heartbeat = 30;    /* (secs) Default is 0.5 minute */
-static unsigned long wdt_status;
-
-#define        WDT_IN_USE              0
-#define        WDT_OK_TO_CLOSE         1
-
-static void wdt_enable(void)
-{
-       unsigned int gms0;
-
-       /* preserve GPIO usage, if any */
-       gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0);
-       if (gms0 & MCF_GPT_GMS_TMS_GPIO)
-               gms0 &= (MCF_GPT_GMS_TMS_GPIO | MCF_GPT_GMS_GPIO_MASK
-                                                       | MCF_GPT_GMS_OD);
-       else
-               gms0 = MCF_GPT_GMS_TMS_GPIO | MCF_GPT_GMS_OD;
-       __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
-       __raw_writel(MCF_GPT_GCIR_PRE(heartbeat*(MCF_BUSCLK/0xffff)) |
-                       MCF_GPT_GCIR_CNT(0xffff), MCF_MBAR + MCF_GPT_GCIR0);
-       gms0 |= MCF_GPT_GMS_OCPW(0xA5) | MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE;
-       __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
-}
-
-static void wdt_disable(void)
-{
-       unsigned int gms0;
-
-       /* disable watchdog */
-       gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0);
-       gms0 &= ~(MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE);
-       __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
-}
-
-static void wdt_keepalive(void)
-{
-       unsigned int gms0;
-
-       gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0);
-       gms0 |= MCF_GPT_GMS_OCPW(0xA5);
-       __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
-}
-
-static int m548x_wdt_open(struct inode *inode, struct file *file)
-{
-       if (test_and_set_bit(WDT_IN_USE, &wdt_status))
-               return -EBUSY;
-
-       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-       wdt_enable();
-       return nonseekable_open(inode, file);
-}
-
-static ssize_t m548x_wdt_write(struct file *file, const char *data,
-                                               size_t len, loff_t *ppos)
-{
-       if (len) {
-               if (!nowayout) {
-                       size_t i;
-
-                       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-                       for (i = 0; i != len; i++) {
-                               char c;
-
-                               if (get_user(c, data + i))
-                                       return -EFAULT;
-                               if (c == 'V')
-                                       set_bit(WDT_OK_TO_CLOSE, &wdt_status);
-                       }
-               }
-               wdt_keepalive();
-       }
-       return len;
-}
-
-static const struct watchdog_info ident = {
-       .options        = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
-                               WDIOF_KEEPALIVEPING,
-       .identity       = "Coldfire M548x Watchdog",
-};
-
-static long m548x_wdt_ioctl(struct file *file, unsigned int cmd,
-                                                        unsigned long arg)
-{
-       int ret = -ENOTTY;
-       int time;
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               ret = copy_to_user((struct watchdog_info *)arg, &ident,
-                                  sizeof(ident)) ? -EFAULT : 0;
-               break;
-
-       case WDIOC_GETSTATUS:
-               ret = put_user(0, (int *)arg);
-               break;
-
-       case WDIOC_GETBOOTSTATUS:
-               ret = put_user(0, (int *)arg);
-               break;
-
-       case WDIOC_KEEPALIVE:
-               wdt_keepalive();
-               ret = 0;
-               break;
-
-       case WDIOC_SETTIMEOUT:
-               ret = get_user(time, (int *)arg);
-               if (ret)
-                       break;
-
-               if (time <= 0 || time > 30) {
-                       ret = -EINVAL;
-                       break;
-               }
-
-               heartbeat = time;
-               wdt_enable();
-               /* Fall through */
-
-       case WDIOC_GETTIMEOUT:
-               ret = put_user(heartbeat, (int *)arg);
-               break;
-       }
-       return ret;
-}
-
-static int m548x_wdt_release(struct inode *inode, struct file *file)
-{
-       if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
-               wdt_disable();
-       else {
-               printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
-                                       "timer will not stop\n");
-               wdt_keepalive();
-       }
-       clear_bit(WDT_IN_USE, &wdt_status);
-       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
-       return 0;
-}
-
-
-static const struct file_operations m548x_wdt_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .write          = m548x_wdt_write,
-       .unlocked_ioctl = m548x_wdt_ioctl,
-       .open           = m548x_wdt_open,
-       .release        = m548x_wdt_release,
-};
-
-static struct miscdevice m548x_wdt_miscdev = {
-       .minor          = WATCHDOG_MINOR,
-       .name           = "watchdog",
-       .fops           = &m548x_wdt_fops,
-};
-
-static int __init m548x_wdt_init(void)
-{
-       if (!request_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4,
-                                               "Coldfire M548x Watchdog")) {
-               printk(KERN_WARNING
-                               "Coldfire M548x Watchdog : I/O region busy\n");
-               return -EBUSY;
-       }
-       printk(KERN_INFO "ColdFire watchdog driver is loaded.\n");
-
-       return misc_register(&m548x_wdt_miscdev);
-}
-
-static void __exit m548x_wdt_exit(void)
-{
-       misc_deregister(&m548x_wdt_miscdev);
-       release_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4);
-}
-
-module_init(m548x_wdt_init);
-module_exit(m548x_wdt_exit);
-
-MODULE_AUTHOR("Philippe De Muyter <phdm@macqel.be>");
-MODULE_DESCRIPTION("Coldfire M548x Watchdog");
-
-module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 30s)");
-
-module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/m54xx_wdt.c b/drivers/watchdog/m54xx_wdt.c
new file mode 100644 (file)
index 0000000..4d43286
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * drivers/watchdog/m54xx_wdt.c
+ *
+ * Watchdog driver for ColdFire MCF547x & MCF548x processors
+ * Copyright 2010 (c) Philippe De Muyter <phdm@macqel.be>
+ *
+ * Adapted from the IXP4xx watchdog driver, which carries these notices:
+ *
+ *  Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ *  Copyright 2004 (c) MontaVista, Software, Inc.
+ *  Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
+ *
+ * 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/ioport.h>
+#include <linux/uaccess.h>
+
+#include <asm/coldfire.h>
+#include <asm/m54xxsim.h>
+#include <asm/m54xxgpt.h>
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+static unsigned int heartbeat = 30;    /* (secs) Default is 0.5 minute */
+static unsigned long wdt_status;
+
+#define        WDT_IN_USE              0
+#define        WDT_OK_TO_CLOSE         1
+
+static void wdt_enable(void)
+{
+       unsigned int gms0;
+
+       /* preserve GPIO usage, if any */
+       gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0);
+       if (gms0 & MCF_GPT_GMS_TMS_GPIO)
+               gms0 &= (MCF_GPT_GMS_TMS_GPIO | MCF_GPT_GMS_GPIO_MASK
+                                                       | MCF_GPT_GMS_OD);
+       else
+               gms0 = MCF_GPT_GMS_TMS_GPIO | MCF_GPT_GMS_OD;
+       __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
+       __raw_writel(MCF_GPT_GCIR_PRE(heartbeat*(MCF_BUSCLK/0xffff)) |
+                       MCF_GPT_GCIR_CNT(0xffff), MCF_MBAR + MCF_GPT_GCIR0);
+       gms0 |= MCF_GPT_GMS_OCPW(0xA5) | MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE;
+       __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
+}
+
+static void wdt_disable(void)
+{
+       unsigned int gms0;
+
+       /* disable watchdog */
+       gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0);
+       gms0 &= ~(MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE);
+       __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
+}
+
+static void wdt_keepalive(void)
+{
+       unsigned int gms0;
+
+       gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0);
+       gms0 |= MCF_GPT_GMS_OCPW(0xA5);
+       __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
+}
+
+static int m54xx_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+               return -EBUSY;
+
+       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+       wdt_enable();
+       return nonseekable_open(inode, file);
+}
+
+static ssize_t m54xx_wdt_write(struct file *file, const char *data,
+                                               size_t len, loff_t *ppos)
+{
+       if (len) {
+               if (!nowayout) {
+                       size_t i;
+
+                       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+                       for (i = 0; i != len; i++) {
+                               char c;
+
+                               if (get_user(c, data + i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+                       }
+               }
+               wdt_keepalive();
+       }
+       return len;
+}
+
+static const struct watchdog_info ident = {
+       .options        = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
+                               WDIOF_KEEPALIVEPING,
+       .identity       = "Coldfire M54xx Watchdog",
+};
+
+static long m54xx_wdt_ioctl(struct file *file, unsigned int cmd,
+                                                        unsigned long arg)
+{
+       int ret = -ENOTTY;
+       int time;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               ret = copy_to_user((struct watchdog_info *)arg, &ident,
+                                  sizeof(ident)) ? -EFAULT : 0;
+               break;
+
+       case WDIOC_GETSTATUS:
+               ret = put_user(0, (int *)arg);
+               break;
+
+       case WDIOC_GETBOOTSTATUS:
+               ret = put_user(0, (int *)arg);
+               break;
+
+       case WDIOC_KEEPALIVE:
+               wdt_keepalive();
+               ret = 0;
+               break;
+
+       case WDIOC_SETTIMEOUT:
+               ret = get_user(time, (int *)arg);
+               if (ret)
+                       break;
+
+               if (time <= 0 || time > 30) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               heartbeat = time;
+               wdt_enable();
+               /* Fall through */
+
+       case WDIOC_GETTIMEOUT:
+               ret = put_user(heartbeat, (int *)arg);
+               break;
+       }
+       return ret;
+}
+
+static int m54xx_wdt_release(struct inode *inode, struct file *file)
+{
+       if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
+               wdt_disable();
+       else {
+               printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
+                                       "timer will not stop\n");
+               wdt_keepalive();
+       }
+       clear_bit(WDT_IN_USE, &wdt_status);
+       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+       return 0;
+}
+
+
+static const struct file_operations m54xx_wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .write          = m54xx_wdt_write,
+       .unlocked_ioctl = m54xx_wdt_ioctl,
+       .open           = m54xx_wdt_open,
+       .release        = m54xx_wdt_release,
+};
+
+static struct miscdevice m54xx_wdt_miscdev = {
+       .minor          = WATCHDOG_MINOR,
+       .name           = "watchdog",
+       .fops           = &m54xx_wdt_fops,
+};
+
+static int __init m54xx_wdt_init(void)
+{
+       if (!request_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4,
+                                               "Coldfire M54xx Watchdog")) {
+               printk(KERN_WARNING
+                               "Coldfire M54xx Watchdog : I/O region busy\n");
+               return -EBUSY;
+       }
+       printk(KERN_INFO "ColdFire watchdog driver is loaded.\n");
+
+       return misc_register(&m54xx_wdt_miscdev);
+}
+
+static void __exit m54xx_wdt_exit(void)
+{
+       misc_deregister(&m54xx_wdt_miscdev);
+       release_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4);
+}
+
+module_init(m54xx_wdt_init);
+module_exit(m54xx_wdt_exit);
+
+MODULE_AUTHOR("Philippe De Muyter <phdm@macqel.be>");
+MODULE_DESCRIPTION("Coldfire M54xx Watchdog");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 30s)");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index c7d67e9..7990625 100644 (file)
@@ -201,11 +201,14 @@ static struct miscdevice fitpc2_wdt_miscdev = {
 static int __init fitpc2_wdt_init(void)
 {
        int err;
+       const char *brd_name;
 
-       if (!strstr(dmi_get_system_info(DMI_BOARD_NAME), "SBC-FITPC2"))
+       brd_name = dmi_get_system_info(DMI_BOARD_NAME);
+
+       if (!brd_name || !strstr(brd_name, "SBC-FITPC2"))
                return -ENODEV;
 
-       pr_info("%s found\n", dmi_get_system_info(DMI_BOARD_NAME));
+       pr_info("%s found\n", brd_name);
 
        if (!request_region(COMMAND_PORT, 1, WATCHDOG_NAME)) {
                pr_err("I/O address 0x%04x already in use\n", COMMAND_PORT);
index 0461858..b61ab1c 100644 (file)
@@ -508,7 +508,7 @@ static int __init sch311x_detect(int sio_config_port, unsigned short *addr)
        sch311x_sio_outb(sio_config_port, 0x07, 0x0a);
 
        /* Check if Logical Device Register is currently active */
-       if (sch311x_sio_inb(sio_config_port, 0x30) && 0x01 == 0)
+       if ((sch311x_sio_inb(sio_config_port, 0x30) & 0x01) == 0)
                printk(KERN_INFO PFX "Seems that LDN 0x0a is not active...\n");
 
        /* Get the base address of the runtime registers */
index a6c12de..df2a64d 100644 (file)
@@ -109,7 +109,7 @@ static int w83697ug_select_wd_register(void)
        outb_p(0x08, WDT_EFDR); /* select logical device 8 (GPIO2) */
        outb_p(0x30, WDT_EFER); /* select CR30 */
        c = inb_p(WDT_EFDR);
-       outb_p(c || 0x01, WDT_EFDR); /* set bit 0 to activate GPIO2 */
+       outb_p(c | 0x01, WDT_EFDR); /* set bit 0 to activate GPIO2 */
 
        return 0;
 }
index 43f9f02..718050a 100644 (file)
@@ -232,7 +232,7 @@ static int increase_reservation(unsigned long nr_pages)
                set_phys_to_machine(pfn, frame_list[i]);
 
                /* Link back into the page tables if not highmem. */
-               if (pfn < max_low_pfn) {
+               if (!xen_hvm_domain() && pfn < max_low_pfn) {
                        int ret;
                        ret = HYPERVISOR_update_va_mapping(
                                (unsigned long)__va(pfn << PAGE_SHIFT),
@@ -280,7 +280,7 @@ static int decrease_reservation(unsigned long nr_pages)
 
                scrub_page(page);
 
-               if (!PageHighMem(page)) {
+               if (!xen_hvm_domain() && !PageHighMem(page)) {
                        ret = HYPERVISOR_update_va_mapping(
                                (unsigned long)__va(pfn << PAGE_SHIFT),
                                __pte_ma(0), 0);
@@ -296,7 +296,7 @@ static int decrease_reservation(unsigned long nr_pages)
        /* No more mappings: invalidate P2M and add to balloon. */
        for (i = 0; i < nr_pages; i++) {
                pfn = mfn_to_pfn(frame_list[i]);
-               set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
+               __set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
                balloon_append(pfn_to_page(pfn));
        }
 
@@ -392,15 +392,19 @@ static struct notifier_block xenstore_notifier;
 
 static int __init balloon_init(void)
 {
-       unsigned long pfn, extra_pfn_end;
+       unsigned long pfn, nr_pages, extra_pfn_end;
        struct page *page;
 
-       if (!xen_pv_domain())
+       if (!xen_domain())
                return -ENODEV;
 
        pr_info("xen_balloon: Initialising balloon driver.\n");
 
-       balloon_stats.current_pages = min(xen_start_info->nr_pages, max_pfn);
+       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.target_pages  = balloon_stats.current_pages;
        balloon_stats.balloon_low   = 0;
        balloon_stats.balloon_high  = 0;
index 7468147..0ad1699 100644 (file)
@@ -114,7 +114,7 @@ struct cpu_evtchn_s {
 static __initdata struct cpu_evtchn_s init_evtchn_mask = {
        .bits[0 ... (NR_EVENT_CHANNELS/BITS_PER_LONG)-1] = ~0ul,
 };
-static struct cpu_evtchn_s *cpu_evtchn_mask_p = &init_evtchn_mask;
+static struct cpu_evtchn_s __refdata *cpu_evtchn_mask_p = &init_evtchn_mask;
 
 static inline unsigned long *cpu_evtchn_mask(int cpu)
 {
@@ -277,7 +277,7 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
 
        BUG_ON(irq == -1);
 #ifdef CONFIG_SMP
-       cpumask_copy(irq_to_desc(irq)->affinity, cpumask_of(cpu));
+       cpumask_copy(irq_to_desc(irq)->irq_data.affinity, cpumask_of(cpu));
 #endif
 
        clear_bit(chn, cpu_evtchn_mask(cpu_from_irq(irq)));
@@ -294,7 +294,7 @@ static void init_evtchn_cpu_bindings(void)
 
        /* By default all event channels notify CPU#0. */
        for_each_irq_desc(i, desc) {
-               cpumask_copy(desc->affinity, cpumask_of(0));
+               cpumask_copy(desc->irq_data.affinity, cpumask_of(0));
        }
 #endif
 
@@ -376,81 +376,69 @@ static void unmask_evtchn(int port)
        put_cpu();
 }
 
-static int get_nr_hw_irqs(void)
+static int xen_allocate_irq_dynamic(void)
 {
-       int ret = 1;
+       int first = 0;
+       int irq;
 
 #ifdef CONFIG_X86_IO_APIC
-       ret = get_nr_irqs_gsi();
+       /*
+        * For an HVM guest or domain 0 which see "real" (emulated or
+        * actual repectively) GSIs we allocate dynamic IRQs
+        * e.g. those corresponding to event channels or MSIs
+        * etc. from the range above those "real" GSIs to avoid
+        * collisions.
+        */
+       if (xen_initial_domain() || xen_hvm_domain())
+               first = get_nr_irqs_gsi();
 #endif
 
-       return ret;
-}
+retry:
+       irq = irq_alloc_desc_from(first, -1);
 
-static int find_unbound_pirq(int type)
-{
-       int rc, i;
-       struct physdev_get_free_pirq op_get_free_pirq;
-       op_get_free_pirq.type = type;
+       if (irq == -ENOMEM && first > NR_IRQS_LEGACY) {
+               printk(KERN_ERR "Out of dynamic IRQ space and eating into GSI space. You should increase nr_irqs\n");
+               first = max(NR_IRQS_LEGACY, first - NR_IRQS_LEGACY);
+               goto retry;
+       }
 
-       rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_free_pirq, &op_get_free_pirq);
-       if (!rc)
-               return op_get_free_pirq.pirq;
+       if (irq < 0)
+               panic("No available IRQ to bind to: increase nr_irqs!\n");
 
-       for (i = 0; i < nr_irqs; i++) {
-               if (pirq_to_irq[i] < 0)
-                       return i;
-       }
-       return -1;
+       return irq;
 }
 
-static int find_unbound_irq(void)
+static int xen_allocate_irq_gsi(unsigned gsi)
 {
-       struct irq_data *data;
-       int irq, res;
-       int bottom = get_nr_hw_irqs();
-       int top = nr_irqs-1;
-
-       if (bottom == nr_irqs)
-               goto no_irqs;
+       int irq;
 
-       /* This loop starts from the top of IRQ space and goes down.
-        * We need this b/c if we have a PCI device in a Xen PV guest
-        * we do not have an IO-APIC (though the backend might have them)
-        * mapped in. To not have a collision of physical IRQs with the Xen
-        * event channels start at the top of the IRQ space for virtual IRQs.
+       /*
+        * A PV guest has no concept of a GSI (since it has no ACPI
+        * nor access to/knowledge of the physical APICs). Therefore
+        * all IRQs are dynamically allocated from the entire IRQ
+        * space.
         */
-       for (irq = top; irq > bottom; irq--) {
-               data = irq_get_irq_data(irq);
-               /* only 15->0 have init'd desc; handle irq > 16 */
-               if (!data)
-                       break;
-               if (data->chip == &no_irq_chip)
-                       break;
-               if (data->chip != &xen_dynamic_chip)
-                       continue;
-               if (irq_info[irq].type == IRQT_UNBOUND)
-                       return irq;
-       }
-
-       if (irq == bottom)
-               goto no_irqs;
+       if (xen_pv_domain() && !xen_initial_domain())
+               return xen_allocate_irq_dynamic();
 
-       res = irq_alloc_desc_at(irq, -1);
+       /* Legacy IRQ descriptors are already allocated by the arch. */
+       if (gsi < NR_IRQS_LEGACY)
+               return gsi;
 
-       if (WARN_ON(res != irq))
-               return -1;
+       irq = irq_alloc_desc_at(gsi, -1);
+       if (irq < 0)
+               panic("Unable to allocate to IRQ%d (%d)\n", gsi, irq);
 
        return irq;
-
-no_irqs:
-       panic("No available IRQ to bind to: increase nr_irqs!\n");
 }
 
-static bool identity_mapped_irq(unsigned irq)
+static void xen_free_irq(unsigned irq)
 {
-       /* identity map all the hardware irqs */
-       return irq < get_nr_hw_irqs();
+       /* Legacy IRQ descriptors are managed by the arch. */
+       if (irq < NR_IRQS_LEGACY)
+               return;
+
+       irq_free_desc(irq);
 }
 
 static void pirq_unmask_notify(int irq)
@@ -486,7 +474,7 @@ static bool probing_irq(int irq)
        return desc && desc->action == NULL;
 }
 
-static unsigned int startup_pirq(unsigned int irq)
+static unsigned int __startup_pirq(unsigned int irq)
 {
        struct evtchn_bind_pirq bind_pirq;
        struct irq_info *info = info_for_irq(irq);
@@ -524,9 +512,15 @@ out:
        return 0;
 }
 
-static void shutdown_pirq(unsigned int irq)
+static unsigned int startup_pirq(struct irq_data *data)
+{
+       return __startup_pirq(data->irq);
+}
+
+static void shutdown_pirq(struct irq_data *data)
 {
        struct evtchn_close close;
+       unsigned int irq = data->irq;
        struct irq_info *info = info_for_irq(irq);
        int evtchn = evtchn_from_irq(irq);
 
@@ -546,20 +540,20 @@ static void shutdown_pirq(unsigned int irq)
        info->evtchn = 0;
 }
 
-static void enable_pirq(unsigned int irq)
+static void enable_pirq(struct irq_data *data)
 {
-       startup_pirq(irq);
+       startup_pirq(data);
 }
 
-static void disable_pirq(unsigned int irq)
+static void disable_pirq(struct irq_data *data)
 {
 }
 
-static void ack_pirq(unsigned int irq)
+static void ack_pirq(struct irq_data *data)
 {
-       int evtchn = evtchn_from_irq(irq);
+       int evtchn = evtchn_from_irq(data->irq);
 
-       move_native_irq(irq);
+       move_native_irq(data->irq);
 
        if (VALID_EVTCHN(evtchn)) {
                mask_evtchn(evtchn);
@@ -567,23 +561,6 @@ static void ack_pirq(unsigned int irq)
        }
 }
 
-static void end_pirq(unsigned int irq)
-{
-       int evtchn = evtchn_from_irq(irq);
-       struct irq_desc *desc = irq_to_desc(irq);
-
-       if (WARN_ON(!desc))
-               return;
-
-       if ((desc->status & (IRQ_DISABLED|IRQ_PENDING)) ==
-           (IRQ_DISABLED|IRQ_PENDING)) {
-               shutdown_pirq(irq);
-       } else if (VALID_EVTCHN(evtchn)) {
-               unmask_evtchn(evtchn);
-               pirq_unmask_notify(irq);
-       }
-}
-
 static int find_irq_by_gsi(unsigned gsi)
 {
        int irq;
@@ -638,14 +615,7 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name)
                goto out;       /* XXX need refcount? */
        }
 
-       /* If we are a PV guest, we don't have GSIs (no ACPI passed). Therefore
-        * we are using the !xen_initial_domain() to drop in the function.*/
-       if (identity_mapped_irq(gsi) || (!xen_initial_domain() &&
-                               xen_pv_domain())) {
-               irq = gsi;
-               irq_alloc_desc_at(irq, -1);
-       } else
-               irq = find_unbound_irq();
+       irq = xen_allocate_irq_gsi(gsi);
 
        set_irq_chip_and_handler_name(irq, &xen_pirq_chip,
                                      handle_level_irq, name);
@@ -658,7 +628,7 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name)
         * this in the priv domain. */
        if (xen_initial_domain() &&
            HYPERVISOR_physdev_op(PHYSDEVOP_alloc_irq_vector, &irq_op)) {
-               irq_free_desc(irq);
+               xen_free_irq(irq);
                irq = -ENOSPC;
                goto out;
        }
@@ -674,87 +644,46 @@ out:
 }
 
 #ifdef CONFIG_PCI_MSI
-#include <linux/msi.h>
-#include "../pci/msi.h"
-
-void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc)
+int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc)
 {
-       spin_lock(&irq_mapping_update_lock);
-
-       if (alloc & XEN_ALLOC_IRQ) {
-               *irq = find_unbound_irq();
-               if (*irq == -1)
-                       goto out;
-       }
-
-       if (alloc & XEN_ALLOC_PIRQ) {
-               *pirq = find_unbound_pirq(MAP_PIRQ_TYPE_MSI);
-               if (*pirq == -1)
-                       goto out;
-       }
+       int rc;
+       struct physdev_get_free_pirq op_get_free_pirq;
 
-       set_irq_chip_and_handler_name(*irq, &xen_pirq_chip,
-                                     handle_level_irq, name);
+       op_get_free_pirq.type = MAP_PIRQ_TYPE_MSI;
+       rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_free_pirq, &op_get_free_pirq);
 
-       irq_info[*irq] = mk_pirq_info(0, *pirq, 0, 0);
-       pirq_to_irq[*pirq] = *irq;
+       WARN_ONCE(rc == -ENOSYS,
+                 "hypervisor does not support the PHYSDEVOP_get_free_pirq interface\n");
 
-out:
-       spin_unlock(&irq_mapping_update_lock);
+       return rc ? -1 : op_get_free_pirq.pirq;
 }
 
-int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type)
+int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
+                            int pirq, int vector, const char *name)
 {
-       int irq = -1;
-       struct physdev_map_pirq map_irq;
-       int rc;
-       int pos;
-       u32 table_offset, bir;
-
-       memset(&map_irq, 0, sizeof(map_irq));
-       map_irq.domid = DOMID_SELF;
-       map_irq.type = MAP_PIRQ_TYPE_MSI;
-       map_irq.index = -1;
-       map_irq.pirq = -1;
-       map_irq.bus = dev->bus->number;
-       map_irq.devfn = dev->devfn;
-
-       if (type == PCI_CAP_ID_MSIX) {
-               pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
-
-               pci_read_config_dword(dev, msix_table_offset_reg(pos),
-                                       &table_offset);
-               bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
-
-               map_irq.table_base = pci_resource_start(dev, bir);
-               map_irq.entry_nr = msidesc->msi_attrib.entry_nr;
-       }
+       int irq, ret;
 
        spin_lock(&irq_mapping_update_lock);
 
-       irq = find_unbound_irq();
-
+       irq = xen_allocate_irq_dynamic();
        if (irq == -1)
                goto out;
 
-       rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
-       if (rc) {
-               printk(KERN_WARNING "xen map irq failed %d\n", rc);
-
-               irq_free_desc(irq);
-
-               irq = -1;
-               goto out;
-       }
-       irq_info[irq] = mk_pirq_info(0, map_irq.pirq, 0, map_irq.index);
-
        set_irq_chip_and_handler_name(irq, &xen_pirq_chip,
-                       handle_level_irq,
-                       (type == PCI_CAP_ID_MSIX) ? "msi-x":"msi");
+                                     handle_level_irq, name);
 
+       irq_info[irq] = mk_pirq_info(0, pirq, 0, vector);
+       pirq_to_irq[pirq] = irq;
+       ret = irq_set_msi_desc(irq, msidesc);
+       if (ret < 0)
+               goto error_irq;
 out:
        spin_unlock(&irq_mapping_update_lock);
        return irq;
+error_irq:
+       spin_unlock(&irq_mapping_update_lock);
+       xen_free_irq(irq);
+       return -1;
 }
 #endif
 
@@ -779,11 +708,12 @@ int xen_destroy_irq(int irq)
                        printk(KERN_WARNING "unmap irq failed %d\n", rc);
                        goto out;
                }
-               pirq_to_irq[info->u.pirq.pirq] = -1;
        }
+       pirq_to_irq[info->u.pirq.pirq] = -1;
+
        irq_info[irq] = mk_unbound_info();
 
-       irq_free_desc(irq);
+       xen_free_irq(irq);
 
 out:
        spin_unlock(&irq_mapping_update_lock);
@@ -814,7 +744,7 @@ int bind_evtchn_to_irq(unsigned int evtchn)
        irq = evtchn_to_irq[evtchn];
 
        if (irq == -1) {
-               irq = find_unbound_irq();
+               irq = xen_allocate_irq_dynamic();
 
                set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
                                              handle_fasteoi_irq, "event");
@@ -839,7 +769,7 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
        irq = per_cpu(ipi_to_irq, cpu)[ipi];
 
        if (irq == -1) {
-               irq = find_unbound_irq();
+               irq = xen_allocate_irq_dynamic();
                if (irq < 0)
                        goto out;
 
@@ -875,7 +805,7 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
        irq = per_cpu(virq_to_irq, cpu)[virq];
 
        if (irq == -1) {
-               irq = find_unbound_irq();
+               irq = xen_allocate_irq_dynamic();
 
                set_irq_chip_and_handler_name(irq, &xen_percpu_chip,
                                              handle_percpu_irq, "virq");
@@ -934,7 +864,7 @@ static void unbind_from_irq(unsigned int irq)
        if (irq_info[irq].type != IRQT_UNBOUND) {
                irq_info[irq] = mk_unbound_info();
 
-               irq_free_desc(irq);
+               xen_free_irq(irq);
        }
 
        spin_unlock(&irq_mapping_update_lock);
@@ -990,7 +920,7 @@ int bind_ipi_to_irqhandler(enum ipi_vector ipi,
        if (irq < 0)
                return irq;
 
-       irqflags |= IRQF_NO_SUSPEND;
+       irqflags |= IRQF_NO_SUSPEND | IRQF_FORCE_RESUME;
        retval = request_irq(irq, handler, irqflags, devname, dev_id);
        if (retval != 0) {
                unbind_from_irq(irq);
@@ -1234,11 +1164,12 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
        return 0;
 }
 
-static int set_affinity_irq(unsigned irq, const struct cpumask *dest)
+static int set_affinity_irq(struct irq_data *data, const struct cpumask *dest,
+                           bool force)
 {
        unsigned tcpu = cpumask_first(dest);
 
-       return rebind_irq_to_cpu(irq, tcpu);
+       return rebind_irq_to_cpu(data->irq, tcpu);
 }
 
 int resend_irq_on_evtchn(unsigned int irq)
@@ -1257,35 +1188,35 @@ int resend_irq_on_evtchn(unsigned int irq)
        return 1;
 }
 
-static void enable_dynirq(unsigned int irq)
+static void enable_dynirq(struct irq_data *data)
 {
-       int evtchn = evtchn_from_irq(irq);
+       int evtchn = evtchn_from_irq(data->irq);
 
        if (VALID_EVTCHN(evtchn))
                unmask_evtchn(evtchn);
 }
 
-static void disable_dynirq(unsigned int irq)
+static void disable_dynirq(struct irq_data *data)
 {
-       int evtchn = evtchn_from_irq(irq);
+       int evtchn = evtchn_from_irq(data->irq);
 
        if (VALID_EVTCHN(evtchn))
                mask_evtchn(evtchn);
 }
 
-static void ack_dynirq(unsigned int irq)
+static void ack_dynirq(struct irq_data *data)
 {
-       int evtchn = evtchn_from_irq(irq);
+       int evtchn = evtchn_from_irq(data->irq);
 
-       move_masked_irq(irq);
+       move_masked_irq(data->irq);
 
        if (VALID_EVTCHN(evtchn))
                unmask_evtchn(evtchn);
 }
 
-static int retrigger_dynirq(unsigned int irq)
+static int retrigger_dynirq(struct irq_data *data)
 {
-       int evtchn = evtchn_from_irq(irq);
+       int evtchn = evtchn_from_irq(data->irq);
        struct shared_info *sh = HYPERVISOR_shared_info;
        int ret = 0;
 
@@ -1334,7 +1265,7 @@ static void restore_cpu_pirqs(void)
 
                printk(KERN_DEBUG "xen: --> irq=%d, pirq=%d\n", irq, map_irq.pirq);
 
-               startup_pirq(irq);
+               __startup_pirq(irq);
        }
 }
 
@@ -1445,7 +1376,6 @@ void xen_poll_irq(int irq)
 void xen_irq_resume(void)
 {
        unsigned int cpu, irq, evtchn;
-       struct irq_desc *desc;
 
        init_evtchn_cpu_bindings();
 
@@ -1465,66 +1395,48 @@ void xen_irq_resume(void)
                restore_cpu_ipis(cpu);
        }
 
-       /*
-        * Unmask any IRQF_NO_SUSPEND IRQs which are enabled. These
-        * are not handled by the IRQ core.
-        */
-       for_each_irq_desc(irq, desc) {
-               if (!desc->action || !(desc->action->flags & IRQF_NO_SUSPEND))
-                       continue;
-               if (desc->status & IRQ_DISABLED)
-                       continue;
-
-               evtchn = evtchn_from_irq(irq);
-               if (evtchn == -1)
-                       continue;
-
-               unmask_evtchn(evtchn);
-       }
-
        restore_cpu_pirqs();
 }
 
 static struct irq_chip xen_dynamic_chip __read_mostly = {
-       .name           = "xen-dyn",
+       .name                   = "xen-dyn",
 
-       .disable        = disable_dynirq,
-       .mask           = disable_dynirq,
-       .unmask         = enable_dynirq,
+       .irq_disable            = disable_dynirq,
+       .irq_mask               = disable_dynirq,
+       .irq_unmask             = enable_dynirq,
 
-       .eoi            = ack_dynirq,
-       .set_affinity   = set_affinity_irq,
-       .retrigger      = retrigger_dynirq,
+       .irq_eoi                = ack_dynirq,
+       .irq_set_affinity       = set_affinity_irq,
+       .irq_retrigger          = retrigger_dynirq,
 };
 
 static struct irq_chip xen_pirq_chip __read_mostly = {
-       .name           = "xen-pirq",
+       .name                   = "xen-pirq",
 
-       .startup        = startup_pirq,
-       .shutdown       = shutdown_pirq,
+       .irq_startup            = startup_pirq,
+       .irq_shutdown           = shutdown_pirq,
 
-       .enable         = enable_pirq,
-       .unmask         = enable_pirq,
+       .irq_enable             = enable_pirq,
+       .irq_unmask             = enable_pirq,
 
-       .disable        = disable_pirq,
-       .mask           = disable_pirq,
+       .irq_disable            = disable_pirq,
+       .irq_mask               = disable_pirq,
 
-       .ack            = ack_pirq,
-       .end            = end_pirq,
+       .irq_ack                = ack_pirq,
 
-       .set_affinity   = set_affinity_irq,
+       .irq_set_affinity       = set_affinity_irq,
 
-       .retrigger      = retrigger_dynirq,
+       .irq_retrigger          = retrigger_dynirq,
 };
 
 static struct irq_chip xen_percpu_chip __read_mostly = {
-       .name           = "xen-percpu",
+       .name                   = "xen-percpu",
 
-       .disable        = disable_dynirq,
-       .mask           = disable_dynirq,
-       .unmask         = enable_dynirq,
+       .irq_disable            = disable_dynirq,
+       .irq_mask               = disable_dynirq,
+       .irq_unmask             = enable_dynirq,
 
-       .ack            = ack_dynirq,
+       .irq_ack                = ack_dynirq,
 };
 
 int xen_set_callback_via(uint64_t via)
index db8c4c4..ebb2928 100644 (file)
@@ -34,32 +34,38 @@ enum shutdown_state {
 /* Ignore multiple shutdown requests. */
 static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
 
-#ifdef CONFIG_PM_SLEEP
-static int xen_hvm_suspend(void *data)
-{
-       struct sched_shutdown r = { .reason = SHUTDOWN_suspend };
-       int *cancelled = data;
-
-       BUG_ON(!irqs_disabled());
-
-       *cancelled = HYPERVISOR_sched_op(SCHEDOP_shutdown, &r);
+struct suspend_info {
+       int cancelled;
+       unsigned long arg; /* extra hypercall argument */
+       void (*pre)(void);
+       void (*post)(int cancelled);
+};
 
-       xen_hvm_post_suspend(*cancelled);
+static void xen_hvm_post_suspend(int cancelled)
+{
+       xen_arch_hvm_post_suspend(cancelled);
        gnttab_resume();
+}
 
-       if (!*cancelled) {
-               xen_irq_resume();
-               xen_console_resume();
-               xen_timer_resume();
-       }
+static void xen_pre_suspend(void)
+{
+       xen_mm_pin_all();
+       gnttab_suspend();
+       xen_arch_pre_suspend();
+}
 
-       return 0;
+static void xen_post_suspend(int cancelled)
+{
+       xen_arch_post_suspend(cancelled);
+       gnttab_resume();
+       xen_mm_unpin_all();
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int xen_suspend(void *data)
 {
+       struct suspend_info *si = data;
        int err;
-       int *cancelled = data;
 
        BUG_ON(!irqs_disabled());
 
@@ -70,22 +76,20 @@ static int xen_suspend(void *data)
                return err;
        }
 
-       xen_mm_pin_all();
-       gnttab_suspend();
-       xen_pre_suspend();
+       if (si->pre)
+               si->pre();
 
        /*
         * This hypercall returns 1 if suspend was cancelled
         * or the domain was merely checkpointed, and 0 if it
         * is resuming in a new domain.
         */
-       *cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
+       si->cancelled = HYPERVISOR_suspend(si->arg);
 
-       xen_post_suspend(*cancelled);
-       gnttab_resume();
-       xen_mm_unpin_all();
+       if (si->post)
+               si->post(si->cancelled);
 
-       if (!*cancelled) {
+       if (!si->cancelled) {
                xen_irq_resume();
                xen_console_resume();
                xen_timer_resume();
@@ -99,7 +103,7 @@ static int xen_suspend(void *data)
 static void do_suspend(void)
 {
        int err;
-       int cancelled = 1;
+       struct suspend_info si;
 
        shutting_down = SHUTDOWN_SUSPEND;
 
@@ -129,20 +133,29 @@ static void do_suspend(void)
                goto out_resume;
        }
 
-       if (xen_hvm_domain())
-               err = stop_machine(xen_hvm_suspend, &cancelled, cpumask_of(0));
-       else
-               err = stop_machine(xen_suspend, &cancelled, cpumask_of(0));
+       si.cancelled = 1;
+
+       if (xen_hvm_domain()) {
+               si.arg = 0UL;
+               si.pre = NULL;
+               si.post = &xen_hvm_post_suspend;
+       } else {
+               si.arg = virt_to_mfn(xen_start_info);
+               si.pre = &xen_pre_suspend;
+               si.post = &xen_post_suspend;
+       }
+
+       err = stop_machine(xen_suspend, &si, cpumask_of(0));
 
        dpm_resume_noirq(PMSG_RESUME);
 
        if (err) {
                printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
-               cancelled = 1;
+               si.cancelled = 1;
        }
 
 out_resume:
-       if (!cancelled) {
+       if (!si.cancelled) {
                xen_arch_resume();
                xs_resume();
        } else
@@ -162,12 +175,39 @@ out:
 }
 #endif /* CONFIG_PM_SLEEP */
 
+struct shutdown_handler {
+       const char *command;
+       void (*cb)(void);
+};
+
+static void do_poweroff(void)
+{
+       shutting_down = SHUTDOWN_POWEROFF;
+       orderly_poweroff(false);
+}
+
+static void do_reboot(void)
+{
+       shutting_down = SHUTDOWN_POWEROFF; /* ? */
+       ctrl_alt_del();
+}
+
 static void shutdown_handler(struct xenbus_watch *watch,
                             const char **vec, unsigned int len)
 {
        char *str;
        struct xenbus_transaction xbt;
        int err;
+       static struct shutdown_handler handlers[] = {
+               { "poweroff",   do_poweroff },
+               { "halt",       do_poweroff },
+               { "reboot",     do_reboot   },
+#ifdef CONFIG_PM_SLEEP
+               { "suspend",    do_suspend  },
+#endif
+               {NULL, NULL},
+       };
+       static struct shutdown_handler *handler;
 
        if (shutting_down != SHUTDOWN_INVALID)
                return;
@@ -184,7 +224,14 @@ static void shutdown_handler(struct xenbus_watch *watch,
                return;
        }
 
-       xenbus_write(xbt, "control", "shutdown", "");
+       for (handler = &handlers[0]; handler->command; handler++) {
+               if (strcmp(str, handler->command) == 0)
+                       break;
+       }
+
+       /* Only acknowledge commands which we are prepared to handle. */
+       if (handler->cb)
+               xenbus_write(xbt, "control", "shutdown", "");
 
        err = xenbus_transaction_end(xbt, 0);
        if (err == -EAGAIN) {
@@ -192,17 +239,8 @@ static void shutdown_handler(struct xenbus_watch *watch,
                goto again;
        }
 
-       if (strcmp(str, "poweroff") == 0 ||
-           strcmp(str, "halt") == 0) {
-               shutting_down = SHUTDOWN_POWEROFF;
-               orderly_poweroff(false);
-       } else if (strcmp(str, "reboot") == 0) {
-               shutting_down = SHUTDOWN_POWEROFF; /* ? */
-               ctrl_alt_del();
-#ifdef CONFIG_PM_SLEEP
-       } else if (strcmp(str, "suspend") == 0) {
-               do_suspend();
-#endif
+       if (handler->cb) {
+               handler->cb();
        } else {
                printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
                shutting_down = SHUTDOWN_INVALID;
@@ -281,27 +319,18 @@ static int shutdown_event(struct notifier_block *notifier,
        return NOTIFY_DONE;
 }
 
-static int __init __setup_shutdown_event(void)
-{
-       /* Delay initialization in the PV on HVM case */
-       if (xen_hvm_domain())
-               return 0;
-
-       if (!xen_pv_domain())
-               return -ENODEV;
-
-       return xen_setup_shutdown_event();
-}
-
 int xen_setup_shutdown_event(void)
 {
        static struct notifier_block xenstore_notifier = {
                .notifier_call = shutdown_event
        };
+
+       if (!xen_domain())
+               return -ENODEV;
        register_xenstore_notifier(&xenstore_notifier);
 
        return 0;
 }
 EXPORT_SYMBOL_GPL(xen_setup_shutdown_event);
 
-subsys_initcall(__setup_shutdown_event);
+subsys_initcall(xen_setup_shutdown_event);
index afbe041..319dd0a 100644 (file)
@@ -156,9 +156,6 @@ static int __devinit platform_pci_init(struct pci_dev *pdev,
        if (ret)
                goto out;
        xenbus_probe(NULL);
-       ret = xen_setup_shutdown_event();
-       if (ret)
-               goto out;
        return 0;
 
 out:
index 3db9caa..7cb53aa 100644 (file)
@@ -47,7 +47,7 @@ config FS_POSIX_ACL
        def_bool n
 
 config EXPORTFS
-       tristate
+       bool
 
 config FILE_LOCKING
        bool "Enable POSIX file locking API" if EXPERT
index a7f7cef..ba01202 100644 (file)
@@ -48,6 +48,8 @@ obj-$(CONFIG_FS_POSIX_ACL)    += posix_acl.o xattr_acl.o
 obj-$(CONFIG_NFS_COMMON)       += nfs_common/
 obj-$(CONFIG_GENERIC_ACL)      += generic_acl.o
 
+obj-$(CONFIG_FHANDLE)          += fhandle.o
+
 obj-y                          += quota/
 
 obj-$(CONFIG_PROC_FS)          += proc/
index 15690bb..789b3af 100644 (file)
@@ -140,6 +140,7 @@ int afs_write_begin(struct file *file, struct address_space *mapping,
        candidate->first = candidate->last = index;
        candidate->offset_first = from;
        candidate->to_last = to;
+       INIT_LIST_HEAD(&candidate->link);
        candidate->usage = 1;
        candidate->state = AFS_WBACK_PENDING;
        init_waitqueue_head(&candidate->waitq);
index fc557a3..7f54f43 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -85,7 +85,7 @@ static int __init aio_setup(void)
        kiocb_cachep = KMEM_CACHE(kiocb, SLAB_HWCACHE_ALIGN|SLAB_PANIC);
        kioctx_cachep = KMEM_CACHE(kioctx,SLAB_HWCACHE_ALIGN|SLAB_PANIC);
 
-       aio_wq = create_workqueue("aio");
+       aio_wq = alloc_workqueue("aio", 0, 1);  /* used to limit concurrency */
        abe_pool = mempool_create_kmalloc_pool(1, sizeof(struct aio_batch_entry));
        BUG_ON(!aio_wq || !abe_pool);
 
@@ -239,15 +239,23 @@ static void __put_ioctx(struct kioctx *ctx)
        call_rcu(&ctx->rcu_head, ctx_rcu_free);
 }
 
-#define get_ioctx(kioctx) do {                                         \
-       BUG_ON(atomic_read(&(kioctx)->users) <= 0);                     \
-       atomic_inc(&(kioctx)->users);                                   \
-} while (0)
-#define put_ioctx(kioctx) do {                                         \
-       BUG_ON(atomic_read(&(kioctx)->users) <= 0);                     \
-       if (unlikely(atomic_dec_and_test(&(kioctx)->users)))            \
-               __put_ioctx(kioctx);                                    \
-} while (0)
+static inline void get_ioctx(struct kioctx *kioctx)
+{
+       BUG_ON(atomic_read(&kioctx->users) <= 0);
+       atomic_inc(&kioctx->users);
+}
+
+static inline int try_get_ioctx(struct kioctx *kioctx)
+{
+       return atomic_inc_not_zero(&kioctx->users);
+}
+
+static inline void put_ioctx(struct kioctx *kioctx)
+{
+       BUG_ON(atomic_read(&kioctx->users) <= 0);
+       if (unlikely(atomic_dec_and_test(&kioctx->users)))
+               __put_ioctx(kioctx);
+}
 
 /* ioctx_alloc
  *     Allocates and initializes an ioctx.  Returns an ERR_PTR if it failed.
@@ -569,7 +577,7 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req)
                spin_lock(&fput_lock);
                list_add(&req->ki_list, &fput_head);
                spin_unlock(&fput_lock);
-               queue_work(aio_wq, &fput_work);
+               schedule_work(&fput_work);
        } else {
                req->ki_filp = NULL;
                really_put_req(ctx, req);
@@ -601,8 +609,13 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id)
        rcu_read_lock();
 
        hlist_for_each_entry_rcu(ctx, n, &mm->ioctx_list, list) {
-               if (ctx->user_id == ctx_id && !ctx->dead) {
-                       get_ioctx(ctx);
+               /*
+                * RCU protects us against accessing freed memory but
+                * we have to be careful not to get a reference when the
+                * reference count already dropped to 0 (ctx->dead test
+                * is unreliable because of races).
+                */
+               if (ctx->user_id == ctx_id && !ctx->dead && try_get_ioctx(ctx)){
                        ret = ctx;
                        break;
                }
@@ -1629,6 +1642,23 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
                goto out_put_req;
 
        spin_lock_irq(&ctx->ctx_lock);
+       /*
+        * We could have raced with io_destroy() and are currently holding a
+        * reference to ctx which should be destroyed. We cannot submit IO
+        * since ctx gets freed as soon as io_submit() puts its reference.  The
+        * check here is reliable: io_destroy() sets ctx->dead before waiting
+        * for outstanding IO and the barrier between these two is realized by
+        * unlock of mm->ioctx_lock and lock of ctx->ctx_lock.  Analogously we
+        * increment ctx->reqs_active before checking for ctx->dead and the
+        * barrier is realized by unlock and lock of ctx->ctx_lock. Thus if we
+        * don't see ctx->dead set here, io_destroy() waits for our IO to
+        * finish.
+        */
+       if (ctx->dead) {
+               spin_unlock_irq(&ctx->ctx_lock);
+               ret = -EINVAL;
+               goto out_put_req;
+       }
        aio_run_iocb(req);
        if (!list_empty(&ctx->run_list)) {
                /* drain the run list */
index 333a7bb..8892870 100644 (file)
@@ -873,6 +873,11 @@ int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk)
        ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj);
        if (ret)
                goto out_del;
+       /*
+        * bdev could be deleted beneath us which would implicitly destroy
+        * the holder directory.  Hold on to it.
+        */
+       kobject_get(bdev->bd_part->holder_dir);
 
        list_add(&holder->list, &bdev->bd_holder_disks);
        goto out_unlock;
@@ -909,6 +914,7 @@ void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk)
                del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
                del_symlink(bdev->bd_part->holder_dir,
                            &disk_to_dev(disk)->kobj);
+               kobject_put(bdev->bd_part->holder_dir);
                list_del_init(&holder->list);
                kfree(holder);
        }
@@ -922,14 +928,15 @@ EXPORT_SYMBOL_GPL(bd_unlink_disk_holder);
  * flush_disk - invalidates all buffer-cache entries on a disk
  *
  * @bdev:      struct block device to be flushed
+ * @kill_dirty: flag to guide handling of dirty inodes
  *
  * Invalidates all buffer-cache entries on a disk. It should be called
  * when a disk has been changed -- either by a media change or online
  * resize.
  */
-static void flush_disk(struct block_device *bdev)
+static void flush_disk(struct block_device *bdev, bool kill_dirty)
 {
-       if (__invalidate_device(bdev)) {
+       if (__invalidate_device(bdev, kill_dirty)) {
                char name[BDEVNAME_SIZE] = "";
 
                if (bdev->bd_disk)
@@ -966,7 +973,7 @@ void check_disk_size_change(struct gendisk *disk, struct block_device *bdev)
                       "%s: detected capacity change from %lld to %lld\n",
                       name, bdev_size, disk_size);
                i_size_write(bdev->bd_inode, disk_size);
-               flush_disk(bdev);
+               flush_disk(bdev, false);
        }
 }
 EXPORT_SYMBOL(check_disk_size_change);
@@ -1019,7 +1026,7 @@ int check_disk_change(struct block_device *bdev)
        if (!(events & DISK_EVENT_MEDIA_CHANGE))
                return 0;
 
-       flush_disk(bdev);
+       flush_disk(bdev, true);
        if (bdops->revalidate_disk)
                bdops->revalidate_disk(bdev->bd_disk);
        return 1;
@@ -1215,12 +1222,6 @@ int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder)
 
        res = __blkdev_get(bdev, mode, 0);
 
-       /* __blkdev_get() may alter read only status, check it afterwards */
-       if (!res && (mode & FMODE_WRITE) && bdev_read_only(bdev)) {
-               __blkdev_put(bdev, mode, 0);
-               res = -EACCES;
-       }
-
        if (whole) {
                /* finish claiming */
                mutex_lock(&bdev->bd_mutex);
@@ -1298,6 +1299,11 @@ struct block_device *blkdev_get_by_path(const char *path, fmode_t mode,
        if (err)
                return ERR_PTR(err);
 
+       if ((mode & FMODE_WRITE) && bdev_read_only(bdev)) {
+               blkdev_put(bdev, mode);
+               return ERR_PTR(-EACCES);
+       }
+
        return bdev;
 }
 EXPORT_SYMBOL(blkdev_get_by_path);
@@ -1601,7 +1607,7 @@ fail:
 }
 EXPORT_SYMBOL(lookup_bdev);
 
-int __invalidate_device(struct block_device *bdev)
+int __invalidate_device(struct block_device *bdev, bool kill_dirty)
 {
        struct super_block *sb = get_super(bdev);
        int res = 0;
@@ -1614,7 +1620,7 @@ int __invalidate_device(struct block_device *bdev)
                 * hold).
                 */
                shrink_dcache_sb(sb);
-               res = invalidate_inodes(sb);
+               res = invalidate_inodes(sb, kill_dirty);
                drop_super(sb);
        }
        invalidate_bdev(bdev);
index 15b5ca2..9c94934 100644 (file)
@@ -37,6 +37,9 @@ static struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
        char *value = NULL;
        struct posix_acl *acl;
 
+       if (!IS_POSIXACL(inode))
+               return NULL;
+
        acl = get_cached_acl(inode, type);
        if (acl != ACL_NOT_CACHED)
                return acl;
@@ -84,6 +87,9 @@ static int btrfs_xattr_acl_get(struct dentry *dentry, const char *name,
        struct posix_acl *acl;
        int ret = 0;
 
+       if (!IS_POSIXACL(dentry->d_inode))
+               return -EOPNOTSUPP;
+
        acl = btrfs_get_acl(dentry->d_inode, type);
 
        if (IS_ERR(acl))
index f745287..4d2110e 100644 (file)
@@ -562,7 +562,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        u64 em_len;
        u64 em_start;
        struct extent_map *em;
-       int ret;
+       int ret = -ENOMEM;
        u32 *sums;
 
        tree = &BTRFS_I(inode)->io_tree;
@@ -577,6 +577,9 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
 
        compressed_len = em->block_len;
        cb = kmalloc(compressed_bio_size(root, compressed_len), GFP_NOFS);
+       if (!cb)
+               goto out;
+
        atomic_set(&cb->pending_bios, 0);
        cb->errors = 0;
        cb->inode = inode;
@@ -597,13 +600,18 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
 
        nr_pages = (compressed_len + PAGE_CACHE_SIZE - 1) /
                                 PAGE_CACHE_SIZE;
-       cb->compressed_pages = kmalloc(sizeof(struct page *) * nr_pages,
+       cb->compressed_pages = kzalloc(sizeof(struct page *) * nr_pages,
                                       GFP_NOFS);
+       if (!cb->compressed_pages)
+               goto fail1;
+
        bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
 
        for (page_index = 0; page_index < nr_pages; page_index++) {
                cb->compressed_pages[page_index] = alloc_page(GFP_NOFS |
                                                              __GFP_HIGHMEM);
+               if (!cb->compressed_pages[page_index])
+                       goto fail2;
        }
        cb->nr_pages = nr_pages;
 
@@ -614,6 +622,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        cb->len = uncompressed_len;
 
        comp_bio = compressed_bio_alloc(bdev, cur_disk_byte, GFP_NOFS);
+       if (!comp_bio)
+               goto fail2;
        comp_bio->bi_private = cb;
        comp_bio->bi_end_io = end_compressed_bio_read;
        atomic_inc(&cb->pending_bios);
@@ -681,6 +691,17 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
 
        bio_put(comp_bio);
        return 0;
+
+fail2:
+       for (page_index = 0; page_index < nr_pages; page_index++)
+               free_page((unsigned long)cb->compressed_pages[page_index]);
+
+       kfree(cb->compressed_pages);
+fail1:
+       kfree(cb);
+out:
+       free_extent_map(em);
+       return ret;
 }
 
 static struct list_head comp_idle_workspace[BTRFS_COMPRESS_TYPES];
@@ -900,7 +921,7 @@ int btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page,
        return ret;
 }
 
-void __exit btrfs_exit_compress(void)
+void btrfs_exit_compress(void)
 {
        free_workspaces();
 }
index 2c98b3a..7f78cc7 100644 (file)
@@ -729,6 +729,15 @@ struct btrfs_space_info {
        u64 disk_total;         /* total bytes on disk, takes mirrors into
                                   account */
 
+       /*
+        * we bump reservation progress every time we decrement
+        * bytes_reserved.  This way people waiting for reservations
+        * know something good has happened and they can check
+        * for progress.  The number here isn't to be trusted, it
+        * just shows reclaim activity
+        */
+       unsigned long reservation_progress;
+
        int full;               /* indicates that we cannot allocate any more
                                   chunks for this space */
        int force_alloc;        /* set if we need to force a chunk alloc for
@@ -1254,6 +1263,7 @@ struct btrfs_root {
 #define BTRFS_MOUNT_SPACE_CACHE                (1 << 12)
 #define BTRFS_MOUNT_CLEAR_CACHE                (1 << 13)
 #define BTRFS_MOUNT_USER_SUBVOL_RM_ALLOWED (1 << 14)
+#define BTRFS_MOUNT_ENOSPC_DEBUG        (1 << 15)
 
 #define btrfs_clear_opt(o, opt)                ((o) &= ~BTRFS_MOUNT_##opt)
 #define btrfs_set_opt(o, opt)          ((o) |= BTRFS_MOUNT_##opt)
@@ -2218,6 +2228,8 @@ int btrfs_error_unpin_extent_range(struct btrfs_root *root,
                                   u64 start, u64 end);
 int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr,
                               u64 num_bytes);
+int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans,
+                           struct btrfs_root *root, u64 type);
 
 /* ctree.c */
 int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key,
index b531c36..e1aa8d6 100644 (file)
@@ -359,10 +359,14 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
 
        tree = &BTRFS_I(page->mapping->host)->io_tree;
 
-       if (page->private == EXTENT_PAGE_PRIVATE)
+       if (page->private == EXTENT_PAGE_PRIVATE) {
+               WARN_ON(1);
                goto out;
-       if (!page->private)
+       }
+       if (!page->private) {
+               WARN_ON(1);
                goto out;
+       }
        len = page->private >> 2;
        WARN_ON(len == 0);
 
@@ -1550,6 +1554,7 @@ static int transaction_kthread(void *arg)
                spin_unlock(&root->fs_info->new_trans_lock);
 
                trans = btrfs_join_transaction(root, 1);
+               BUG_ON(IS_ERR(trans));
                if (transid == trans->transid) {
                        ret = btrfs_commit_transaction(trans, root);
                        BUG_ON(ret);
@@ -2453,10 +2458,14 @@ int btrfs_commit_super(struct btrfs_root *root)
        up_write(&root->fs_info->cleanup_work_sem);
 
        trans = btrfs_join_transaction(root, 1);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
        ret = btrfs_commit_transaction(trans, root);
        BUG_ON(ret);
        /* run commit again to drop the original snapshot */
        trans = btrfs_join_transaction(root, 1);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
        btrfs_commit_transaction(trans, root);
        ret = btrfs_write_and_wait_transaction(NULL, root);
        BUG_ON(ret);
@@ -2554,6 +2563,8 @@ int close_ctree(struct btrfs_root *root)
        kfree(fs_info->chunk_root);
        kfree(fs_info->dev_root);
        kfree(fs_info->csum_root);
+       kfree(fs_info);
+
        return 0;
 }
 
index 9786963..b4ffad8 100644 (file)
@@ -21,9 +21,13 @@ static int btrfs_encode_fh(struct dentry *dentry, u32 *fh, int *max_len,
        int len = *max_len;
        int type;
 
-       if ((len < BTRFS_FID_SIZE_NON_CONNECTABLE) ||
-           (connectable && len < BTRFS_FID_SIZE_CONNECTABLE))
+       if (connectable && (len < BTRFS_FID_SIZE_CONNECTABLE)) {
+               *max_len = BTRFS_FID_SIZE_CONNECTABLE;
                return 255;
+       } else if (len < BTRFS_FID_SIZE_NON_CONNECTABLE) {
+               *max_len = BTRFS_FID_SIZE_NON_CONNECTABLE;
+               return 255;
+       }
 
        len  = BTRFS_FID_SIZE_NON_CONNECTABLE;
        type = FILEID_BTRFS_WITHOUT_PARENT;
@@ -171,6 +175,8 @@ static struct dentry *btrfs_get_parent(struct dentry *child)
        int ret;
 
        path = btrfs_alloc_path();
+       if (!path)
+               return ERR_PTR(-ENOMEM);
 
        if (dir->i_ino == BTRFS_FIRST_FREE_OBJECTID) {
                key.objectid = root->root_key.objectid;
index b552693..7b3089b 100644 (file)
@@ -320,11 +320,6 @@ static int caching_kthread(void *data)
        if (!path)
                return -ENOMEM;
 
-       exclude_super_stripes(extent_root, block_group);
-       spin_lock(&block_group->space_info->lock);
-       block_group->space_info->bytes_readonly += block_group->bytes_super;
-       spin_unlock(&block_group->space_info->lock);
-
        last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET);
 
        /*
@@ -467,8 +462,10 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,
                        cache->cached = BTRFS_CACHE_NO;
                }
                spin_unlock(&cache->lock);
-               if (ret == 1)
+               if (ret == 1) {
+                       free_excluded_extents(fs_info->extent_root, cache);
                        return 0;
+               }
        }
 
        if (load_cache_only)
@@ -3344,21 +3341,24 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans,
        u64 reserved;
        u64 max_reclaim;
        u64 reclaimed = 0;
-       int pause = 1;
+       long time_left;
        int nr_pages = (2 * 1024 * 1024) >> PAGE_CACHE_SHIFT;
+       int loops = 0;
+       unsigned long progress;
 
        block_rsv = &root->fs_info->delalloc_block_rsv;
        space_info = block_rsv->space_info;
 
        smp_mb();
        reserved = space_info->bytes_reserved;
+       progress = space_info->reservation_progress;
 
        if (reserved == 0)
                return 0;
 
        max_reclaim = min(reserved, to_reclaim);
 
-       while (1) {
+       while (loops < 1024) {
                /* have the flusher threads jump in and do some IO */
                smp_mb();
                nr_pages = min_t(unsigned long, nr_pages,
@@ -3371,17 +3371,31 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans,
                reserved = space_info->bytes_reserved;
                spin_unlock(&space_info->lock);
 
+               loops++;
+
                if (reserved == 0 || reclaimed >= max_reclaim)
                        break;
 
                if (trans && trans->transaction->blocked)
                        return -EAGAIN;
 
-               __set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(pause);
-               pause <<= 1;
-               if (pause > HZ / 10)
-                       pause = HZ / 10;
+               time_left = schedule_timeout_interruptible(1);
+
+               /* We were interrupted, exit */
+               if (time_left)
+                       break;
+
+               /* we've kicked the IO a few times, if anything has been freed,
+                * exit.  There is no sense in looping here for a long time
+                * when we really need to commit the transaction, or there are
+                * just too many writers without enough free space
+                */
+
+               if (loops > 3) {
+                       smp_mb();
+                       if (progress != space_info->reservation_progress)
+                               break;
+               }
 
        }
        return reclaimed >= to_reclaim;
@@ -3588,10 +3602,23 @@ void block_rsv_release_bytes(struct btrfs_block_rsv *block_rsv,
 
        if (num_bytes > 0) {
                if (dest) {
-                       block_rsv_add_bytes(dest, num_bytes, 0);
-               } else {
+                       spin_lock(&dest->lock);
+                       if (!dest->full) {
+                               u64 bytes_to_add;
+
+                               bytes_to_add = dest->size - dest->reserved;
+                               bytes_to_add = min(num_bytes, bytes_to_add);
+                               dest->reserved += bytes_to_add;
+                               if (dest->reserved >= dest->size)
+                                       dest->full = 1;
+                               num_bytes -= bytes_to_add;
+                       }
+                       spin_unlock(&dest->lock);
+               }
+               if (num_bytes) {
                        spin_lock(&space_info->lock);
                        space_info->bytes_reserved -= num_bytes;
+                       space_info->reservation_progress++;
                        spin_unlock(&space_info->lock);
                }
        }
@@ -3824,6 +3851,7 @@ static void update_global_block_rsv(struct btrfs_fs_info *fs_info)
        if (block_rsv->reserved >= block_rsv->size) {
                num_bytes = block_rsv->reserved - block_rsv->size;
                sinfo->bytes_reserved -= num_bytes;
+               sinfo->reservation_progress++;
                block_rsv->reserved = block_rsv->size;
                block_rsv->full = 1;
        }
@@ -3985,7 +4013,6 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
                to_reserve = 0;
        }
        spin_unlock(&BTRFS_I(inode)->accounting_lock);
-
        to_reserve += calc_csum_metadata_size(inode, num_bytes);
        ret = reserve_metadata_bytes(NULL, root, block_rsv, to_reserve, 1);
        if (ret)
@@ -4012,6 +4039,7 @@ void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
 
        num_bytes = ALIGN(num_bytes, root->sectorsize);
        atomic_dec(&BTRFS_I(inode)->outstanding_extents);
+       WARN_ON(atomic_read(&BTRFS_I(inode)->outstanding_extents) < 0);
 
        spin_lock(&BTRFS_I(inode)->accounting_lock);
        nr_extents = atomic_read(&BTRFS_I(inode)->outstanding_extents);
@@ -4112,6 +4140,7 @@ static int update_block_group(struct btrfs_trans_handle *trans,
                        btrfs_set_block_group_used(&cache->item, old_val);
                        cache->reserved -= num_bytes;
                        cache->space_info->bytes_reserved -= num_bytes;
+                       cache->space_info->reservation_progress++;
                        cache->space_info->bytes_used += num_bytes;
                        cache->space_info->disk_used += num_bytes * factor;
                        spin_unlock(&cache->lock);
@@ -4163,6 +4192,7 @@ static int pin_down_extent(struct btrfs_root *root,
        if (reserved) {
                cache->reserved -= num_bytes;
                cache->space_info->bytes_reserved -= num_bytes;
+               cache->space_info->reservation_progress++;
        }
        spin_unlock(&cache->lock);
        spin_unlock(&cache->space_info->lock);
@@ -4213,6 +4243,7 @@ static int update_reserved_bytes(struct btrfs_block_group_cache *cache,
                                space_info->bytes_readonly += num_bytes;
                        cache->reserved -= num_bytes;
                        space_info->bytes_reserved -= num_bytes;
+                       space_info->reservation_progress++;
                }
                spin_unlock(&cache->lock);
                spin_unlock(&space_info->lock);
@@ -4691,6 +4722,7 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
                if (ret) {
                        spin_lock(&cache->space_info->lock);
                        cache->space_info->bytes_reserved -= buf->len;
+                       cache->space_info->reservation_progress++;
                        spin_unlock(&cache->space_info->lock);
                }
                goto out;
@@ -5355,7 +5387,7 @@ again:
                               num_bytes, data, 1);
                goto again;
        }
-       if (ret == -ENOSPC) {
+       if (ret == -ENOSPC && btrfs_test_opt(root, ENOSPC_DEBUG)) {
                struct btrfs_space_info *sinfo;
 
                sinfo = __find_space_info(root->fs_info, data);
@@ -5633,6 +5665,7 @@ use_block_rsv(struct btrfs_trans_handle *trans,
              struct btrfs_root *root, u32 blocksize)
 {
        struct btrfs_block_rsv *block_rsv;
+       struct btrfs_block_rsv *global_rsv = &root->fs_info->global_block_rsv;
        int ret;
 
        block_rsv = get_block_rsv(trans, root);
@@ -5640,14 +5673,39 @@ use_block_rsv(struct btrfs_trans_handle *trans,
        if (block_rsv->size == 0) {
                ret = reserve_metadata_bytes(trans, root, block_rsv,
                                             blocksize, 0);
-               if (ret)
+               /*
+                * If we couldn't reserve metadata bytes try and use some from
+                * the global reserve.
+                */
+               if (ret && block_rsv != global_rsv) {
+                       ret = block_rsv_use_bytes(global_rsv, blocksize);
+                       if (!ret)
+                               return global_rsv;
+                       return ERR_PTR(ret);
+               } else if (ret) {
                        return ERR_PTR(ret);
+               }
                return block_rsv;
        }
 
        ret = block_rsv_use_bytes(block_rsv, blocksize);
        if (!ret)
                return block_rsv;
+       if (ret) {
+               WARN_ON(1);
+               ret = reserve_metadata_bytes(trans, root, block_rsv, blocksize,
+                                            0);
+               if (!ret) {
+                       spin_lock(&block_rsv->lock);
+                       block_rsv->size += blocksize;
+                       spin_unlock(&block_rsv->lock);
+                       return block_rsv;
+               } else if (ret && block_rsv != global_rsv) {
+                       ret = block_rsv_use_bytes(global_rsv, blocksize);
+                       if (!ret)
+                               return global_rsv;
+               }
+       }
 
        return ERR_PTR(-ENOSPC);
 }
@@ -6221,6 +6279,8 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
        BUG_ON(!wc);
 
        trans = btrfs_start_transaction(tree_root, 0);
+       BUG_ON(IS_ERR(trans));
+
        if (block_rsv)
                trans->block_rsv = block_rsv;
 
@@ -6318,6 +6378,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
 
                        btrfs_end_transaction_throttle(trans, tree_root);
                        trans = btrfs_start_transaction(tree_root, 0);
+                       BUG_ON(IS_ERR(trans));
                        if (block_rsv)
                                trans->block_rsv = block_rsv;
                }
@@ -6446,6 +6507,8 @@ static noinline int relocate_inode_pages(struct inode *inode, u64 start,
        int ret = 0;
 
        ra = kzalloc(sizeof(*ra), GFP_NOFS);
+       if (!ra)
+               return -ENOMEM;
 
        mutex_lock(&inode->i_mutex);
        first_index = start >> PAGE_CACHE_SHIFT;
@@ -6531,7 +6594,7 @@ static noinline int relocate_data_extent(struct inode *reloc_inode,
        u64 end = start + extent_key->offset - 1;
 
        em = alloc_extent_map(GFP_NOFS);
-       BUG_ON(!em || IS_ERR(em));
+       BUG_ON(!em);
 
        em->start = start;
        em->len = extent_key->offset;
@@ -7477,7 +7540,7 @@ int btrfs_drop_dead_reloc_roots(struct btrfs_root *root)
                BUG_ON(reloc_root->commit_root != NULL);
                while (1) {
                        trans = btrfs_join_transaction(root, 1);
-                       BUG_ON(!trans);
+                       BUG_ON(IS_ERR(trans));
 
                        mutex_lock(&root->fs_info->drop_mutex);
                        ret = btrfs_drop_snapshot(trans, reloc_root);
@@ -7535,7 +7598,7 @@ int btrfs_cleanup_reloc_trees(struct btrfs_root *root)
 
        if (found) {
                trans = btrfs_start_transaction(root, 1);
-               BUG_ON(!trans);
+               BUG_ON(IS_ERR(trans));
                ret = btrfs_commit_transaction(trans, root);
                BUG_ON(ret);
        }
@@ -7779,7 +7842,7 @@ static noinline int relocate_one_extent(struct btrfs_root *extent_root,
 
 
        trans = btrfs_start_transaction(extent_root, 1);
-       BUG_ON(!trans);
+       BUG_ON(IS_ERR(trans));
 
        if (extent_key->objectid == 0) {
                ret = del_extent_zero(trans, extent_root, path, extent_key);
@@ -8013,6 +8076,13 @@ out:
        return ret;
 }
 
+int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans,
+                           struct btrfs_root *root, u64 type)
+{
+       u64 alloc_flags = get_alloc_profile(root, type);
+       return do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags, 1);
+}
+
 /*
  * helper to account the unused space of all the readonly block group in the
  * list. takes mirrors into account.
@@ -8270,6 +8340,13 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
                if (block_group->cached == BTRFS_CACHE_STARTED)
                        wait_block_group_cache_done(block_group);
 
+               /*
+                * We haven't cached this block group, which means we could
+                * possibly have excluded extents on this block group.
+                */
+               if (block_group->cached == BTRFS_CACHE_NO)
+                       free_excluded_extents(info->extent_root, block_group);
+
                btrfs_remove_free_space_cache(block_group);
                btrfs_put_block_group(block_group);
 
@@ -8384,6 +8461,13 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                cache->flags = btrfs_block_group_flags(&cache->item);
                cache->sectorsize = root->sectorsize;
 
+               /*
+                * We need to exclude the super stripes now so that the space
+                * info has super bytes accounted for, otherwise we'll think
+                * we have more space than we actually do.
+                */
+               exclude_super_stripes(root, cache);
+
                /*
                 * check for two cases, either we are full, and therefore
                 * don't need to bother with the caching work since we won't
@@ -8392,12 +8476,10 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                 * time, particularly in the full case.
                 */
                if (found_key.offset == btrfs_block_group_used(&cache->item)) {
-                       exclude_super_stripes(root, cache);
                        cache->last_byte_to_unpin = (u64)-1;
                        cache->cached = BTRFS_CACHE_FINISHED;
                        free_excluded_extents(root, cache);
                } else if (btrfs_block_group_used(&cache->item) == 0) {
-                       exclude_super_stripes(root, cache);
                        cache->last_byte_to_unpin = (u64)-1;
                        cache->cached = BTRFS_CACHE_FINISHED;
                        add_new_free_space(cache, root->fs_info,
index 2e993cf..714adc4 100644 (file)
@@ -1433,12 +1433,13 @@ int extent_clear_unlock_delalloc(struct inode *inode,
  */
 u64 count_range_bits(struct extent_io_tree *tree,
                     u64 *start, u64 search_end, u64 max_bytes,
-                    unsigned long bits)
+                    unsigned long bits, int contig)
 {
        struct rb_node *node;
        struct extent_state *state;
        u64 cur_start = *start;
        u64 total_bytes = 0;
+       u64 last = 0;
        int found = 0;
 
        if (search_end <= cur_start) {
@@ -1463,7 +1464,9 @@ u64 count_range_bits(struct extent_io_tree *tree,
                state = rb_entry(node, struct extent_state, rb_node);
                if (state->start > search_end)
                        break;
-               if (state->end >= cur_start && (state->state & bits)) {
+               if (contig && found && state->start > last + 1)
+                       break;
+               if (state->end >= cur_start && (state->state & bits) == bits) {
                        total_bytes += min(search_end, state->end) + 1 -
                                       max(cur_start, state->start);
                        if (total_bytes >= max_bytes)
@@ -1472,6 +1475,9 @@ u64 count_range_bits(struct extent_io_tree *tree,
                                *start = state->start;
                                found = 1;
                        }
+                       last = state->end;
+               } else if (contig && found) {
+                       break;
                }
                node = rb_next(node);
                if (!node)
@@ -1865,7 +1871,7 @@ static int submit_one_bio(int rw, struct bio *bio, int mirror_num,
        bio_get(bio);
 
        if (tree->ops && tree->ops->submit_bio_hook)
-               tree->ops->submit_bio_hook(page->mapping->host, rw, bio,
+               ret = tree->ops->submit_bio_hook(page->mapping->host, rw, bio,
                                           mirror_num, bio_flags, start);
        else
                submit_bio(rw, bio);
@@ -1920,6 +1926,8 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree,
                nr = bio_get_nr_vecs(bdev);
 
        bio = btrfs_bio_alloc(bdev, sector, nr, GFP_NOFS | __GFP_HIGH);
+       if (!bio)
+               return -ENOMEM;
 
        bio_add_page(bio, page, page_size, offset);
        bio->bi_end_io = end_io_func;
@@ -1944,6 +1952,7 @@ void set_page_extent_mapped(struct page *page)
 
 static void set_page_extent_head(struct page *page, unsigned long len)
 {
+       WARN_ON(!PagePrivate(page));
        set_page_private(page, EXTENT_PAGE_PRIVATE_FIRST_PAGE | len << 2);
 }
 
@@ -2126,7 +2135,7 @@ int extent_read_full_page(struct extent_io_tree *tree, struct page *page,
        ret = __extent_read_full_page(tree, page, get_extent, &bio, 0,
                                      &bio_flags);
        if (bio)
-               submit_one_bio(READ, bio, 0, bio_flags);
+               ret = submit_one_bio(READ, bio, 0, bio_flags);
        return ret;
 }
 
@@ -2819,9 +2828,17 @@ int try_release_extent_state(struct extent_map_tree *map,
                 * at this point we can safely clear everything except the
                 * locked bit and the nodatasum bit
                 */
-               clear_extent_bit(tree, start, end,
+               ret = clear_extent_bit(tree, start, end,
                                 ~(EXTENT_LOCKED | EXTENT_NODATASUM),
                                 0, 0, NULL, mask);
+
+               /* if clear_extent_bit failed for enomem reasons,
+                * we can't allow the release to continue.
+                */
+               if (ret < 0)
+                       ret = 0;
+               else
+                       ret = 1;
        }
        return ret;
 }
@@ -2901,6 +2918,46 @@ out:
        return sector;
 }
 
+/*
+ * helper function for fiemap, which doesn't want to see any holes.
+ * This maps until we find something past 'last'
+ */
+static struct extent_map *get_extent_skip_holes(struct inode *inode,
+                                               u64 offset,
+                                               u64 last,
+                                               get_extent_t *get_extent)
+{
+       u64 sectorsize = BTRFS_I(inode)->root->sectorsize;
+       struct extent_map *em;
+       u64 len;
+
+       if (offset >= last)
+               return NULL;
+
+       while(1) {
+               len = last - offset;
+               if (len == 0)
+                       break;
+               len = (len + sectorsize - 1) & ~(sectorsize - 1);
+               em = get_extent(inode, NULL, 0, offset, len, 0);
+               if (!em || IS_ERR(em))
+                       return em;
+
+               /* if this isn't a hole return it */
+               if (!test_bit(EXTENT_FLAG_VACANCY, &em->flags) &&
+                   em->block_start != EXTENT_MAP_HOLE) {
+                       return em;
+               }
+
+               /* this is a hole, advance to the next extent */
+               offset = extent_map_end(em);
+               free_extent_map(em);
+               if (offset >= last)
+                       break;
+       }
+       return NULL;
+}
+
 int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                __u64 start, __u64 len, get_extent_t *get_extent)
 {
@@ -2910,16 +2967,19 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
        u32 flags = 0;
        u32 found_type;
        u64 last;
+       u64 last_for_get_extent = 0;
        u64 disko = 0;
+       u64 isize = i_size_read(inode);
        struct btrfs_key found_key;
        struct extent_map *em = NULL;
        struct extent_state *cached_state = NULL;
        struct btrfs_path *path;
        struct btrfs_file_extent_item *item;
        int end = 0;
-       u64 em_start = 0, em_len = 0;
+       u64 em_start = 0;
+       u64 em_len = 0;
+       u64 em_end = 0;
        unsigned long emflags;
-       int hole = 0;
 
        if (len == 0)
                return -EINVAL;
@@ -2929,6 +2989,10 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                return -ENOMEM;
        path->leave_spinning = 1;
 
+       /*
+        * lookup the last file extent.  We're not using i_size here
+        * because there might be preallocation past i_size
+        */
        ret = btrfs_lookup_file_extent(NULL, BTRFS_I(inode)->root,
                                       path, inode->i_ino, -1, 0);
        if (ret < 0) {
@@ -2942,18 +3006,38 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
        btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]);
        found_type = btrfs_key_type(&found_key);
 
-       /* No extents, just return */
+       /* No extents, but there might be delalloc bits */
        if (found_key.objectid != inode->i_ino ||
            found_type != BTRFS_EXTENT_DATA_KEY) {
-               btrfs_free_path(path);
-               return 0;
+               /* have to trust i_size as the end */
+               last = (u64)-1;
+               last_for_get_extent = isize;
+       } else {
+               /*
+                * remember the start of the last extent.  There are a
+                * bunch of different factors that go into the length of the
+                * extent, so its much less complex to remember where it started
+                */
+               last = found_key.offset;
+               last_for_get_extent = last + 1;
        }
-       last = found_key.offset;
        btrfs_free_path(path);
 
+       /*
+        * we might have some extents allocated but more delalloc past those
+        * extents.  so, we trust isize unless the start of the last extent is
+        * beyond isize
+        */
+       if (last < isize) {
+               last = (u64)-1;
+               last_for_get_extent = isize;
+       }
+
        lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len, 0,
                         &cached_state, GFP_NOFS);
-       em = get_extent(inode, NULL, 0, off, max - off, 0);
+
+       em = get_extent_skip_holes(inode, off, last_for_get_extent,
+                                  get_extent);
        if (!em)
                goto out;
        if (IS_ERR(em)) {
@@ -2962,22 +3046,38 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
        }
 
        while (!end) {
-               hole = 0;
-               off = em->start + em->len;
-               if (off >= max)
-                       end = 1;
+               u64 offset_in_extent;
 
-               if (em->block_start == EXTENT_MAP_HOLE) {
-                       hole = 1;
-                       goto next;
-               }
+               /* break if the extent we found is outside the range */
+               if (em->start >= max || extent_map_end(em) < off)
+                       break;
 
-               em_start = em->start;
-               em_len = em->len;
+               /*
+                * get_extent may return an extent that starts before our
+                * requested range.  We have to make sure the ranges
+                * we return to fiemap always move forward and don't
+                * overlap, so adjust the offsets here
+                */
+               em_start = max(em->start, off);
 
+               /*
+                * record the offset from the start of the extent
+                * for adjusting the disk offset below
+                */
+               offset_in_extent = em_start - em->start;
+               em_end = extent_map_end(em);
+               em_len = em_end - em_start;
+               emflags = em->flags;
                disko = 0;
                flags = 0;
 
+               /*
+                * bump off for our next call to get_extent
+                */
+               off = extent_map_end(em);
+               if (off >= max)
+                       end = 1;
+
                if (em->block_start == EXTENT_MAP_LAST_BYTE) {
                        end = 1;
                        flags |= FIEMAP_EXTENT_LAST;
@@ -2988,42 +3088,34 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                        flags |= (FIEMAP_EXTENT_DELALLOC |
                                  FIEMAP_EXTENT_UNKNOWN);
                } else {
-                       disko = em->block_start;
+                       disko = em->block_start + offset_in_extent;
                }
                if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags))
                        flags |= FIEMAP_EXTENT_ENCODED;
 
-next:
-               emflags = em->flags;
                free_extent_map(em);
                em = NULL;
-               if (!end) {
-                       em = get_extent(inode, NULL, 0, off, max - off, 0);
-                       if (!em)
-                               goto out;
-                       if (IS_ERR(em)) {
-                               ret = PTR_ERR(em);
-                               goto out;
-                       }
-                       emflags = em->flags;
-               }
-
-               if (test_bit(EXTENT_FLAG_VACANCY, &emflags)) {
+               if ((em_start >= last) || em_len == (u64)-1 ||
+                  (last == (u64)-1 && isize <= em_end)) {
                        flags |= FIEMAP_EXTENT_LAST;
                        end = 1;
                }
 
-               if (em_start == last) {
+               /* now scan forward to see if this is really the last extent. */
+               em = get_extent_skip_holes(inode, off, last_for_get_extent,
+                                          get_extent);
+               if (IS_ERR(em)) {
+                       ret = PTR_ERR(em);
+                       goto out;
+               }
+               if (!em) {
                        flags |= FIEMAP_EXTENT_LAST;
                        end = 1;
                }
-
-               if (!hole) {
-                       ret = fiemap_fill_next_extent(fieinfo, em_start, disko,
-                                               em_len, flags);
-                       if (ret)
-                               goto out_free;
-               }
+               ret = fiemap_fill_next_extent(fieinfo, em_start, disko,
+                                             em_len, flags);
+               if (ret)
+                       goto out_free;
        }
 out_free:
        free_extent_map(em);
@@ -3192,7 +3284,13 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
                }
                if (!PageUptodate(p))
                        uptodate = 0;
-               unlock_page(p);
+
+               /*
+                * see below about how we avoid a nasty race with release page
+                * and why we unlock later
+                */
+               if (i != 0)
+                       unlock_page(p);
        }
        if (uptodate)
                set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
@@ -3216,9 +3314,26 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
        atomic_inc(&eb->refs);
        spin_unlock(&tree->buffer_lock);
        radix_tree_preload_end();
+
+       /*
+        * there is a race where release page may have
+        * tried to find this extent buffer in the radix
+        * but failed.  It will tell the VM it is safe to
+        * reclaim the, and it will clear the page private bit.
+        * We must make sure to set the page private bit properly
+        * after the extent buffer is in the radix tree so
+        * it doesn't get lost
+        */
+       set_page_extent_mapped(eb->first_page);
+       set_page_extent_head(eb->first_page, eb->len);
+       if (!page0)
+               unlock_page(eb->first_page);
        return eb;
 
 free_eb:
+       if (eb->first_page && !page0)
+               unlock_page(eb->first_page);
+
        if (!atomic_dec_and_test(&eb->refs))
                return exists;
        btrfs_release_extent_buffer(eb);
@@ -3269,10 +3384,11 @@ int clear_extent_buffer_dirty(struct extent_io_tree *tree,
                        continue;
 
                lock_page(page);
+               WARN_ON(!PagePrivate(page));
+
+               set_page_extent_mapped(page);
                if (i == 0)
                        set_page_extent_head(page, eb->len);
-               else
-                       set_page_private(page, EXTENT_PAGE_PRIVATE);
 
                clear_page_dirty_for_io(page);
                spin_lock_irq(&page->mapping->tree_lock);
@@ -3462,6 +3578,13 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
 
        for (i = start_i; i < num_pages; i++) {
                page = extent_buffer_page(eb, i);
+
+               WARN_ON(!PagePrivate(page));
+
+               set_page_extent_mapped(page);
+               if (i == 0)
+                       set_page_extent_head(page, eb->len);
+
                if (inc_all_pages)
                        page_cache_get(page);
                if (!PageUptodate(page)) {
index 7083cfa..9318dfe 100644 (file)
@@ -191,7 +191,7 @@ void extent_io_exit(void);
 
 u64 count_range_bits(struct extent_io_tree *tree,
                     u64 *start, u64 search_end,
-                    u64 max_bytes, unsigned long bits);
+                    u64 max_bytes, unsigned long bits, int contig);
 
 void free_extent_state(struct extent_state *state);
 int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end,
index b0e1fce..2b6c12e 100644 (file)
@@ -51,8 +51,8 @@ struct extent_map *alloc_extent_map(gfp_t mask)
 {
        struct extent_map *em;
        em = kmem_cache_alloc(extent_map_cache, mask);
-       if (!em || IS_ERR(em))
-               return em;
+       if (!em)
+               return NULL;
        em->in_tree = 0;
        em->flags = 0;
        em->compress_type = BTRFS_COMPRESS_NONE;
index a562a25..4f19a3e 100644 (file)
@@ -536,6 +536,8 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
        root = root->fs_info->csum_root;
 
        path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
 
        while (1) {
                key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
@@ -548,7 +550,10 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
                        if (path->slots[0] == 0)
                                goto out;
                        path->slots[0]--;
+               } else if (ret < 0) {
+                       goto out;
                }
+
                leaf = path->nodes[0];
                btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
 
index c800d58..f447b78 100644 (file)
@@ -70,6 +70,19 @@ static noinline int btrfs_copy_from_user(loff_t pos, int num_pages,
 
                /* Flush processor's dcache for this page */
                flush_dcache_page(page);
+
+               /*
+                * if we get a partial write, we can end up with
+                * partially up to date pages.  These add
+                * a lot of complexity, so make sure they don't
+                * happen by forcing this copy to be retried.
+                *
+                * The rest of the btrfs_file_write code will fall
+                * back to page at a time copies after we return 0.
+                */
+               if (!PageUptodate(page) && copied < count)
+                       copied = 0;
+
                iov_iter_advance(i, copied);
                write_bytes -= copied;
                total_copied += copied;
@@ -186,6 +199,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                        split = alloc_extent_map(GFP_NOFS);
                if (!split2)
                        split2 = alloc_extent_map(GFP_NOFS);
+               BUG_ON(!split || !split2);
 
                write_lock(&em_tree->lock);
                em = lookup_extent_mapping(em_tree, start, len);
@@ -761,6 +775,27 @@ out:
        return 0;
 }
 
+/*
+ * on error we return an unlocked page and the error value
+ * on success we return a locked page and 0
+ */
+static int prepare_uptodate_page(struct page *page, u64 pos)
+{
+       int ret = 0;
+
+       if ((pos & (PAGE_CACHE_SIZE - 1)) && !PageUptodate(page)) {
+               ret = btrfs_readpage(NULL, page);
+               if (ret)
+                       return ret;
+               lock_page(page);
+               if (!PageUptodate(page)) {
+                       unlock_page(page);
+                       return -EIO;
+               }
+       }
+       return 0;
+}
+
 /*
  * this gets pages into the page cache and locks them down, it also properly
  * waits for data=ordered extents to finish before allowing the pages to be
@@ -776,6 +811,7 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file,
        unsigned long index = pos >> PAGE_CACHE_SHIFT;
        struct inode *inode = fdentry(file)->d_inode;
        int err = 0;
+       int faili = 0;
        u64 start_pos;
        u64 last_pos;
 
@@ -793,11 +829,24 @@ again:
        for (i = 0; i < num_pages; i++) {
                pages[i] = grab_cache_page(inode->i_mapping, index + i);
                if (!pages[i]) {
+                       faili = i - 1;
                        err = -ENOMEM;
-                       BUG_ON(1);
+                       goto fail;
+               }
+
+               if (i == 0)
+                       err = prepare_uptodate_page(pages[i], pos);
+               if (i == num_pages - 1)
+                       err = prepare_uptodate_page(pages[i],
+                                                   pos + write_bytes);
+               if (err) {
+                       page_cache_release(pages[i]);
+                       faili = i - 1;
+                       goto fail;
                }
                wait_on_page_writeback(pages[i]);
        }
+       err = 0;
        if (start_pos < inode->i_size) {
                struct btrfs_ordered_extent *ordered;
                lock_extent_bits(&BTRFS_I(inode)->io_tree,
@@ -837,6 +886,14 @@ again:
                WARN_ON(!PageLocked(pages[i]));
        }
        return 0;
+fail:
+       while (faili >= 0) {
+               unlock_page(pages[faili]);
+               page_cache_release(pages[faili]);
+               faili--;
+       }
+       return err;
+
 }
 
 static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
@@ -846,7 +903,6 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
        struct file *file = iocb->ki_filp;
        struct inode *inode = fdentry(file)->d_inode;
        struct btrfs_root *root = BTRFS_I(inode)->root;
-       struct page *pinned[2];
        struct page **pages = NULL;
        struct iov_iter i;
        loff_t *ppos = &iocb->ki_pos;
@@ -867,9 +923,6 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
        will_write = ((file->f_flags & O_DSYNC) || IS_SYNC(inode) ||
                      (file->f_flags & O_DIRECT));
 
-       pinned[0] = NULL;
-       pinned[1] = NULL;
-
        start_pos = pos;
 
        vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
@@ -946,6 +999,10 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
                     PAGE_CACHE_SIZE, PAGE_CACHE_SIZE /
                     (sizeof(struct page *)));
        pages = kmalloc(nrptrs * sizeof(struct page *), GFP_KERNEL);
+       if (!pages) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
        /* generic_write_checks can change our pos */
        start_pos = pos;
@@ -953,39 +1010,13 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
        first_index = pos >> PAGE_CACHE_SHIFT;
        last_index = (pos + iov_iter_count(&i)) >> PAGE_CACHE_SHIFT;
 
-       /*
-        * there are lots of better ways to do this, but this code
-        * makes sure the first and last page in the file range are
-        * up to date and ready for cow
-        */
-       if ((pos & (PAGE_CACHE_SIZE - 1))) {
-               pinned[0] = grab_cache_page(inode->i_mapping, first_index);
-               if (!PageUptodate(pinned[0])) {
-                       ret = btrfs_readpage(NULL, pinned[0]);
-                       BUG_ON(ret);
-                       wait_on_page_locked(pinned[0]);
-               } else {
-                       unlock_page(pinned[0]);
-               }
-       }
-       if ((pos + iov_iter_count(&i)) & (PAGE_CACHE_SIZE - 1)) {
-               pinned[1] = grab_cache_page(inode->i_mapping, last_index);
-               if (!PageUptodate(pinned[1])) {
-                       ret = btrfs_readpage(NULL, pinned[1]);
-                       BUG_ON(ret);
-                       wait_on_page_locked(pinned[1]);
-               } else {
-                       unlock_page(pinned[1]);
-               }
-       }
-
        while (iov_iter_count(&i) > 0) {
                size_t offset = pos & (PAGE_CACHE_SIZE - 1);
                size_t write_bytes = min(iov_iter_count(&i),
                                         nrptrs * (size_t)PAGE_CACHE_SIZE -
                                         offset);
-               size_t num_pages = (write_bytes + PAGE_CACHE_SIZE - 1) >>
-                                       PAGE_CACHE_SHIFT;
+               size_t num_pages = (write_bytes + offset +
+                                   PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
 
                WARN_ON(num_pages > nrptrs);
                memset(pages, 0, sizeof(struct page *) * nrptrs);
@@ -1015,8 +1046,20 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
 
                copied = btrfs_copy_from_user(pos, num_pages,
                                           write_bytes, pages, &i);
-               dirty_pages = (copied + PAGE_CACHE_SIZE - 1) >>
-                                       PAGE_CACHE_SHIFT;
+
+               /*
+                * if we have trouble faulting in the pages, fall
+                * back to one page at a time
+                */
+               if (copied < write_bytes)
+                       nrptrs = 1;
+
+               if (copied == 0)
+                       dirty_pages = 0;
+               else
+                       dirty_pages = (copied + offset +
+                                      PAGE_CACHE_SIZE - 1) >>
+                                      PAGE_CACHE_SHIFT;
 
                if (num_pages > dirty_pages) {
                        if (copied > 0)
@@ -1060,10 +1103,6 @@ out:
                err = ret;
 
        kfree(pages);
-       if (pinned[0])
-               page_cache_release(pinned[0]);
-       if (pinned[1])
-               page_cache_release(pinned[1]);
        *ppos = pos;
 
        /*
index 60d6842..a039065 100644 (file)
@@ -987,11 +987,18 @@ tree_search_offset(struct btrfs_block_group_cache *block_group,
        return entry;
 }
 
-static void unlink_free_space(struct btrfs_block_group_cache *block_group,
-                             struct btrfs_free_space *info)
+static inline void
+__unlink_free_space(struct btrfs_block_group_cache *block_group,
+                   struct btrfs_free_space *info)
 {
        rb_erase(&info->offset_index, &block_group->free_space_offset);
        block_group->free_extents--;
+}
+
+static void unlink_free_space(struct btrfs_block_group_cache *block_group,
+                             struct btrfs_free_space *info)
+{
+       __unlink_free_space(block_group, info);
        block_group->free_space -= info->bytes;
 }
 
@@ -1016,14 +1023,18 @@ static void recalculate_thresholds(struct btrfs_block_group_cache *block_group)
        u64 max_bytes;
        u64 bitmap_bytes;
        u64 extent_bytes;
+       u64 size = block_group->key.offset;
 
        /*
         * The goal is to keep the total amount of memory used per 1gb of space
         * at or below 32k, so we need to adjust how much memory we allow to be
         * used by extent based free space tracking
         */
-       max_bytes = MAX_CACHE_BYTES_PER_GIG *
-               (div64_u64(block_group->key.offset, 1024 * 1024 * 1024));
+       if (size < 1024 * 1024 * 1024)
+               max_bytes = MAX_CACHE_BYTES_PER_GIG;
+       else
+               max_bytes = MAX_CACHE_BYTES_PER_GIG *
+                       div64_u64(size, 1024 * 1024 * 1024);
 
        /*
         * we want to account for 1 more bitmap than what we have so we can make
@@ -1171,6 +1182,16 @@ static void add_new_bitmap(struct btrfs_block_group_cache *block_group,
        recalculate_thresholds(block_group);
 }
 
+static void free_bitmap(struct btrfs_block_group_cache *block_group,
+                       struct btrfs_free_space *bitmap_info)
+{
+       unlink_free_space(block_group, bitmap_info);
+       kfree(bitmap_info->bitmap);
+       kfree(bitmap_info);
+       block_group->total_bitmaps--;
+       recalculate_thresholds(block_group);
+}
+
 static noinline int remove_from_bitmap(struct btrfs_block_group_cache *block_group,
                              struct btrfs_free_space *bitmap_info,
                              u64 *offset, u64 *bytes)
@@ -1195,6 +1216,7 @@ again:
         */
        search_start = *offset;
        search_bytes = *bytes;
+       search_bytes = min(search_bytes, end - search_start + 1);
        ret = search_bitmap(block_group, bitmap_info, &search_start,
                            &search_bytes);
        BUG_ON(ret < 0 || search_start != *offset);
@@ -1211,13 +1233,8 @@ again:
 
        if (*bytes) {
                struct rb_node *next = rb_next(&bitmap_info->offset_index);
-               if (!bitmap_info->bytes) {
-                       unlink_free_space(block_group, bitmap_info);
-                       kfree(bitmap_info->bitmap);
-                       kfree(bitmap_info);
-                       block_group->total_bitmaps--;
-                       recalculate_thresholds(block_group);
-               }
+               if (!bitmap_info->bytes)
+                       free_bitmap(block_group, bitmap_info);
 
                /*
                 * no entry after this bitmap, but we still have bytes to
@@ -1250,13 +1267,8 @@ again:
                        return -EAGAIN;
 
                goto again;
-       } else if (!bitmap_info->bytes) {
-               unlink_free_space(block_group, bitmap_info);
-               kfree(bitmap_info->bitmap);
-               kfree(bitmap_info);
-               block_group->total_bitmaps--;
-               recalculate_thresholds(block_group);
-       }
+       } else if (!bitmap_info->bytes)
+               free_bitmap(block_group, bitmap_info);
 
        return 0;
 }
@@ -1359,22 +1371,14 @@ out:
        return ret;
 }
 
-int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
-                        u64 offset, u64 bytes)
+bool try_merge_free_space(struct btrfs_block_group_cache *block_group,
+                         struct btrfs_free_space *info, bool update_stat)
 {
-       struct btrfs_free_space *right_info = NULL;
-       struct btrfs_free_space *left_info = NULL;
-       struct btrfs_free_space *info = NULL;
-       int ret = 0;
-
-       info = kzalloc(sizeof(struct btrfs_free_space), GFP_NOFS);
-       if (!info)
-               return -ENOMEM;
-
-       info->offset = offset;
-       info->bytes = bytes;
-
-       spin_lock(&block_group->tree_lock);
+       struct btrfs_free_space *left_info;
+       struct btrfs_free_space *right_info;
+       bool merged = false;
+       u64 offset = info->offset;
+       u64 bytes = info->bytes;
 
        /*
         * first we want to see if there is free space adjacent to the range we
@@ -1388,37 +1392,62 @@ int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
        else
                left_info = tree_search_offset(block_group, offset - 1, 0, 0);
 
-       /*
-        * If there was no extent directly to the left or right of this new
-        * extent then we know we're going to have to allocate a new extent, so
-        * before we do that see if we need to drop this into a bitmap
-        */
-       if ((!left_info || left_info->bitmap) &&
-           (!right_info || right_info->bitmap)) {
-               ret = insert_into_bitmap(block_group, info);
-
-               if (ret < 0) {
-                       goto out;
-               } else if (ret) {
-                       ret = 0;
-                       goto out;
-               }
-       }
-
        if (right_info && !right_info->bitmap) {
-               unlink_free_space(block_group, right_info);
+               if (update_stat)
+                       unlink_free_space(block_group, right_info);
+               else
+                       __unlink_free_space(block_group, right_info);
                info->bytes += right_info->bytes;
                kfree(right_info);
+               merged = true;
        }
 
        if (left_info && !left_info->bitmap &&
            left_info->offset + left_info->bytes == offset) {
-               unlink_free_space(block_group, left_info);
+               if (update_stat)
+                       unlink_free_space(block_group, left_info);
+               else
+                       __unlink_free_space(block_group, left_info);
                info->offset = left_info->offset;
                info->bytes += left_info->bytes;
                kfree(left_info);
+               merged = true;
        }
 
+       return merged;
+}
+
+int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
+                        u64 offset, u64 bytes)
+{
+       struct btrfs_free_space *info;
+       int ret = 0;
+
+       info = kzalloc(sizeof(struct btrfs_free_space), GFP_NOFS);
+       if (!info)
+               return -ENOMEM;
+
+       info->offset = offset;
+       info->bytes = bytes;
+
+       spin_lock(&block_group->tree_lock);
+
+       if (try_merge_free_space(block_group, info, true))
+               goto link;
+
+       /*
+        * There was no extent directly to the left or right of this new
+        * extent then we know we're going to have to allocate a new extent, so
+        * before we do that see if we need to drop this into a bitmap
+        */
+       ret = insert_into_bitmap(block_group, info);
+       if (ret < 0) {
+               goto out;
+       } else if (ret) {
+               ret = 0;
+               goto out;
+       }
+link:
        ret = link_free_space(block_group, info);
        if (ret)
                kfree(info);
@@ -1621,6 +1650,7 @@ __btrfs_return_cluster_to_free_space(
                node = rb_next(&entry->offset_index);
                rb_erase(&entry->offset_index, &cluster->root);
                BUG_ON(entry->bitmap);
+               try_merge_free_space(block_group, entry, false);
                tree_insert_offset(&block_group->free_space_offset,
                                   entry->offset, &entry->offset_index, 0);
        }
@@ -1685,13 +1715,8 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group,
        ret = offset;
        if (entry->bitmap) {
                bitmap_clear_bits(block_group, entry, offset, bytes);
-               if (!entry->bytes) {
-                       unlink_free_space(block_group, entry);
-                       kfree(entry->bitmap);
-                       kfree(entry);
-                       block_group->total_bitmaps--;
-                       recalculate_thresholds(block_group);
-               }
+               if (!entry->bytes)
+                       free_bitmap(block_group, entry);
        } else {
                unlink_free_space(block_group, entry);
                entry->offset += bytes;
@@ -1789,6 +1814,8 @@ static u64 btrfs_alloc_from_bitmap(struct btrfs_block_group_cache *block_group,
 
        ret = search_start;
        bitmap_clear_bits(block_group, entry, ret, bytes);
+       if (entry->bytes == 0)
+               free_bitmap(block_group, entry);
 out:
        spin_unlock(&cluster->lock);
        spin_unlock(&block_group->tree_lock);
@@ -1842,15 +1869,26 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
                entry->offset += bytes;
                entry->bytes -= bytes;
 
-               if (entry->bytes == 0) {
+               if (entry->bytes == 0)
                        rb_erase(&entry->offset_index, &cluster->root);
-                       kfree(entry);
-               }
                break;
        }
 out:
        spin_unlock(&cluster->lock);
 
+       if (!ret)
+               return 0;
+
+       spin_lock(&block_group->tree_lock);
+
+       block_group->free_space -= bytes;
+       if (entry->bytes == 0) {
+               block_group->free_extents--;
+               kfree(entry);
+       }
+
+       spin_unlock(&block_group->tree_lock);
+
        return ret;
 }
 
index 160b55b..4a0107e 100644 (file)
@@ -416,7 +416,7 @@ again:
        }
        if (start == 0) {
                trans = btrfs_join_transaction(root, 1);
-               BUG_ON(!trans);
+               BUG_ON(IS_ERR(trans));
                btrfs_set_trans_block_group(trans, inode);
                trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
@@ -612,6 +612,7 @@ retry:
                            GFP_NOFS);
 
                trans = btrfs_join_transaction(root, 1);
+               BUG_ON(IS_ERR(trans));
                ret = btrfs_reserve_extent(trans, root,
                                           async_extent->compressed_size,
                                           async_extent->compressed_size,
@@ -643,6 +644,7 @@ retry:
                                        async_extent->ram_size - 1, 0);
 
                em = alloc_extent_map(GFP_NOFS);
+               BUG_ON(!em);
                em->start = async_extent->start;
                em->len = async_extent->ram_size;
                em->orig_start = em->start;
@@ -771,7 +773,7 @@ static noinline int cow_file_range(struct inode *inode,
 
        BUG_ON(root == root->fs_info->tree_root);
        trans = btrfs_join_transaction(root, 1);
-       BUG_ON(!trans);
+       BUG_ON(IS_ERR(trans));
        btrfs_set_trans_block_group(trans, inode);
        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
@@ -819,6 +821,7 @@ static noinline int cow_file_range(struct inode *inode,
                BUG_ON(ret);
 
                em = alloc_extent_map(GFP_NOFS);
+               BUG_ON(!em);
                em->start = start;
                em->orig_start = em->start;
                ram_size = ins.offset;
@@ -1049,7 +1052,7 @@ static noinline int run_delalloc_nocow(struct inode *inode,
        } else {
                trans = btrfs_join_transaction(root, 1);
        }
-       BUG_ON(!trans);
+       BUG_ON(IS_ERR(trans));
 
        cow_start = (u64)-1;
        cur_offset = start;
@@ -1168,6 +1171,7 @@ out_check:
                        struct extent_map_tree *em_tree;
                        em_tree = &BTRFS_I(inode)->extent_tree;
                        em = alloc_extent_map(GFP_NOFS);
+                       BUG_ON(!em);
                        em->start = cur_offset;
                        em->orig_start = em->start;
                        em->len = num_bytes;
@@ -1557,6 +1561,7 @@ out:
 out_page:
        unlock_page(page);
        page_cache_release(page);
+       kfree(fixup);
 }
 
 /*
@@ -1703,7 +1708,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
                                trans = btrfs_join_transaction_nolock(root, 1);
                        else
                                trans = btrfs_join_transaction(root, 1);
-                       BUG_ON(!trans);
+                       BUG_ON(IS_ERR(trans));
                        btrfs_set_trans_block_group(trans, inode);
                        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
                        ret = btrfs_update_inode(trans, root, inode);
@@ -1720,6 +1725,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
                trans = btrfs_join_transaction_nolock(root, 1);
        else
                trans = btrfs_join_transaction(root, 1);
+       BUG_ON(IS_ERR(trans));
        btrfs_set_trans_block_group(trans, inode);
        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
@@ -1907,7 +1913,7 @@ static int btrfs_clean_io_failures(struct inode *inode, u64 start)
 
        private = 0;
        if (count_range_bits(&BTRFS_I(inode)->io_failure_tree, &private,
-                            (u64)-1, 1, EXTENT_DIRTY)) {
+                            (u64)-1, 1, EXTENT_DIRTY, 0)) {
                ret = get_state_private(&BTRFS_I(inode)->io_failure_tree,
                                        start, &private_failure);
                if (ret == 0) {
@@ -2354,6 +2360,7 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
                 */
                if (is_bad_inode(inode)) {
                        trans = btrfs_start_transaction(root, 0);
+                       BUG_ON(IS_ERR(trans));
                        btrfs_orphan_del(trans, inode);
                        btrfs_end_transaction(trans, root);
                        iput(inode);
@@ -2381,6 +2388,7 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
 
        if (root->orphan_block_rsv || root->orphan_item_inserted) {
                trans = btrfs_join_transaction(root, 1);
+               BUG_ON(IS_ERR(trans));
                btrfs_end_transaction(trans, root);
        }
 
@@ -2641,7 +2649,7 @@ int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
        path = btrfs_alloc_path();
        if (!path) {
                ret = -ENOMEM;
-               goto err;
+               goto out;
        }
 
        path->leave_spinning = 1;
@@ -2714,9 +2722,10 @@ static int check_path_shared(struct btrfs_root *root,
        struct extent_buffer *eb;
        int level;
        u64 refs = 1;
-       int uninitialized_var(ret);
 
        for (level = 0; level < BTRFS_MAX_LEVEL; level++) {
+               int ret;
+
                if (!path->nodes[level])
                        break;
                eb = path->nodes[level];
@@ -2727,7 +2736,7 @@ static int check_path_shared(struct btrfs_root *root,
                if (refs > 1)
                        return 1;
        }
-       return ret; /* XXX callers? */
+       return 0;
 }
 
 /*
@@ -4134,7 +4143,7 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
        }
        srcu_read_unlock(&root->fs_info->subvol_srcu, index);
 
-       if (root != sub_root) {
+       if (!IS_ERR(inode) && root != sub_root) {
                down_read(&root->fs_info->cleanup_work_sem);
                if (!(inode->i_sb->s_flags & MS_RDONLY))
                        btrfs_orphan_cleanup(sub_root);
@@ -4347,6 +4356,8 @@ int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc)
                        trans = btrfs_join_transaction_nolock(root, 1);
                else
                        trans = btrfs_join_transaction(root, 1);
+               if (IS_ERR(trans))
+                       return PTR_ERR(trans);
                btrfs_set_trans_block_group(trans, inode);
                if (nolock)
                        ret = btrfs_end_transaction_nolock(trans, root);
@@ -4372,6 +4383,7 @@ void btrfs_dirty_inode(struct inode *inode)
                return;
 
        trans = btrfs_join_transaction(root, 1);
+       BUG_ON(IS_ERR(trans));
        btrfs_set_trans_block_group(trans, inode);
 
        ret = btrfs_update_inode(trans, root, inode);
@@ -4794,9 +4806,6 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
        int err;
        int drop_inode = 0;
 
-       if (inode->i_nlink == 0)
-               return -ENOENT;
-
        /* do not allow sys_link's with other subvols of the same device */
        if (root->objectid != BTRFS_I(inode)->root->objectid)
                return -EPERM;
@@ -4809,10 +4818,11 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
                goto fail;
 
        /*
-        * 1 item for inode ref
+        * 2 items for inode and inode ref
         * 2 items for dir items
+        * 1 item for parent inode
         */
-       trans = btrfs_start_transaction(root, 3);
+       trans = btrfs_start_transaction(root, 5);
        if (IS_ERR(trans)) {
                err = PTR_ERR(trans);
                goto fail;
@@ -5176,6 +5186,8 @@ again:
                                em = NULL;
                                btrfs_release_path(root, path);
                                trans = btrfs_join_transaction(root, 1);
+                               if (IS_ERR(trans))
+                                       return ERR_CAST(trans);
                                goto again;
                        }
                        map = kmap(page);
@@ -5266,6 +5278,128 @@ out:
        return em;
 }
 
+struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *page,
+                                          size_t pg_offset, u64 start, u64 len,
+                                          int create)
+{
+       struct extent_map *em;
+       struct extent_map *hole_em = NULL;
+       u64 range_start = start;
+       u64 end;
+       u64 found;
+       u64 found_end;
+       int err = 0;
+
+       em = btrfs_get_extent(inode, page, pg_offset, start, len, create);
+       if (IS_ERR(em))
+               return em;
+       if (em) {
+               /*
+                * if our em maps to a hole, there might
+                * actually be delalloc bytes behind it
+                */
+               if (em->block_start != EXTENT_MAP_HOLE)
+                       return em;
+               else
+                       hole_em = em;
+       }
+
+       /* check to see if we've wrapped (len == -1 or similar) */
+       end = start + len;
+       if (end < start)
+               end = (u64)-1;
+       else
+               end -= 1;
+
+       em = NULL;
+
+       /* ok, we didn't find anything, lets look for delalloc */
+       found = count_range_bits(&BTRFS_I(inode)->io_tree, &range_start,
+                                end, len, EXTENT_DELALLOC, 1);
+       found_end = range_start + found;
+       if (found_end < range_start)
+               found_end = (u64)-1;
+
+       /*
+        * we didn't find anything useful, return
+        * the original results from get_extent()
+        */
+       if (range_start > end || found_end <= start) {
+               em = hole_em;
+               hole_em = NULL;
+               goto out;
+       }
+
+       /* adjust the range_start to make sure it doesn't
+        * go backwards from the start they passed in
+        */
+       range_start = max(start,range_start);
+       found = found_end - range_start;
+
+       if (found > 0) {
+               u64 hole_start = start;
+               u64 hole_len = len;
+
+               em = alloc_extent_map(GFP_NOFS);
+               if (!em) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+               /*
+                * when btrfs_get_extent can't find anything it
+                * returns one huge hole
+                *
+                * make sure what it found really fits our range, and
+                * adjust to make sure it is based on the start from
+                * the caller
+                */
+               if (hole_em) {
+                       u64 calc_end = extent_map_end(hole_em);
+
+                       if (calc_end <= start || (hole_em->start > end)) {
+                               free_extent_map(hole_em);
+                               hole_em = NULL;
+                       } else {
+                               hole_start = max(hole_em->start, start);
+                               hole_len = calc_end - hole_start;
+                       }
+               }
+               em->bdev = NULL;
+               if (hole_em && range_start > hole_start) {
+                       /* our hole starts before our delalloc, so we
+                        * have to return just the parts of the hole
+                        * that go until  the delalloc starts
+                        */
+                       em->len = min(hole_len,
+                                     range_start - hole_start);
+                       em->start = hole_start;
+                       em->orig_start = hole_start;
+                       /*
+                        * don't adjust block start at all,
+                        * it is fixed at EXTENT_MAP_HOLE
+                        */
+                       em->block_start = hole_em->block_start;
+                       em->block_len = hole_len;
+               } else {
+                       em->start = range_start;
+                       em->len = found;
+                       em->orig_start = range_start;
+                       em->block_start = EXTENT_MAP_DELALLOC;
+                       em->block_len = found;
+               }
+       } else if (hole_em) {
+               return hole_em;
+       }
+out:
+
+       free_extent_map(hole_em);
+       if (err) {
+               free_extent_map(em);
+               return ERR_PTR(err);
+       }
+       return em;
+}
+
 static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
                                                  u64 start, u64 len)
 {
@@ -5280,8 +5414,8 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
        btrfs_drop_extent_cache(inode, start, start + len - 1, 0);
 
        trans = btrfs_join_transaction(root, 0);
-       if (!trans)
-               return ERR_PTR(-ENOMEM);
+       if (IS_ERR(trans))
+               return ERR_CAST(trans);
 
        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
@@ -5505,7 +5639,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
                 * while we look for nocow cross refs
                 */
                trans = btrfs_join_transaction(root, 0);
-               if (!trans)
+               if (IS_ERR(trans))
                        goto must_cow;
 
                if (can_nocow_odirect(trans, inode, start, len) == 1) {
@@ -5640,7 +5774,7 @@ again:
        BUG_ON(!ordered);
 
        trans = btrfs_join_transaction(root, 1);
-       if (!trans) {
+       if (IS_ERR(trans)) {
                err = -ENOMEM;
                goto out;
        }
@@ -5920,6 +6054,7 @@ static void btrfs_submit_direct(int rw, struct bio *bio, struct inode *inode,
        if (!skip_sum) {
                dip->csums = kmalloc(sizeof(u32) * bio->bi_vcnt, GFP_NOFS);
                if (!dip->csums) {
+                       kfree(dip);
                        ret = -ENOMEM;
                        goto free_ordered;
                }
@@ -6088,7 +6223,7 @@ out:
 static int btrfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                __u64 start, __u64 len)
 {
-       return extent_fiemap(inode, fieinfo, start, len, btrfs_get_extent);
+       return extent_fiemap(inode, fieinfo, start, len, btrfs_get_extent_fiemap);
 }
 
 int btrfs_readpage(struct file *file, struct page *page)
index a506a22..5fdb2ab 100644 (file)
@@ -203,7 +203,7 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
 
 
        trans = btrfs_join_transaction(root, 1);
-       BUG_ON(!trans);
+       BUG_ON(IS_ERR(trans));
 
        ret = btrfs_update_inode(trans, root, inode);
        BUG_ON(ret);
@@ -907,6 +907,10 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
 
        if (new_size > old_size) {
                trans = btrfs_start_transaction(root, 0);
+               if (IS_ERR(trans)) {
+                       ret = PTR_ERR(trans);
+                       goto out_unlock;
+               }
                ret = btrfs_grow_device(trans, device, new_size);
                btrfs_commit_transaction(trans, root);
        } else {
@@ -1067,12 +1071,15 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file,
        if (copy_from_user(&flags, arg, sizeof(flags)))
                return -EFAULT;
 
-       if (flags & ~BTRFS_SUBVOL_CREATE_ASYNC)
+       if (flags & BTRFS_SUBVOL_CREATE_ASYNC)
                return -EINVAL;
 
        if (flags & ~BTRFS_SUBVOL_RDONLY)
                return -EOPNOTSUPP;
 
+       if (!is_owner_or_cap(inode))
+               return -EACCES;
+
        down_write(&root->fs_info->subvol_sem);
 
        /* nothing to do */
@@ -1093,7 +1100,7 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file,
                goto out_reset;
        }
 
-       ret = btrfs_update_root(trans, root,
+       ret = btrfs_update_root(trans, root->fs_info->tree_root,
                                &root->root_key, &root->root_item);
 
        btrfs_commit_transaction(trans, root);
@@ -1898,7 +1905,10 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
 
                        memcpy(&new_key, &key, sizeof(new_key));
                        new_key.objectid = inode->i_ino;
-                       new_key.offset = key.offset + destoff - off;
+                       if (off <= key.offset)
+                               new_key.offset = key.offset + destoff - off;
+                       else
+                               new_key.offset = destoff;
 
                        trans = btrfs_start_transaction(root, 1);
                        if (IS_ERR(trans)) {
@@ -2082,7 +2092,7 @@ static long btrfs_ioctl_trans_start(struct file *file)
 
        ret = -ENOMEM;
        trans = btrfs_start_ioctl_transaction(root, 0);
-       if (!trans)
+       if (IS_ERR(trans))
                goto out_drop;
 
        file->private_data = trans;
@@ -2138,9 +2148,9 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
        path->leave_spinning = 1;
 
        trans = btrfs_start_transaction(root, 1);
-       if (!trans) {
+       if (IS_ERR(trans)) {
                btrfs_free_path(path);
-               return -ENOMEM;
+               return PTR_ERR(trans);
        }
 
        dir_id = btrfs_super_root_dir(&root->fs_info->super_copy);
@@ -2201,7 +2211,7 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
        int num_types = 4;
        int alloc_size;
        int ret = 0;
-       int slot_count = 0;
+       u64 slot_count = 0;
        int i, c;
 
        if (copy_from_user(&space_args,
@@ -2240,7 +2250,7 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
                goto out;
        }
 
-       slot_count = min_t(int, space_args.space_slots, slot_count);
+       slot_count = min_t(u64, space_args.space_slots, slot_count);
 
        alloc_size = sizeof(*dest) * slot_count;
 
@@ -2260,6 +2270,9 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
        for (i = 0; i < num_types; i++) {
                struct btrfs_space_info *tmp;
 
+               if (!slot_count)
+                       break;
+
                info = NULL;
                rcu_read_lock();
                list_for_each_entry_rcu(tmp, &root->fs_info->space_info,
@@ -2281,7 +2294,10 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
                                memcpy(dest, &space, sizeof(space));
                                dest++;
                                space_args.total_spaces++;
+                               slot_count--;
                        }
+                       if (!slot_count)
+                               break;
                }
                up_read(&info->groups_sem);
        }
@@ -2334,6 +2350,8 @@ static noinline long btrfs_ioctl_start_sync(struct file *file, void __user *argp
        u64 transid;
 
        trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
        transid = trans->transid;
        btrfs_commit_transaction_async(trans, root, 0);
 
index cc9b450..a178f5e 100644 (file)
@@ -280,6 +280,7 @@ static int lzo_decompress_biovec(struct list_head *ws,
        unsigned long tot_out;
        unsigned long tot_len;
        char *buf;
+       bool may_late_unmap, need_unmap;
 
        data_in = kmap(pages_in[0]);
        tot_len = read_compress_length(data_in);
@@ -300,11 +301,13 @@ static int lzo_decompress_biovec(struct list_head *ws,
 
                tot_in += in_len;
                working_bytes = in_len;
+               may_late_unmap = need_unmap = false;
 
                /* fast path: avoid using the working buffer */
                if (in_page_bytes_left >= in_len) {
                        buf = data_in + in_offset;
                        bytes = in_len;
+                       may_late_unmap = true;
                        goto cont;
                }
 
@@ -329,14 +332,17 @@ cont:
                                if (working_bytes == 0 && tot_in >= tot_len)
                                        break;
 
-                               kunmap(pages_in[page_in_index]);
-                               page_in_index++;
-                               if (page_in_index >= total_pages_in) {
+                               if (page_in_index + 1 >= total_pages_in) {
                                        ret = -1;
-                                       data_in = NULL;
                                        goto done;
                                }
-                               data_in = kmap(pages_in[page_in_index]);
+
+                               if (may_late_unmap)
+                                       need_unmap = true;
+                               else
+                                       kunmap(pages_in[page_in_index]);
+
+                               data_in = kmap(pages_in[++page_in_index]);
 
                                in_page_bytes_left = PAGE_CACHE_SIZE;
                                in_offset = 0;
@@ -346,6 +352,8 @@ cont:
                out_len = lzo1x_worst_compress(PAGE_CACHE_SIZE);
                ret = lzo1x_decompress_safe(buf, in_len, workspace->buf,
                                            &out_len);
+               if (need_unmap)
+                       kunmap(pages_in[page_in_index - 1]);
                if (ret != LZO_E_OK) {
                        printk(KERN_WARNING "btrfs decompress failed\n");
                        ret = -1;
@@ -363,8 +371,7 @@ cont:
                        break;
        }
 done:
-       if (data_in)
-               kunmap(pages_in[page_in_index]);
+       kunmap(pages_in[page_in_index]);
        return ret;
 }
 
index 2b61e1d..083a554 100644 (file)
@@ -141,7 +141,7 @@ static inline struct rb_node *tree_search(struct btrfs_ordered_inode_tree *tree,
                                          u64 file_offset)
 {
        struct rb_root *root = &tree->tree;
-       struct rb_node *prev;
+       struct rb_node *prev = NULL;
        struct rb_node *ret;
        struct btrfs_ordered_extent *entry;
 
index 0d126be..fb2605d 100644 (file)
@@ -260,6 +260,7 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
 #else
                        BUG();
 #endif
+                       break;
                case BTRFS_BLOCK_GROUP_ITEM_KEY:
                        bi = btrfs_item_ptr(l, i,
                                            struct btrfs_block_group_item);
index 045c9c2..31ade58 100644 (file)
@@ -1157,6 +1157,7 @@ static int clone_backref_node(struct btrfs_trans_handle *trans,
        new_node->bytenr = dest->node->start;
        new_node->level = node->level;
        new_node->lowest = node->lowest;
+       new_node->checked = 1;
        new_node->root = dest;
 
        if (!node->lowest) {
@@ -2028,6 +2029,7 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
 
        while (1) {
                trans = btrfs_start_transaction(root, 0);
+               BUG_ON(IS_ERR(trans));
                trans->block_rsv = rc->block_rsv;
 
                ret = btrfs_block_rsv_check(trans, root, rc->block_rsv,
@@ -2147,6 +2149,12 @@ again:
        }
 
        trans = btrfs_join_transaction(rc->extent_root, 1);
+       if (IS_ERR(trans)) {
+               if (!err)
+                       btrfs_block_rsv_release(rc->extent_root,
+                                               rc->block_rsv, num_bytes);
+               return PTR_ERR(trans);
+       }
 
        if (!err) {
                if (num_bytes != rc->merging_rsv_size) {
@@ -3222,6 +3230,7 @@ truncate:
        trans = btrfs_join_transaction(root, 0);
        if (IS_ERR(trans)) {
                btrfs_free_path(path);
+               ret = PTR_ERR(trans);
                goto out;
        }
 
@@ -3628,6 +3637,7 @@ int prepare_to_relocate(struct reloc_control *rc)
        set_reloc_control(rc);
 
        trans = btrfs_join_transaction(rc->extent_root, 1);
+       BUG_ON(IS_ERR(trans));
        btrfs_commit_transaction(trans, rc->extent_root);
        return 0;
 }
@@ -3644,6 +3654,7 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
        u32 item_size;
        int ret;
        int err = 0;
+       int progress = 0;
 
        path = btrfs_alloc_path();
        if (!path)
@@ -3656,8 +3667,10 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
        }
 
        while (1) {
+               progress++;
                trans = btrfs_start_transaction(rc->extent_root, 0);
-
+               BUG_ON(IS_ERR(trans));
+restart:
                if (update_backref_cache(trans, &rc->backref_cache)) {
                        btrfs_end_transaction(trans, rc->extent_root);
                        continue;
@@ -3770,6 +3783,15 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
                        }
                }
        }
+       if (trans && progress && err == -ENOSPC) {
+               ret = btrfs_force_chunk_alloc(trans, rc->extent_root,
+                                             rc->block_group->flags);
+               if (ret == 0) {
+                       err = 0;
+                       progress = 0;
+                       goto restart;
+               }
+       }
 
        btrfs_release_path(rc->extent_root, path);
        clear_extent_bits(&rc->processed_blocks, 0, (u64)-1, EXTENT_DIRTY,
@@ -3804,7 +3826,10 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
 
        /* get rid of pinned extents */
        trans = btrfs_join_transaction(rc->extent_root, 1);
-       btrfs_commit_transaction(trans, rc->extent_root);
+       if (IS_ERR(trans))
+               err = PTR_ERR(trans);
+       else
+               btrfs_commit_transaction(trans, rc->extent_root);
 out_free:
        btrfs_free_block_rsv(rc->extent_root, rc->block_rsv);
        btrfs_free_path(path);
@@ -4022,6 +4047,7 @@ static noinline_for_stack int mark_garbage_root(struct btrfs_root *root)
        int ret;
 
        trans = btrfs_start_transaction(root->fs_info->tree_root, 0);
+       BUG_ON(IS_ERR(trans));
 
        memset(&root->root_item.drop_progress, 0,
                sizeof(root->root_item.drop_progress));
@@ -4125,6 +4151,11 @@ int btrfs_recover_relocation(struct btrfs_root *root)
        set_reloc_control(rc);
 
        trans = btrfs_join_transaction(rc->extent_root, 1);
+       if (IS_ERR(trans)) {
+               unset_reloc_control(rc);
+               err = PTR_ERR(trans);
+               goto out_free;
+       }
 
        rc->merge_reloc_tree = 1;
 
@@ -4154,9 +4185,13 @@ int btrfs_recover_relocation(struct btrfs_root *root)
        unset_reloc_control(rc);
 
        trans = btrfs_join_transaction(rc->extent_root, 1);
-       btrfs_commit_transaction(trans, rc->extent_root);
-out:
+       if (IS_ERR(trans))
+               err = PTR_ERR(trans);
+       else
+               btrfs_commit_transaction(trans, rc->extent_root);
+out_free:
        kfree(rc);
+out:
        while (!list_empty(&reloc_roots)) {
                reloc_root = list_entry(reloc_roots.next,
                                        struct btrfs_root, root_list);
index b2130c4..d39a989 100644 (file)
@@ -155,7 +155,8 @@ enum {
        Opt_nossd, Opt_ssd_spread, Opt_thread_pool, Opt_noacl, Opt_compress,
        Opt_compress_type, Opt_compress_force, Opt_compress_force_type,
        Opt_notreelog, Opt_ratio, Opt_flushoncommit, Opt_discard,
-       Opt_space_cache, Opt_clear_cache, Opt_user_subvol_rm_allowed, Opt_err,
+       Opt_space_cache, Opt_clear_cache, Opt_user_subvol_rm_allowed,
+       Opt_enospc_debug, Opt_err,
 };
 
 static match_table_t tokens = {
@@ -184,6 +185,7 @@ static match_table_t tokens = {
        {Opt_space_cache, "space_cache"},
        {Opt_clear_cache, "clear_cache"},
        {Opt_user_subvol_rm_allowed, "user_subvol_rm_allowed"},
+       {Opt_enospc_debug, "enospc_debug"},
        {Opt_err, NULL},
 };
 
@@ -358,6 +360,9 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                case Opt_user_subvol_rm_allowed:
                        btrfs_set_opt(info->mount_opt, USER_SUBVOL_RM_ALLOWED);
                        break;
+               case Opt_enospc_debug:
+                       btrfs_set_opt(info->mount_opt, ENOSPC_DEBUG);
+                       break;
                case Opt_err:
                        printk(KERN_INFO "btrfs: unrecognized mount option "
                               "'%s'\n", p);
@@ -383,7 +388,7 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags,
                struct btrfs_fs_devices **fs_devices)
 {
        substring_t args[MAX_OPT_ARGS];
-       char *opts, *p;
+       char *opts, *orig, *p;
        int error = 0;
        int intarg;
 
@@ -397,6 +402,7 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags,
        opts = kstrdup(options, GFP_KERNEL);
        if (!opts)
                return -ENOMEM;
+       orig = opts;
 
        while ((p = strsep(&opts, ",")) != NULL) {
                int token;
@@ -432,7 +438,7 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags,
        }
 
  out_free_opts:
-       kfree(opts);
+       kfree(orig);
  out:
        /*
         * If no subvolume name is specified we use the default one.  Allocate
@@ -623,6 +629,8 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
        btrfs_wait_ordered_extents(root, 0, 0);
 
        trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
        ret = btrfs_commit_transaction(trans, root);
        return ret;
 }
@@ -761,6 +769,8 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
                }
 
                btrfs_close_devices(fs_devices);
+               kfree(fs_info);
+               kfree(tree_root);
        } else {
                char b[BDEVNAME_SIZE];
 
index bae5c7b..3d73c8d 100644 (file)
@@ -1161,6 +1161,11 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
        INIT_DELAYED_WORK(&ac->work, do_async_commit);
        ac->root = root;
        ac->newtrans = btrfs_join_transaction(root, 0);
+       if (IS_ERR(ac->newtrans)) {
+               int err = PTR_ERR(ac->newtrans);
+               kfree(ac);
+               return err;
+       }
 
        /* take transaction reference */
        mutex_lock(&root->fs_info->trans_mutex);
index 054744a..a4bbb85 100644 (file)
@@ -338,6 +338,12 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
                }
                dst_copy = kmalloc(item_size, GFP_NOFS);
                src_copy = kmalloc(item_size, GFP_NOFS);
+               if (!dst_copy || !src_copy) {
+                       btrfs_release_path(root, path);
+                       kfree(dst_copy);
+                       kfree(src_copy);
+                       return -ENOMEM;
+               }
 
                read_extent_buffer(eb, src_copy, src_ptr, item_size);
 
@@ -665,6 +671,9 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
        btrfs_dir_item_key_to_cpu(leaf, di, &location);
        name_len = btrfs_dir_name_len(leaf, di);
        name = kmalloc(name_len, GFP_NOFS);
+       if (!name)
+               return -ENOMEM;
+
        read_extent_buffer(leaf, name, (unsigned long)(di + 1), name_len);
        btrfs_release_path(root, path);
 
@@ -744,6 +753,9 @@ static noinline int backref_in_log(struct btrfs_root *log,
        int match = 0;
 
        path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
        ret = btrfs_search_slot(NULL, log, key, path, 0, 0);
        if (ret != 0)
                goto out;
@@ -967,6 +979,8 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
        key.offset = (u64)-1;
 
        path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
 
        while (1) {
                ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
@@ -1178,6 +1192,9 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
 
        name_len = btrfs_dir_name_len(eb, di);
        name = kmalloc(name_len, GFP_NOFS);
+       if (!name)
+               return -ENOMEM;
+
        log_type = btrfs_dir_type(eb, di);
        read_extent_buffer(eb, name, (unsigned long)(di + 1),
                   name_len);
@@ -1692,6 +1709,8 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
                root_owner = btrfs_header_owner(parent);
 
                next = btrfs_find_create_tree_block(root, bytenr, blocksize);
+               if (!next)
+                       return -ENOMEM;
 
                if (*level == 1) {
                        wc->process_func(root, next, wc, ptr_gen);
@@ -2032,6 +2051,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
                wait_log_commit(trans, log_root_tree,
                                log_root_tree->log_transid);
                mutex_unlock(&log_root_tree->log_mutex);
+               ret = 0;
                goto out;
        }
        atomic_set(&log_root_tree->log_commit[index2], 1);
@@ -2096,7 +2116,7 @@ out:
        smp_mb();
        if (waitqueue_active(&root->log_commit_wait[index1]))
                wake_up(&root->log_commit_wait[index1]);
-       return 0;
+       return ret;
 }
 
 static void free_log_tree(struct btrfs_trans_handle *trans,
@@ -2194,6 +2214,9 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
 
        log = root->log_root;
        path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
        di = btrfs_lookup_dir_item(trans, log, path, dir->i_ino,
                                   name, name_len, -1);
        if (IS_ERR(di)) {
@@ -2594,6 +2617,9 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
 
        ins_data = kmalloc(nr * sizeof(struct btrfs_key) +
                           nr * sizeof(u32), GFP_NOFS);
+       if (!ins_data)
+               return -ENOMEM;
+
        ins_sizes = (u32 *)ins_data;
        ins_keys = (struct btrfs_key *)(ins_data + nr * sizeof(u32));
 
@@ -2725,7 +2751,13 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
        log = root->log_root;
 
        path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
        dst_path = btrfs_alloc_path();
+       if (!dst_path) {
+               btrfs_free_path(path);
+               return -ENOMEM;
+       }
 
        min_key.objectid = inode->i_ino;
        min_key.type = BTRFS_INODE_ITEM_KEY;
@@ -3080,6 +3112,7 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
        BUG_ON(!path);
 
        trans = btrfs_start_transaction(fs_info->tree_root, 0);
+       BUG_ON(IS_ERR(trans));
 
        wc.trans = trans;
        wc.pin = 1;
index d158530..dd13eb8 100644 (file)
@@ -1213,6 +1213,10 @@ static int btrfs_rm_dev_item(struct btrfs_root *root,
                return -ENOMEM;
 
        trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans)) {
+               btrfs_free_path(path);
+               return PTR_ERR(trans);
+       }
        key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
        key.type = BTRFS_DEV_ITEM_KEY;
        key.offset = device->devid;
@@ -1334,11 +1338,11 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
 
        ret = btrfs_shrink_device(device, 0);
        if (ret)
-               goto error_brelse;
+               goto error_undo;
 
        ret = btrfs_rm_dev_item(root->fs_info->chunk_root, device);
        if (ret)
-               goto error_brelse;
+               goto error_undo;
 
        device->in_fs_metadata = 0;
 
@@ -1412,6 +1416,13 @@ out:
        mutex_unlock(&root->fs_info->volume_mutex);
        mutex_unlock(&uuid_mutex);
        return ret;
+error_undo:
+       if (device->writeable) {
+               list_add(&device->dev_alloc_list,
+                        &root->fs_info->fs_devices->alloc_list);
+               root->fs_info->fs_devices->rw_devices++;
+       }
+       goto error_brelse;
 }
 
 /*
@@ -1601,11 +1612,19 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
 
        ret = find_next_devid(root, &device->devid);
        if (ret) {
+               kfree(device->name);
                kfree(device);
                goto error;
        }
 
        trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans)) {
+               kfree(device->name);
+               kfree(device);
+               ret = PTR_ERR(trans);
+               goto error;
+       }
+
        lock_chunks(root);
 
        device->writeable = 1;
@@ -1621,7 +1640,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
        device->dev_root = root->fs_info->dev_root;
        device->bdev = bdev;
        device->in_fs_metadata = 1;
-       device->mode = 0;
+       device->mode = FMODE_EXCL;
        set_blocksize(device->bdev, 4096);
 
        if (seeding_dev) {
@@ -1873,7 +1892,7 @@ static int btrfs_relocate_chunk(struct btrfs_root *root,
                return ret;
 
        trans = btrfs_start_transaction(root, 0);
-       BUG_ON(!trans);
+       BUG_ON(IS_ERR(trans));
 
        lock_chunks(root);
 
@@ -2047,7 +2066,7 @@ int btrfs_balance(struct btrfs_root *dev_root)
                BUG_ON(ret);
 
                trans = btrfs_start_transaction(dev_root, 0);
-               BUG_ON(!trans);
+               BUG_ON(IS_ERR(trans));
 
                ret = btrfs_grow_device(trans, device, old_size);
                BUG_ON(ret);
@@ -2213,6 +2232,11 @@ again:
 
        /* Shrinking succeeded, else we would be at "done". */
        trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans)) {
+               ret = PTR_ERR(trans);
+               goto done;
+       }
+
        lock_chunks(root);
 
        device->disk_total_bytes = new_size;
index 60d27bc..6b61ded 100644 (file)
@@ -1560,9 +1560,10 @@ retry_locked:
                /* NOTE: no side-effects allowed, until we take s_mutex */
 
                revoking = cap->implemented & ~cap->issued;
-               if (revoking)
-                       dout(" mds%d revoking %s\n", cap->mds,
-                            ceph_cap_string(revoking));
+               dout(" mds%d cap %p issued %s implemented %s revoking %s\n",
+                    cap->mds, cap, ceph_cap_string(cap->issued),
+                    ceph_cap_string(cap->implemented),
+                    ceph_cap_string(revoking));
 
                if (cap == ci->i_auth_cap &&
                    (cap->issued & CEPH_CAP_FILE_WR)) {
@@ -1658,6 +1659,8 @@ ack:
 
                if (cap == ci->i_auth_cap && ci->i_dirty_caps)
                        flushing = __mark_caps_flushing(inode, session);
+               else
+                       flushing = 0;
 
                mds = cap->mds;  /* remember mds, so we don't repeat */
                sent++;
@@ -1940,6 +1943,35 @@ void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc,
        }
 }
 
+static void kick_flushing_inode_caps(struct ceph_mds_client *mdsc,
+                                    struct ceph_mds_session *session,
+                                    struct inode *inode)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_cap *cap;
+       int delayed = 0;
+
+       spin_lock(&inode->i_lock);
+       cap = ci->i_auth_cap;
+       dout("kick_flushing_inode_caps %p flushing %s flush_seq %lld\n", inode,
+            ceph_cap_string(ci->i_flushing_caps), ci->i_cap_flush_seq);
+       __ceph_flush_snaps(ci, &session, 1);
+       if (ci->i_flushing_caps) {
+               delayed = __send_cap(mdsc, cap, CEPH_CAP_OP_FLUSH,
+                                    __ceph_caps_used(ci),
+                                    __ceph_caps_wanted(ci),
+                                    cap->issued | cap->implemented,
+                                    ci->i_flushing_caps, NULL);
+               if (delayed) {
+                       spin_lock(&inode->i_lock);
+                       __cap_delay_requeue(mdsc, ci);
+                       spin_unlock(&inode->i_lock);
+               }
+       } else {
+               spin_unlock(&inode->i_lock);
+       }
+}
+
 
 /*
  * Take references to capabilities we hold, so that we don't release
@@ -2687,7 +2719,7 @@ static void handle_cap_import(struct ceph_mds_client *mdsc,
        ceph_add_cap(inode, session, cap_id, -1,
                     issued, wanted, seq, mseq, realmino, CEPH_CAP_FLAG_AUTH,
                     NULL /* no caps context */);
-       try_flush_caps(inode, session, NULL);
+       kick_flushing_inode_caps(mdsc, session, inode);
        up_read(&mdsc->snap_rwsem);
 
        /* make sure we re-request max_size, if necessary */
@@ -2785,8 +2817,7 @@ void ceph_handle_caps(struct ceph_mds_session *session,
        case CEPH_CAP_OP_IMPORT:
                handle_cap_import(mdsc, inode, h, session,
                                  snaptrace, snaptrace_len);
-               ceph_check_caps(ceph_inode(inode), CHECK_CAPS_NODELAY,
-                               session);
+               ceph_check_caps(ceph_inode(inode), 0, session);
                goto done_unlocked;
        }
 
index 0bc68de..ebafa65 100644 (file)
@@ -409,7 +409,7 @@ more:
        spin_lock(&inode->i_lock);
        if (ci->i_release_count == fi->dir_release_count) {
                dout(" marking %p complete\n", inode);
-               ci->i_ceph_flags |= CEPH_I_COMPLETE;
+               /* ci->i_ceph_flags |= CEPH_I_COMPLETE; */
                ci->i_max_offset = filp->f_pos;
        }
        spin_unlock(&inode->i_lock);
@@ -496,6 +496,7 @@ struct dentry *ceph_finish_lookup(struct ceph_mds_request *req,
 
        /* .snap dir? */
        if (err == -ENOENT &&
+           ceph_snap(parent) == CEPH_NOSNAP &&
            strcmp(dentry->d_name.name,
                   fsc->mount_options->snapdir_name) == 0) {
                struct inode *inode = ceph_get_snapdir(parent);
@@ -992,7 +993,7 @@ static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
        struct inode *dir;
 
-       if (nd->flags & LOOKUP_RCU)
+       if (nd && nd->flags & LOOKUP_RCU)
                return -ECHILD;
 
        dir = dentry->d_parent->d_inode;
@@ -1029,28 +1030,8 @@ out_touch:
 static void ceph_dentry_release(struct dentry *dentry)
 {
        struct ceph_dentry_info *di = ceph_dentry(dentry);
-       struct inode *parent_inode = NULL;
-       u64 snapid = CEPH_NOSNAP;
 
-       if (!IS_ROOT(dentry)) {
-               parent_inode = dentry->d_parent->d_inode;
-               if (parent_inode)
-                       snapid = ceph_snap(parent_inode);
-       }
-       dout("dentry_release %p parent %p\n", dentry, parent_inode);
-       if (parent_inode && snapid != CEPH_SNAPDIR) {
-               struct ceph_inode_info *ci = ceph_inode(parent_inode);
-
-               spin_lock(&parent_inode->i_lock);
-               if (ci->i_shared_gen == di->lease_shared_gen ||
-                   snapid <= CEPH_MAXSNAP) {
-                       dout(" clearing %p complete (d_release)\n",
-                            parent_inode);
-                       ci->i_ceph_flags &= ~CEPH_I_COMPLETE;
-                       ci->i_release_count++;
-               }
-               spin_unlock(&parent_inode->i_lock);
-       }
+       dout("dentry_release %p\n", dentry);
        if (di) {
                ceph_dentry_lru_del(dentry);
                if (di->lease_session)
index e835eff..193bfa5 100644 (file)
@@ -707,13 +707,9 @@ static int fill_inode(struct inode *inode,
                    (issued & CEPH_CAP_FILE_EXCL) == 0 &&
                    (ci->i_ceph_flags & CEPH_I_COMPLETE) == 0) {
                        dout(" marking %p complete (empty)\n", inode);
-                       ci->i_ceph_flags |= CEPH_I_COMPLETE;
+                       /* ci->i_ceph_flags |= CEPH_I_COMPLETE; */
                        ci->i_max_offset = 2;
                }
-
-               /* it may be better to set st_size in getattr instead? */
-               if (ceph_test_mount_opt(ceph_sb_to_client(inode->i_sb), RBYTES))
-                       inode->i_size = ci->i_rbytes;
                break;
        default:
                pr_err("fill_inode %llx.%llx BAD mode 0%o\n",
@@ -1819,7 +1815,11 @@ int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry,
                else
                        stat->dev = 0;
                if (S_ISDIR(inode->i_mode)) {
-                       stat->size = ci->i_rbytes;
+                       if (ceph_test_mount_opt(ceph_sb_to_client(inode->i_sb),
+                                               RBYTES))
+                               stat->size = ci->i_rbytes;
+                       else
+                               stat->size = ci->i_files + ci->i_subdirs;
                        stat->blocks = 0;
                        stat->blksize = 65536;
                }
index 1e30d19..a1ee8fa 100644 (file)
@@ -693,9 +693,11 @@ static int __choose_mds(struct ceph_mds_client *mdsc,
                                dout("choose_mds %p %llx.%llx "
                                     "frag %u mds%d (%d/%d)\n",
                                     inode, ceph_vinop(inode),
-                                    frag.frag, frag.mds,
+                                    frag.frag, mds,
                                     (int)r, frag.ndist);
-                               return mds;
+                               if (ceph_mdsmap_get_state(mdsc->mdsmap, mds) >=
+                                   CEPH_MDS_STATE_ACTIVE)
+                                       return mds;
                        }
 
                        /* since this file/dir wasn't known to be
@@ -708,7 +710,9 @@ static int __choose_mds(struct ceph_mds_client *mdsc,
                                dout("choose_mds %p %llx.%llx "
                                     "frag %u mds%d (auth)\n",
                                     inode, ceph_vinop(inode), frag.frag, mds);
-                               return mds;
+                               if (ceph_mdsmap_get_state(mdsc->mdsmap, mds) >=
+                                   CEPH_MDS_STATE_ACTIVE)
+                                       return mds;
                        }
                }
        }
index 39c243a..f40b913 100644 (file)
@@ -584,10 +584,14 @@ static void queue_realm_cap_snaps(struct ceph_snap_realm *realm)
        if (lastinode)
                iput(lastinode);
 
-       dout("queue_realm_cap_snaps %p %llx children\n", realm, realm->ino);
-       list_for_each_entry(child, &realm->children, child_item)
-               queue_realm_cap_snaps(child);
+       list_for_each_entry(child, &realm->children, child_item) {
+               dout("queue_realm_cap_snaps %p %llx queue child %p %llx\n",
+                    realm, realm->ino, child, child->ino);
+               list_del_init(&child->dirty_item);
+               list_add(&child->dirty_item, &realm->dirty_item);
+       }
 
+       list_del_init(&realm->dirty_item);
        dout("queue_realm_cap_snaps %p %llx done\n", realm, realm->ino);
 }
 
@@ -683,7 +687,9 @@ more:
         * queue cap snaps _after_ we've built the new snap contexts,
         * so that i_head_snapc can be set appropriately.
         */
-       list_for_each_entry(realm, &dirty_realms, dirty_item) {
+       while (!list_empty(&dirty_realms)) {
+               realm = list_first_entry(&dirty_realms, struct ceph_snap_realm,
+                                        dirty_item);
                queue_realm_cap_snaps(realm);
        }
 
index bf6f0f3..9c50854 100644 (file)
@@ -290,6 +290,8 @@ static int parse_mount_options(struct ceph_mount_options **pfsopt,
 
         fsopt->rsize = CEPH_MOUNT_RSIZE_DEFAULT;
         fsopt->snapdir_name = kstrdup(CEPH_SNAPDIRNAME_DEFAULT, GFP_KERNEL);
+       fsopt->caps_wanted_delay_min = CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT;
+       fsopt->caps_wanted_delay_max = CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT;
         fsopt->cap_release_safety = CEPH_CAP_RELEASE_SAFETY_DEFAULT;
         fsopt->max_readdir = CEPH_MAX_READDIR_DEFAULT;
         fsopt->max_readdir_bytes = CEPH_MAX_READDIR_BYTES_DEFAULT;
index 6e12a6b..8c9eba6 100644 (file)
@@ -219,6 +219,7 @@ static struct ceph_inode_xattr *__get_xattr(struct ceph_inode_info *ci,
        struct rb_node **p;
        struct rb_node *parent = NULL;
        struct ceph_inode_xattr *xattr = NULL;
+       int name_len = strlen(name);
        int c;
 
        p = &ci->i_xattrs.index.rb_node;
@@ -226,6 +227,8 @@ static struct ceph_inode_xattr *__get_xattr(struct ceph_inode_info *ci,
                parent = *p;
                xattr = rb_entry(parent, struct ceph_inode_xattr, node);
                c = strncmp(name, xattr->name, xattr->name_len);
+               if (c == 0 && name_len > xattr->name_len)
+                       c = 1;
                if (c < 0)
                        p = &(*p)->rb_left;
                else if (c > 0)
index ee45648..7cb0f7f 100644 (file)
@@ -3,6 +3,7 @@ config CIFS
        depends on INET
        select NLS
        select CRYPTO
+       select CRYPTO_MD4
        select CRYPTO_MD5
        select CRYPTO_HMAC
        select CRYPTO_ARC4
index 43b19dd..d875584 100644 (file)
@@ -5,7 +5,7 @@ obj-$(CONFIG_CIFS) += cifs.o
 
 cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \
          link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o \
-         md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o \
+         cifs_unicode.o nterr.o xattr.o cifsencrypt.o \
          readdir.o ioctl.o sess.o export.o
 
 cifs-$(CONFIG_CIFS_ACL) += cifsacl.o
index 46af99a..fe16835 100644 (file)
@@ -452,6 +452,11 @@ A partial list of the supported mount options follows:
                if oplock (caching token) is granted and held. Note that
                direct allows write operations larger than page size
                to be sent to the server.
+  strictcache   Use for switching on strict cache mode. In this mode the
+               client read from the cache all the time it has Oplock Level II,
+               otherwise - read from the server. All written data are stored
+               in the cache, but if the client doesn't have Exclusive Oplock,
+               it writes the data to the server.
   acl          Allow setfacl and getfacl to manage posix ACLs if server
                supports them.  (default)
   noacl        Do not allow setfacl and getfacl calls on this mount
index f1c6862..0a265ad 100644 (file)
@@ -282,8 +282,6 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
        cFYI(1, "in %s", __func__);
        BUG_ON(IS_ROOT(mntpt));
 
-       xid = GetXid();
-
        /*
         * The MSDFS spec states that paths in DFS referral requests and
         * responses must be prefixed by a single '\' character instead of
@@ -293,7 +291,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
        mnt = ERR_PTR(-ENOMEM);
        full_path = build_path_from_dentry(mntpt);
        if (full_path == NULL)
-               goto free_xid;
+               goto cdda_exit;
 
        cifs_sb = CIFS_SB(mntpt->d_inode->i_sb);
        tlink = cifs_sb_tlink(cifs_sb);
@@ -303,9 +301,11 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
        }
        ses = tlink_tcon(tlink)->ses;
 
+       xid = GetXid();
        rc = get_dfs_path(xid, ses, full_path + 1, cifs_sb->local_nls,
                &num_referrals, &referrals,
                cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       FreeXid(xid);
 
        cifs_put_tlink(tlink);
 
@@ -338,8 +338,7 @@ success:
        free_dfs_info_array(referrals, num_referrals);
 free_full_path:
        kfree(full_path);
-free_xid:
-       FreeXid(xid);
+cdda_exit:
        cFYI(1, "leaving %s" , __func__);
        return mnt;
 }
index 1e7636b..beeebf1 100644 (file)
@@ -372,6 +372,10 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
 
                ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
                                GFP_KERNEL);
+               if (!ppace) {
+                       cERROR(1, "DACL memory allocation error");
+                       return;
+               }
 
                for (i = 0; i < num_aces; ++i) {
                        ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
index 66f3d50..a51585f 100644 (file)
@@ -24,7 +24,6 @@
 #include "cifspdu.h"
 #include "cifsglob.h"
 #include "cifs_debug.h"
-#include "md5.h"
 #include "cifs_unicode.h"
 #include "cifsproto.h"
 #include "ntlmssp.h"
 /* Note that the smb header signature field on input contains the
        sequence number before this function is called */
 
-extern void mdfour(unsigned char *out, unsigned char *in, int n);
-extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
-extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8,
-                      unsigned char *p24);
-
 static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu,
                                struct TCP_Server_Info *server, char *signature)
 {
@@ -234,6 +228,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu,
 /* first calculate 24 bytes ntlm response and then 16 byte session key */
 int setup_ntlm_response(struct cifsSesInfo *ses)
 {
+       int rc = 0;
        unsigned int temp_len = CIFS_SESS_KEY_SIZE + CIFS_AUTH_RESP_SIZE;
        char temp_key[CIFS_SESS_KEY_SIZE];
 
@@ -247,13 +242,26 @@ int setup_ntlm_response(struct cifsSesInfo *ses)
        }
        ses->auth_key.len = temp_len;
 
-       SMBNTencrypt(ses->password, ses->server->cryptkey,
+       rc = SMBNTencrypt(ses->password, ses->server->cryptkey,
                        ses->auth_key.response + CIFS_SESS_KEY_SIZE);
+       if (rc) {
+               cFYI(1, "%s Can't generate NTLM response, error: %d",
+                       __func__, rc);
+               return rc;
+       }
 
-       E_md4hash(ses->password, temp_key);
-       mdfour(ses->auth_key.response, temp_key, CIFS_SESS_KEY_SIZE);
+       rc = E_md4hash(ses->password, temp_key);
+       if (rc) {
+               cFYI(1, "%s Can't generate NT hash, error: %d", __func__, rc);
+               return rc;
+       }
 
-       return 0;
+       rc = mdfour(ses->auth_key.response, temp_key, CIFS_SESS_KEY_SIZE);
+       if (rc)
+               cFYI(1, "%s Can't generate NTLM session key, error: %d",
+                       __func__, rc);
+
+       return rc;
 }
 
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
@@ -649,9 +657,10 @@ calc_seckey(struct cifsSesInfo *ses)
        get_random_bytes(sec_key, CIFS_SESS_KEY_SIZE);
 
        tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
-       if (!tfm_arc4 || IS_ERR(tfm_arc4)) {
+       if (IS_ERR(tfm_arc4)) {
+               rc = PTR_ERR(tfm_arc4);
                cERROR(1, "could not allocate crypto API arc4\n");
-               return PTR_ERR(tfm_arc4);
+               return rc;
        }
 
        desc.tfm = tfm_arc4;
@@ -700,14 +709,13 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
        unsigned int size;
 
        server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
-       if (!server->secmech.hmacmd5 ||
-                       IS_ERR(server->secmech.hmacmd5)) {
+       if (IS_ERR(server->secmech.hmacmd5)) {
                cERROR(1, "could not allocate crypto hmacmd5\n");
                return PTR_ERR(server->secmech.hmacmd5);
        }
 
        server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
-       if (!server->secmech.md5 || IS_ERR(server->secmech.md5)) {
+       if (IS_ERR(server->secmech.md5)) {
                cERROR(1, "could not allocate crypto md5\n");
                rc = PTR_ERR(server->secmech.md5);
                goto crypto_allocate_md5_fail;
diff --git a/fs/cifs/cifsencrypt.h b/fs/cifs/cifsencrypt.h
deleted file mode 100644 (file)
index 15d2ec0..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- *   fs/cifs/cifsencrypt.h
- *
- *   Copyright (c) International Business Machines  Corp., 2005
- *   Author(s): Steve French (sfrench@us.ibm.com)
- *
- *   Externs for misc. small encryption routines
- *   so we do not have to put them in cifsproto.h
- *
- *   This library is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU Lesser General Public License as published
- *   by the Free Software Foundation; either version 2.1 of the License, or
- *   (at your option) any later version.
- *
- *   This library 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 Lesser General Public License for more details.
- *
- *   You should have received a copy of the GNU Lesser General Public License
- *   along with this library; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/* md4.c */
-extern void mdfour(unsigned char *out, unsigned char *in, int n);
-/* smbdes.c */
-extern void E_P16(unsigned char *p14, unsigned char *p16);
-extern void E_P24(unsigned char *p21, const unsigned char *c8,
-                 unsigned char *p24);
-
-
-
index a8323f1..f297013 100644 (file)
@@ -600,10 +600,17 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
 {
        struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode;
        ssize_t written;
+       int rc;
 
        written = generic_file_aio_write(iocb, iov, nr_segs, pos);
-       if (!CIFS_I(inode)->clientCanCacheAll)
-               filemap_fdatawrite(inode->i_mapping);
+
+       if (CIFS_I(inode)->clientCanCacheAll)
+               return written;
+
+       rc = filemap_fdatawrite(inode->i_mapping);
+       if (rc)
+               cFYI(1, "cifs_file_aio_write: %d rc on %p inode", rc, inode);
+
        return written;
 }
 
@@ -737,7 +744,7 @@ const struct file_operations cifs_file_strict_ops = {
        .read = do_sync_read,
        .write = do_sync_write,
        .aio_read = cifs_strict_readv,
-       .aio_write = cifs_file_aio_write,
+       .aio_write = cifs_strict_writev,
        .open = cifs_open,
        .release = cifs_close,
        .lock = cifs_lock,
@@ -793,7 +800,7 @@ const struct file_operations cifs_file_strict_nobrl_ops = {
        .read = do_sync_read,
        .write = do_sync_write,
        .aio_read = cifs_strict_readv,
-       .aio_write = cifs_file_aio_write,
+       .aio_write = cifs_strict_writev,
        .open = cifs_open,
        .release = cifs_close,
        .fsync = cifs_strict_fsync,
index f23206d..a9371b6 100644 (file)
@@ -85,7 +85,9 @@ extern ssize_t cifs_user_read(struct file *file, char __user *read_data,
 extern ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
                                 unsigned long nr_segs, loff_t pos);
 extern ssize_t cifs_user_write(struct file *file, const char __user *write_data,
-                        size_t write_size, loff_t *poffset);
+                              size_t write_size, loff_t *poffset);
+extern ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
+                                 unsigned long nr_segs, loff_t pos);
 extern int cifs_lock(struct file *, int, struct file_lock *);
 extern int cifs_fsync(struct file *, int);
 extern int cifs_strict_fsync(struct file *, int);
@@ -125,5 +127,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
 extern const struct export_operations cifs_export_ops;
 #endif /* EXPERIMENTAL */
 
-#define CIFS_VERSION   "1.69"
+#define CIFS_VERSION   "1.71"
 #endif                         /* _CIFSFS_H */
index edd5b29..17afb0f 100644 (file)
@@ -188,6 +188,8 @@ struct TCP_Server_Info {
        /* multiplexed reads or writes */
        unsigned int maxBuf;    /* maxBuf specifies the maximum */
        /* message size the server can send or receive for non-raw SMBs */
+       /* maxBuf is returned by SMB NegotiateProtocol so maxBuf is only 0 */
+       /* when socket is setup (and during reconnect) before NegProt sent */
        unsigned int max_rw;    /* maxRw specifies the maximum */
        /* message size the server can send or receive for */
        /* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */
@@ -652,7 +654,7 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
 #define   MID_REQUEST_SUBMITTED 2
 #define   MID_RESPONSE_RECEIVED 4
 #define   MID_RETRY_NEEDED      8 /* session closed while this request out */
-#define   MID_NO_RESP_NEEDED 0x10
+#define   MID_RESPONSE_MALFORMED 0x10
 
 /* Types of response buffer returned from SendReceive2 */
 #define   CIFS_NO_BUFFER        0    /* Response buffer not returned */
index 982895f..8096f27 100644 (file)
@@ -85,6 +85,8 @@ extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
 extern bool is_valid_oplock_break(struct smb_hdr *smb,
                                  struct TCP_Server_Info *);
 extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
+extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
+                           unsigned int bytes_written);
 extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool);
 extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
 extern unsigned int smbCalcSize(struct smb_hdr *ptr);
@@ -373,7 +375,7 @@ extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
 extern int cifs_verify_signature(struct smb_hdr *,
                                 struct TCP_Server_Info *server,
                                __u32 expected_sequence_number);
-extern void SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *);
+extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *);
 extern int setup_ntlm_response(struct cifsSesInfo *);
 extern int setup_ntlmv2_rsp(struct cifsSesInfo *, const struct nls_table *);
 extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *);
@@ -423,4 +425,11 @@ extern bool CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr);
 extern int CIFSCheckMFSymlink(struct cifs_fattr *fattr,
                const unsigned char *path,
                struct cifs_sb_info *cifs_sb, int xid);
+extern int mdfour(unsigned char *, unsigned char *, int);
+extern int E_md4hash(const unsigned char *passwd, unsigned char *p16);
+extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8,
+                       unsigned char *p24);
+extern void E_P16(unsigned char *p14, unsigned char *p16);
+extern void E_P24(unsigned char *p21, const unsigned char *c8,
+                       unsigned char *p24);
 #endif                 /* _CIFSPROTO_H */
index 3106f5e..904aa47 100644 (file)
@@ -136,9 +136,6 @@ cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
                }
        }
 
-       if (ses->status == CifsExiting)
-               return -EIO;
-
        /*
         * Give demultiplex thread up to 10 seconds to reconnect, should be
         * greater than cifs socket timeout which is 7 seconds
@@ -156,7 +153,7 @@ cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
                 * retrying until process is killed or server comes
                 * back on-line
                 */
-               if (!tcon->retry || ses->status == CifsExiting) {
+               if (!tcon->retry) {
                        cFYI(1, "gave up waiting on reconnect in smb_init");
                        return -EHOSTDOWN;
                }
@@ -4914,7 +4911,6 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
                   __u16 fid, __u32 pid_of_opener, bool SetAllocation)
 {
        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
-       char *data_offset;
        struct file_end_of_file_info *parm_data;
        int rc = 0;
        __u16 params, param_offset, offset, byte_count, count;
@@ -4938,8 +4934,6 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
        param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
        offset = param_offset + params;
 
-       data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
-
        count = sizeof(struct file_end_of_file_info);
        pSMB->MaxParameterCount = cpu_to_le16(2);
        /* BB find exact max SMB PDU from sess structure BB */
index 0cc3b81..8d6c17a 100644 (file)
@@ -55,9 +55,6 @@
 /* SMB echo "timeout" -- FIXME: tunable? */
 #define SMB_ECHO_INTERVAL (60 * HZ)
 
-extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
-                        unsigned char *p24);
-
 extern mempool_t *cifs_req_poolp;
 
 struct smb_vol {
@@ -87,6 +84,7 @@ struct smb_vol {
        bool no_xattr:1;   /* set if xattr (EA) support should be disabled*/
        bool server_ino:1; /* use inode numbers from server ie UniqueId */
        bool direct_io:1;
+       bool strict_io:1; /* strict cache behavior */
        bool remap:1;      /* set to remap seven reserved chars in filenames */
        bool posix_paths:1; /* unset to not ask for posix pathnames. */
        bool no_linux_ext:1;
@@ -339,8 +337,13 @@ cifs_echo_request(struct work_struct *work)
        struct TCP_Server_Info *server = container_of(work,
                                        struct TCP_Server_Info, echo.work);
 
-       /* no need to ping if we got a response recently */
-       if (time_before(jiffies, server->lstrp + SMB_ECHO_INTERVAL - HZ))
+       /*
+        * We cannot send an echo until the NEGOTIATE_PROTOCOL request is
+        * done, which is indicated by maxBuf != 0. Also, no need to ping if
+        * we got a response recently
+        */
+       if (server->maxBuf == 0 ||
+           time_before(jiffies, server->lstrp + SMB_ECHO_INTERVAL - HZ))
                goto requeue_echo;
 
        rc = CIFSSMBEcho(server);
@@ -580,14 +583,23 @@ incomplete_rcv:
                else if (reconnect == 1)
                        continue;
 
-               length += 4; /* account for rfc1002 hdr */
+               total_read += 4; /* account for rfc1002 hdr */
 
+               dump_smb(smb_buffer, total_read);
 
-               dump_smb(smb_buffer, length);
-               if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
-                       cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
-                       continue;
-               }
+               /*
+                * We know that we received enough to get to the MID as we
+                * checked the pdu_length earlier. Now check to see
+                * if the rest of the header is OK. We borrow the length
+                * var for the rest of the loop to avoid a new stack var.
+                *
+                * 48 bytes is enough to display the header and a little bit
+                * into the payload for debugging purposes.
+                */
+               length = checkSMB(smb_buffer, smb_buffer->Mid, total_read);
+               if (length != 0)
+                       cifs_dump_mem("Bad SMB: ", smb_buffer,
+                                       min_t(unsigned int, total_read, 48));
 
                mid_entry = NULL;
                server->lstrp = jiffies;
@@ -599,7 +611,8 @@ incomplete_rcv:
                        if ((mid_entry->mid == smb_buffer->Mid) &&
                            (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
                            (mid_entry->command == smb_buffer->Command)) {
-                               if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
+                               if (length == 0 &&
+                                  check2ndT2(smb_buffer, server->maxBuf) > 0) {
                                        /* We have a multipart transact2 resp */
                                        isMultiRsp = true;
                                        if (mid_entry->resp_buf) {
@@ -634,12 +647,17 @@ incomplete_rcv:
                                mid_entry->resp_buf = smb_buffer;
                                mid_entry->largeBuf = isLargeBuf;
 multi_t2_fnd:
-                               mid_entry->midState = MID_RESPONSE_RECEIVED;
-                               list_del_init(&mid_entry->qhead);
-                               mid_entry->callback(mid_entry);
+                               if (length == 0)
+                                       mid_entry->midState =
+                                                       MID_RESPONSE_RECEIVED;
+                               else
+                                       mid_entry->midState =
+                                                       MID_RESPONSE_MALFORMED;
 #ifdef CONFIG_CIFS_STATS2
                                mid_entry->when_received = jiffies;
 #endif
+                               list_del_init(&mid_entry->qhead);
+                               mid_entry->callback(mid_entry);
                                break;
                        }
                        mid_entry = NULL;
@@ -655,6 +673,9 @@ multi_t2_fnd:
                                else
                                        smallbuf = NULL;
                        }
+               } else if (length != 0) {
+                       /* response sanity checks failed */
+                       continue;
                } else if (!is_valid_oplock_break(smb_buffer, server) &&
                           !isMultiRsp) {
                        cERROR(1, "No task to wake, unknown frame received! "
@@ -1344,6 +1365,8 @@ cifs_parse_mount_options(char *options, const char *devname,
                        vol->direct_io = 1;
                } else if (strnicmp(data, "forcedirectio", 13) == 0) {
                        vol->direct_io = 1;
+               } else if (strnicmp(data, "strictcache", 11) == 0) {
+                       vol->strict_io = 1;
                } else if (strnicmp(data, "noac", 4) == 0) {
                        printk(KERN_WARNING "CIFS: Mount option noac not "
                                "supported. Instead set "
@@ -2584,6 +2607,8 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
        if (pvolume_info->multiuser)
                cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_MULTIUSER |
                                            CIFS_MOUNT_NO_PERM);
+       if (pvolume_info->strict_io)
+               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_STRICT_IO;
        if (pvolume_info->direct_io) {
                cFYI(1, "mounting share using direct i/o");
                cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
@@ -2985,7 +3010,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                                         bcc_ptr);
                else
 #endif /* CIFS_WEAK_PW_HASH */
-               SMBNTencrypt(tcon->password, ses->server->cryptkey, bcc_ptr);
+               rc = SMBNTencrypt(tcon->password, ses->server->cryptkey,
+                                       bcc_ptr);
 
                bcc_ptr += CIFS_AUTH_RESP_SIZE;
                if (ses->capabilities & CAP_UNICODE) {
index d7d65a7..e964b1c 100644 (file)
@@ -346,7 +346,6 @@ int cifs_open(struct inode *inode, struct file *file)
        struct cifsTconInfo *tcon;
        struct tcon_link *tlink;
        struct cifsFileInfo *pCifsFile = NULL;
-       struct cifsInodeInfo *pCifsInode;
        char *full_path = NULL;
        bool posix_open_ok = false;
        __u16 netfid;
@@ -361,8 +360,6 @@ int cifs_open(struct inode *inode, struct file *file)
        }
        tcon = tlink_tcon(tlink);
 
-       pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
-
        full_path = build_path_from_dentry(file->f_path.dentry);
        if (full_path == NULL) {
                rc = -ENOMEM;
@@ -848,7 +845,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
 }
 
 /* update the file size (if needed) after a write */
-static void
+void
 cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
                      unsigned int bytes_written)
 {
@@ -1146,7 +1143,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
        char *write_data;
        int rc = -EFAULT;
        int bytes_written = 0;
-       struct cifs_sb_info *cifs_sb;
        struct inode *inode;
        struct cifsFileInfo *open_file;
 
@@ -1154,7 +1150,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
                return -EFAULT;
 
        inode = page->mapping->host;
-       cifs_sb = CIFS_SB(inode->i_sb);
 
        offset += (loff_t)from;
        write_data = kmap(page);
@@ -1619,13 +1614,215 @@ int cifs_flush(struct file *file, fl_owner_t id)
        return rc;
 }
 
+static int
+cifs_write_allocate_pages(struct page **pages, unsigned long num_pages)
+{
+       int rc = 0;
+       unsigned long i;
+
+       for (i = 0; i < num_pages; i++) {
+               pages[i] = alloc_page(__GFP_HIGHMEM);
+               if (!pages[i]) {
+                       /*
+                        * save number of pages we have already allocated and
+                        * return with ENOMEM error
+                        */
+                       num_pages = i;
+                       rc = -ENOMEM;
+                       goto error;
+               }
+       }
+
+       return rc;
+
+error:
+       for (i = 0; i < num_pages; i++)
+               put_page(pages[i]);
+       return rc;
+}
+
+static inline
+size_t get_numpages(const size_t wsize, const size_t len, size_t *cur_len)
+{
+       size_t num_pages;
+       size_t clen;
+
+       clen = min_t(const size_t, len, wsize);
+       num_pages = clen / PAGE_CACHE_SIZE;
+       if (clen % PAGE_CACHE_SIZE)
+               num_pages++;
+
+       if (cur_len)
+               *cur_len = clen;
+
+       return num_pages;
+}
+
+static ssize_t
+cifs_iovec_write(struct file *file, const struct iovec *iov,
+                unsigned long nr_segs, loff_t *poffset)
+{
+       unsigned int written;
+       unsigned long num_pages, npages, i;
+       size_t copied, len, cur_len;
+       ssize_t total_written = 0;
+       struct kvec *to_send;
+       struct page **pages;
+       struct iov_iter it;
+       struct inode *inode;
+       struct cifsFileInfo *open_file;
+       struct cifsTconInfo *pTcon;
+       struct cifs_sb_info *cifs_sb;
+       int xid, rc;
+
+       len = iov_length(iov, nr_segs);
+       if (!len)
+               return 0;
+
+       rc = generic_write_checks(file, poffset, &len, 0);
+       if (rc)
+               return rc;
+
+       cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+       num_pages = get_numpages(cifs_sb->wsize, len, &cur_len);
+
+       pages = kmalloc(sizeof(struct pages *)*num_pages, GFP_KERNEL);
+       if (!pages)
+               return -ENOMEM;
+
+       to_send = kmalloc(sizeof(struct kvec)*(num_pages + 1), GFP_KERNEL);
+       if (!to_send) {
+               kfree(pages);
+               return -ENOMEM;
+       }
+
+       rc = cifs_write_allocate_pages(pages, num_pages);
+       if (rc) {
+               kfree(pages);
+               kfree(to_send);
+               return rc;
+       }
+
+       xid = GetXid();
+       open_file = file->private_data;
+       pTcon = tlink_tcon(open_file->tlink);
+       inode = file->f_path.dentry->d_inode;
+
+       iov_iter_init(&it, iov, nr_segs, len, 0);
+       npages = num_pages;
+
+       do {
+               size_t save_len = cur_len;
+               for (i = 0; i < npages; i++) {
+                       copied = min_t(const size_t, cur_len, PAGE_CACHE_SIZE);
+                       copied = iov_iter_copy_from_user(pages[i], &it, 0,
+                                                        copied);
+                       cur_len -= copied;
+                       iov_iter_advance(&it, copied);
+                       to_send[i+1].iov_base = kmap(pages[i]);
+                       to_send[i+1].iov_len = copied;
+               }
+
+               cur_len = save_len - cur_len;
+
+               do {
+                       if (open_file->invalidHandle) {
+                               rc = cifs_reopen_file(open_file, false);
+                               if (rc != 0)
+                                       break;
+                       }
+                       rc = CIFSSMBWrite2(xid, pTcon, open_file->netfid,
+                                          cur_len, *poffset, &written,
+                                          to_send, npages, 0);
+               } while (rc == -EAGAIN);
+
+               for (i = 0; i < npages; i++)
+                       kunmap(pages[i]);
+
+               if (written) {
+                       len -= written;
+                       total_written += written;
+                       cifs_update_eof(CIFS_I(inode), *poffset, written);
+                       *poffset += written;
+               } else if (rc < 0) {
+                       if (!total_written)
+                               total_written = rc;
+                       break;
+               }
+
+               /* get length and number of kvecs of the next write */
+               npages = get_numpages(cifs_sb->wsize, len, &cur_len);
+       } while (len > 0);
+
+       if (total_written > 0) {
+               spin_lock(&inode->i_lock);
+               if (*poffset > inode->i_size)
+                       i_size_write(inode, *poffset);
+               spin_unlock(&inode->i_lock);
+       }
+
+       cifs_stats_bytes_written(pTcon, total_written);
+       mark_inode_dirty_sync(inode);
+
+       for (i = 0; i < num_pages; i++)
+               put_page(pages[i]);
+       kfree(to_send);
+       kfree(pages);
+       FreeXid(xid);
+       return total_written;
+}
+
+static ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov,
+                               unsigned long nr_segs, loff_t pos)
+{
+       ssize_t written;
+       struct inode *inode;
+
+       inode = iocb->ki_filp->f_path.dentry->d_inode;
+
+       /*
+        * BB - optimize the way when signing is disabled. We can drop this
+        * extra memory-to-memory copying and use iovec buffers for constructing
+        * write request.
+        */
+
+       written = cifs_iovec_write(iocb->ki_filp, iov, nr_segs, &pos);
+       if (written > 0) {
+               CIFS_I(inode)->invalid_mapping = true;
+               iocb->ki_pos = pos;
+       }
+
+       return written;
+}
+
+ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
+                          unsigned long nr_segs, loff_t pos)
+{
+       struct inode *inode;
+
+       inode = iocb->ki_filp->f_path.dentry->d_inode;
+
+       if (CIFS_I(inode)->clientCanCacheAll)
+               return generic_file_aio_write(iocb, iov, nr_segs, pos);
+
+       /*
+        * In strict cache mode we need to write the data to the server exactly
+        * from the pos to pos+len-1 rather than flush all affected pages
+        * because it may cause a error with mandatory locks on these pages but
+        * not on the region from pos to ppos+len-1.
+        */
+
+       return cifs_user_writev(iocb, iov, nr_segs, pos);
+}
+
 static ssize_t
 cifs_iovec_read(struct file *file, const struct iovec *iov,
                 unsigned long nr_segs, loff_t *poffset)
 {
        int rc;
        int xid;
-       unsigned int total_read, bytes_read = 0;
+       ssize_t total_read;
+       unsigned int bytes_read = 0;
        size_t len, cur_len;
        int iov_offset = 0;
        struct cifs_sb_info *cifs_sb;
index 306769d..e8804d3 100644 (file)
@@ -28,7 +28,6 @@
 #include "cifsproto.h"
 #include "cifs_debug.h"
 #include "cifs_fs_sb.h"
-#include "md5.h"
 
 #define CIFS_MF_SYMLINK_LEN_OFFSET (4+1)
 #define CIFS_MF_SYMLINK_MD5_OFFSET (CIFS_MF_SYMLINK_LEN_OFFSET+(4+1))
        md5_hash[8],  md5_hash[9],  md5_hash[10], md5_hash[11],\
        md5_hash[12], md5_hash[13], md5_hash[14], md5_hash[15]
 
+static int
+symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
+{
+       int rc;
+       unsigned int size;
+       struct crypto_shash *md5;
+       struct sdesc *sdescmd5;
+
+       md5 = crypto_alloc_shash("md5", 0, 0);
+       if (IS_ERR(md5)) {
+               rc = PTR_ERR(md5);
+               cERROR(1, "%s: Crypto md5 allocation error %d\n", __func__, rc);
+               return rc;
+       }
+       size = sizeof(struct shash_desc) + crypto_shash_descsize(md5);
+       sdescmd5 = kmalloc(size, GFP_KERNEL);
+       if (!sdescmd5) {
+               rc = -ENOMEM;
+               cERROR(1, "%s: Memory allocation failure\n", __func__);
+               goto symlink_hash_err;
+       }
+       sdescmd5->shash.tfm = md5;
+       sdescmd5->shash.flags = 0x0;
+
+       rc = crypto_shash_init(&sdescmd5->shash);
+       if (rc) {
+               cERROR(1, "%s: Could not init md5 shash\n", __func__);
+               goto symlink_hash_err;
+       }
+       crypto_shash_update(&sdescmd5->shash, link_str, link_len);
+       rc = crypto_shash_final(&sdescmd5->shash, md5_hash);
+
+symlink_hash_err:
+       crypto_free_shash(md5);
+       kfree(sdescmd5);
+
+       return rc;
+}
+
 static int
 CIFSParseMFSymlink(const u8 *buf,
                   unsigned int buf_len,
@@ -56,7 +94,6 @@ CIFSParseMFSymlink(const u8 *buf,
        unsigned int link_len;
        const char *md5_str1;
        const char *link_str;
-       struct MD5Context md5_ctx;
        u8 md5_hash[16];
        char md5_str2[34];
 
@@ -70,9 +107,11 @@ CIFSParseMFSymlink(const u8 *buf,
        if (rc != 1)
                return -EINVAL;
 
-       cifs_MD5_init(&md5_ctx);
-       cifs_MD5_update(&md5_ctx, (const u8 *)link_str, link_len);
-       cifs_MD5_final(md5_hash, &md5_ctx);
+       rc = symlink_hash(link_len, link_str, md5_hash);
+       if (rc) {
+               cFYI(1, "%s: MD5 hash failure: %d\n", __func__, rc);
+               return rc;
+       }
 
        snprintf(md5_str2, sizeof(md5_str2),
                 CIFS_MF_SYMLINK_MD5_FORMAT,
@@ -94,9 +133,9 @@ CIFSParseMFSymlink(const u8 *buf,
 static int
 CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str)
 {
+       int rc;
        unsigned int link_len;
        unsigned int ofs;
-       struct MD5Context md5_ctx;
        u8 md5_hash[16];
 
        if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE)
@@ -107,9 +146,11 @@ CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str)
        if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN)
                return -ENAMETOOLONG;
 
-       cifs_MD5_init(&md5_ctx);
-       cifs_MD5_update(&md5_ctx, (const u8 *)link_str, link_len);
-       cifs_MD5_final(md5_hash, &md5_ctx);
+       rc = symlink_hash(link_len, link_str, md5_hash);
+       if (rc) {
+               cFYI(1, "%s: MD5 hash failure: %d\n", __func__, rc);
+               return rc;
+       }
 
        snprintf(buf, buf_len,
                 CIFS_MF_SYMLINK_LEN_FORMAT CIFS_MF_SYMLINK_MD5_FORMAT,
diff --git a/fs/cifs/md4.c b/fs/cifs/md4.c
deleted file mode 100644 (file)
index a725c26..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
-   Unix SMB/Netbios implementation.
-   Version 1.9.
-   a implementation of MD4 designed for use in the SMB authentication protocol
-   Copyright (C) Andrew Tridgell 1997-1998.
-   Modified by Steve French (sfrench@us.ibm.com) 2002-2003
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-#include <linux/module.h>
-#include <linux/fs.h>
-#include "cifsencrypt.h"
-
-/* NOTE: This code makes no attempt to be fast! */
-
-static __u32
-F(__u32 X, __u32 Y, __u32 Z)
-{
-       return (X & Y) | ((~X) & Z);
-}
-
-static __u32
-G(__u32 X, __u32 Y, __u32 Z)
-{
-       return (X & Y) | (X & Z) | (Y & Z);
-}
-
-static __u32
-H(__u32 X, __u32 Y, __u32 Z)
-{
-       return X ^ Y ^ Z;
-}
-
-static __u32
-lshift(__u32 x, int s)
-{
-       x &= 0xFFFFFFFF;
-       return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
-}
-
-#define ROUND1(a,b,c,d,k,s) (*a) = lshift((*a) + F(*b,*c,*d) + X[k], s)
-#define ROUND2(a,b,c,d,k,s) (*a) = lshift((*a) + G(*b,*c,*d) + X[k] + (__u32)0x5A827999,s)
-#define ROUND3(a,b,c,d,k,s) (*a) = lshift((*a) + H(*b,*c,*d) + X[k] + (__u32)0x6ED9EBA1,s)
-
-/* this applies md4 to 64 byte chunks */
-static void
-mdfour64(__u32 *M, __u32 *A, __u32 *B, __u32 *C, __u32 *D)
-{
-       int j;
-       __u32 AA, BB, CC, DD;
-       __u32 X[16];
-
-
-       for (j = 0; j < 16; j++)
-               X[j] = M[j];
-
-       AA = *A;
-       BB = *B;
-       CC = *C;
-       DD = *D;
-
-       ROUND1(A, B, C, D, 0, 3);
-       ROUND1(D, A, B, C, 1, 7);
-       ROUND1(C, D, A, B, 2, 11);
-       ROUND1(B, C, D, A, 3, 19);
-       ROUND1(A, B, C, D, 4, 3);
-       ROUND1(D, A, B, C, 5, 7);
-       ROUND1(C, D, A, B, 6, 11);
-       ROUND1(B, C, D, A, 7, 19);
-       ROUND1(A, B, C, D, 8, 3);
-       ROUND1(D, A, B, C, 9, 7);
-       ROUND1(C, D, A, B, 10, 11);
-       ROUND1(B, C, D, A, 11, 19);
-       ROUND1(A, B, C, D, 12, 3);
-       ROUND1(D, A, B, C, 13, 7);
-       ROUND1(C, D, A, B, 14, 11);
-       ROUND1(B, C, D, A, 15, 19);
-
-       ROUND2(A, B, C, D, 0, 3);
-       ROUND2(D, A, B, C, 4, 5);
-       ROUND2(C, D, A, B, 8, 9);
-       ROUND2(B, C, D, A, 12, 13);
-       ROUND2(A, B, C, D, 1, 3);
-       ROUND2(D, A, B, C, 5, 5);
-       ROUND2(C, D, A, B, 9, 9);
-       ROUND2(B, C, D, A, 13, 13);
-       ROUND2(A, B, C, D, 2, 3);
-       ROUND2(D, A, B, C, 6, 5);
-       ROUND2(C, D, A, B, 10, 9);
-       ROUND2(B, C, D, A, 14, 13);
-       ROUND2(A, B, C, D, 3, 3);
-       ROUND2(D, A, B, C, 7, 5);
-       ROUND2(C, D, A, B, 11, 9);
-       ROUND2(B, C, D, A, 15, 13);
-
-       ROUND3(A, B, C, D, 0, 3);
-       ROUND3(D, A, B, C, 8, 9);
-       ROUND3(C, D, A, B, 4, 11);
-       ROUND3(B, C, D, A, 12, 15);
-       ROUND3(A, B, C, D, 2, 3);
-       ROUND3(D, A, B, C, 10, 9);
-       ROUND3(C, D, A, B, 6, 11);
-       ROUND3(B, C, D, A, 14, 15);
-       ROUND3(A, B, C, D, 1, 3);
-       ROUND3(D, A, B, C, 9, 9);
-       ROUND3(C, D, A, B, 5, 11);
-       ROUND3(B, C, D, A, 13, 15);
-       ROUND3(A, B, C, D, 3, 3);
-       ROUND3(D, A, B, C, 11, 9);
-       ROUND3(C, D, A, B, 7, 11);
-       ROUND3(B, C, D, A, 15, 15);
-
-       *A += AA;
-       *B += BB;
-       *C += CC;
-       *D += DD;
-
-       *A &= 0xFFFFFFFF;
-       *B &= 0xFFFFFFFF;
-       *C &= 0xFFFFFFFF;
-       *D &= 0xFFFFFFFF;
-
-       for (j = 0; j < 16; j++)
-               X[j] = 0;
-}
-
-static void
-copy64(__u32 *M, unsigned char *in)
-{
-       int i;
-
-       for (i = 0; i < 16; i++)
-               M[i] = (in[i * 4 + 3] << 24) | (in[i * 4 + 2] << 16) |
-                   (in[i * 4 + 1] << 8) | (in[i * 4 + 0] << 0);
-}
-
-static void
-copy4(unsigned char *out, __u32 x)
-{
-       out[0] = x & 0xFF;
-       out[1] = (x >> 8) & 0xFF;
-       out[2] = (x >> 16) & 0xFF;
-       out[3] = (x >> 24) & 0xFF;
-}
-
-/* produce a md4 message digest from data of length n bytes */
-void
-mdfour(unsigned char *out, unsigned char *in, int n)
-{
-       unsigned char buf[128];
-       __u32 M[16];
-       __u32 b = n * 8;
-       int i;
-       __u32 A = 0x67452301;
-       __u32 B = 0xefcdab89;
-       __u32 C = 0x98badcfe;
-       __u32 D = 0x10325476;
-
-       while (n > 64) {
-               copy64(M, in);
-               mdfour64(M, &A, &B, &C, &D);
-               in += 64;
-               n -= 64;
-       }
-
-       for (i = 0; i < 128; i++)
-               buf[i] = 0;
-       memcpy(buf, in, n);
-       buf[n] = 0x80;
-
-       if (n <= 55) {
-               copy4(buf + 56, b);
-               copy64(M, buf);
-               mdfour64(M, &A, &B, &C, &D);
-       } else {
-               copy4(buf + 120, b);
-               copy64(M, buf);
-               mdfour64(M, &A, &B, &C, &D);
-               copy64(M, buf + 64);
-               mdfour64(M, &A, &B, &C, &D);
-       }
-
-       for (i = 0; i < 128; i++)
-               buf[i] = 0;
-       copy64(M, buf);
-
-       copy4(out, A);
-       copy4(out + 4, B);
-       copy4(out + 8, C);
-       copy4(out + 12, D);
-
-       A = B = C = D = 0;
-}
diff --git a/fs/cifs/md5.c b/fs/cifs/md5.c
deleted file mode 100644 (file)
index 98b66a5..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * This code implements the MD5 message-digest algorithm.
- * The algorithm is due to Ron Rivest.  This code was
- * written by Colin Plumb in 1993, no copyright is claimed.
- * This code is in the public domain; do with it what you wish.
- *
- * Equivalent code is available from RSA Data Security, Inc.
- * This code has been tested against that, and is equivalent,
- * except that you don't need to include two pages of legalese
- * with every copy.
- *
- * To compute the message digest of a chunk of bytes, declare an
- * MD5Context structure, pass it to cifs_MD5_init, call cifs_MD5_update as
- * needed on buffers full of bytes, and then call cifs_MD5_final, which
- * will fill a supplied 16-byte array with the digest.
- */
-
-/* This code slightly modified to fit into Samba by
-   abartlet@samba.org Jun 2001
-   and to fit the cifs vfs by
-   Steve French sfrench@us.ibm.com */
-
-#include <linux/string.h>
-#include "md5.h"
-
-static void MD5Transform(__u32 buf[4], __u32 const in[16]);
-
-/*
- * Note: this code is harmless on little-endian machines.
- */
-static void
-byteReverse(unsigned char *buf, unsigned longs)
-{
-       __u32 t;
-       do {
-               t = (__u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
-                   ((unsigned) buf[1] << 8 | buf[0]);
-               *(__u32 *) buf = t;
-               buf += 4;
-       } while (--longs);
-}
-
-/*
- * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
- * initialization constants.
- */
-void
-cifs_MD5_init(struct MD5Context *ctx)
-{
-       ctx->buf[0] = 0x67452301;
-       ctx->buf[1] = 0xefcdab89;
-       ctx->buf[2] = 0x98badcfe;
-       ctx->buf[3] = 0x10325476;
-
-       ctx->bits[0] = 0;
-       ctx->bits[1] = 0;
-}
-
-/*
- * Update context to reflect the concatenation of another buffer full
- * of bytes.
- */
-void
-cifs_MD5_update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
-{
-       register __u32 t;
-
-       /* Update bitcount */
-
-       t = ctx->bits[0];
-       if ((ctx->bits[0] = t + ((__u32) len << 3)) < t)
-               ctx->bits[1]++; /* Carry from low to high */
-       ctx->bits[1] += len >> 29;
-
-       t = (t >> 3) & 0x3f;    /* Bytes already in shsInfo->data */
-
-       /* Handle any leading odd-sized chunks */
-
-       if (t) {
-               unsigned char *p = (unsigned char *) ctx->in + t;
-
-               t = 64 - t;
-               if (len < t) {
-                       memmove(p, buf, len);
-                       return;
-               }
-               memmove(p, buf, t);
-               byteReverse(ctx->in, 16);
-               MD5Transform(ctx->buf, (__u32 *) ctx->in);
-               buf += t;
-               len -= t;
-       }
-       /* Process data in 64-byte chunks */
-
-       while (len >= 64) {
-               memmove(ctx->in, buf, 64);
-               byteReverse(ctx->in, 16);
-               MD5Transform(ctx->buf, (__u32 *) ctx->in);
-               buf += 64;
-               len -= 64;
-       }
-
-       /* Handle any remaining bytes of data. */
-
-       memmove(ctx->in, buf, len);
-}
-
-/*
- * Final wrapup - pad to 64-byte boundary with the bit pattern
- * 1 0* (64-bit count of bits processed, MSB-first)
- */
-void
-cifs_MD5_final(unsigned char digest[16], struct MD5Context *ctx)
-{
-       unsigned int count;
-       unsigned char *p;
-
-       /* Compute number of bytes mod 64 */
-       count = (ctx->bits[0] >> 3) & 0x3F;
-
-       /* Set the first char of padding to 0x80.  This is safe since there is
-          always at least one byte free */
-       p = ctx->in + count;
-       *p++ = 0x80;
-
-       /* Bytes of padding needed to make 64 bytes */
-       count = 64 - 1 - count;
-
-       /* Pad out to 56 mod 64 */
-       if (count < 8) {
-               /* Two lots of padding:  Pad the first block to 64 bytes */
-               memset(p, 0, count);
-               byteReverse(ctx->in, 16);
-               MD5Transform(ctx->buf, (__u32 *) ctx->in);
-
-               /* Now fill the next block with 56 bytes */
-               memset(ctx->in, 0, 56);
-       } else {
-               /* Pad block to 56 bytes */
-               memset(p, 0, count - 8);
-       }
-       byteReverse(ctx->in, 14);
-
-       /* Append length in bits and transform */
-       ((__u32 *) ctx->in)[14] = ctx->bits[0];
-       ((__u32 *) ctx->in)[15] = ctx->bits[1];
-
-       MD5Transform(ctx->buf, (__u32 *) ctx->in);
-       byteReverse((unsigned char *) ctx->buf, 4);
-       memmove(digest, ctx->buf, 16);
-       memset(ctx, 0, sizeof(*ctx));   /* In case it's sensitive */
-}
-
-/* The four core functions - F1 is optimized somewhat */
-
-/* #define F1(x, y, z) (x & y | ~x & z) */
-#define F1(x, y, z) (z ^ (x & (y ^ z)))
-#define F2(x, y, z) F1(z, x, y)
-#define F3(x, y, z) (x ^ y ^ z)
-#define F4(x, y, z) (y ^ (x | ~z))
-
-/* This is the central step in the MD5 algorithm. */
-#define MD5STEP(f, w, x, y, z, data, s) \
-       (w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x)
-
-/*
- * The core of the MD5 algorithm, this alters an existing MD5 hash to
- * reflect the addition of 16 longwords of new data.  cifs_MD5_update blocks
- * the data and converts bytes into longwords for this routine.
- */
-static void
-MD5Transform(__u32 buf[4], __u32 const in[16])
-{
-       register __u32 a, b, c, d;
-
-       a = buf[0];
-       b = buf[1];
-       c = buf[2];
-       d = buf[3];
-
-       MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
-       MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
-       MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
-       MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
-       MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
-       MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
-       MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
-       MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
-       MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
-       MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
-       MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
-       MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
-       MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
-       MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
-       MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
-       MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
-
-       MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
-       MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
-       MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
-       MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
-       MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
-       MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
-       MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
-       MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
-       MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
-       MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
-       MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
-       MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
-       MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
-       MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
-       MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
-       MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
-
-       MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
-       MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
-       MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
-       MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
-       MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
-       MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
-       MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
-       MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
-       MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
-       MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
-       MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
-       MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
-       MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
-       MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
-       MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
-       MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
-
-       MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
-       MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
-       MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
-       MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
-       MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
-       MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
-       MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
-       MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
-       MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
-       MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
-       MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
-       MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
-       MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
-       MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
-       MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
-       MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
-
-       buf[0] += a;
-       buf[1] += b;
-       buf[2] += c;
-       buf[3] += d;
-}
-
-#if 0   /* currently unused */
-/***********************************************************************
- the rfc 2104 version of hmac_md5 initialisation.
-***********************************************************************/
-static void
-hmac_md5_init_rfc2104(unsigned char *key, int key_len,
-                     struct HMACMD5Context *ctx)
-{
-       int i;
-
-       /* if key is longer than 64 bytes reset it to key=MD5(key) */
-       if (key_len > 64) {
-               unsigned char tk[16];
-               struct MD5Context tctx;
-
-               cifs_MD5_init(&tctx);
-               cifs_MD5_update(&tctx, key, key_len);
-               cifs_MD5_final(tk, &tctx);
-
-               key = tk;
-               key_len = 16;
-       }
-
-       /* start out by storing key in pads */
-       memset(ctx->k_ipad, 0, sizeof(ctx->k_ipad));
-       memset(ctx->k_opad, 0, sizeof(ctx->k_opad));
-       memcpy(ctx->k_ipad, key, key_len);
-       memcpy(ctx->k_opad, key, key_len);
-
-       /* XOR key with ipad and opad values */
-       for (i = 0; i < 64; i++) {
-               ctx->k_ipad[i] ^= 0x36;
-               ctx->k_opad[i] ^= 0x5c;
-       }
-
-       cifs_MD5_init(&ctx->ctx);
-       cifs_MD5_update(&ctx->ctx, ctx->k_ipad, 64);
-}
-#endif
-
-/***********************************************************************
- the microsoft version of hmac_md5 initialisation.
-***********************************************************************/
-void
-hmac_md5_init_limK_to_64(const unsigned char *key, int key_len,
-                        struct HMACMD5Context *ctx)
-{
-       int i;
-
-       /* if key is longer than 64 bytes truncate it */
-       if (key_len > 64)
-               key_len = 64;
-
-       /* start out by storing key in pads */
-       memset(ctx->k_ipad, 0, sizeof(ctx->k_ipad));
-       memset(ctx->k_opad, 0, sizeof(ctx->k_opad));
-       memcpy(ctx->k_ipad, key, key_len);
-       memcpy(ctx->k_opad, key, key_len);
-
-       /* XOR key with ipad and opad values */
-       for (i = 0; i < 64; i++) {
-               ctx->k_ipad[i] ^= 0x36;
-               ctx->k_opad[i] ^= 0x5c;
-       }
-
-       cifs_MD5_init(&ctx->ctx);
-       cifs_MD5_update(&ctx->ctx, ctx->k_ipad, 64);
-}
-
-/***********************************************************************
- update hmac_md5 "inner" buffer
-***********************************************************************/
-void
-hmac_md5_update(const unsigned char *text, int text_len,
-               struct HMACMD5Context *ctx)
-{
-       cifs_MD5_update(&ctx->ctx, text, text_len);     /* then text of datagram */
-}
-
-/***********************************************************************
- finish off hmac_md5 "inner" buffer and generate outer one.
-***********************************************************************/
-void
-hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx)
-{
-       struct MD5Context ctx_o;
-
-       cifs_MD5_final(digest, &ctx->ctx);
-
-       cifs_MD5_init(&ctx_o);
-       cifs_MD5_update(&ctx_o, ctx->k_opad, 64);
-       cifs_MD5_update(&ctx_o, digest, 16);
-       cifs_MD5_final(digest, &ctx_o);
-}
-
-/***********************************************************
- single function to calculate an HMAC MD5 digest from data.
- use the microsoft hmacmd5 init method because the key is 16 bytes.
-************************************************************/
-#if 0 /* currently unused */
-static void
-hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
-        unsigned char *digest)
-{
-       struct HMACMD5Context ctx;
-       hmac_md5_init_limK_to_64(key, 16, &ctx);
-       if (data_len != 0)
-               hmac_md5_update(data, data_len, &ctx);
-
-       hmac_md5_final(digest, &ctx);
-}
-#endif
diff --git a/fs/cifs/md5.h b/fs/cifs/md5.h
deleted file mode 100644 (file)
index 6fba8cb..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef MD5_H
-#define MD5_H
-#ifndef HEADER_MD5_H
-/* Try to avoid clashes with OpenSSL */
-#define HEADER_MD5_H
-#endif
-
-struct MD5Context {
-       __u32 buf[4];
-       __u32 bits[2];
-       unsigned char in[64];
-};
-#endif                         /* !MD5_H */
-
-#ifndef _HMAC_MD5_H
-struct HMACMD5Context {
-       struct MD5Context ctx;
-       unsigned char k_ipad[65];
-       unsigned char k_opad[65];
-};
-#endif                         /* _HMAC_MD5_H */
-
-void cifs_MD5_init(struct MD5Context *context);
-void cifs_MD5_update(struct MD5Context *context, unsigned char const *buf,
-                       unsigned len);
-void cifs_MD5_final(unsigned char digest[16], struct MD5Context *context);
-
-/* The following definitions come from lib/hmacmd5.c  */
-
-/* void hmac_md5_init_rfc2104(unsigned char *key, int key_len,
-                       struct HMACMD5Context *ctx);*/
-void hmac_md5_init_limK_to_64(const unsigned char *key, int key_len,
-                       struct HMACMD5Context *ctx);
-void hmac_md5_update(const unsigned char *text, int text_len,
-                       struct HMACMD5Context *ctx);
-void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx);
-/* void hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
-                       unsigned char *digest);*/
index a09e077..2a930a7 100644 (file)
@@ -236,10 +236,7 @@ __u16 GetNextMid(struct TCP_Server_Info *server)
 {
        __u16 mid = 0;
        __u16 last_mid;
-       int   collision;
-
-       if (server == NULL)
-               return mid;
+       bool collision;
 
        spin_lock(&GlobalMid_Lock);
        last_mid = server->CurrentMid; /* we do not want to loop forever */
@@ -252,24 +249,38 @@ __u16 GetNextMid(struct TCP_Server_Info *server)
        (and it would also have to have been a request that
         did not time out) */
        while (server->CurrentMid != last_mid) {
-               struct list_head *tmp;
                struct mid_q_entry *mid_entry;
+               unsigned int num_mids;
 
-               collision = 0;
+               collision = false;
                if (server->CurrentMid == 0)
                        server->CurrentMid++;
 
-               list_for_each(tmp, &server->pending_mid_q) {
-                       mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-
-                       if ((mid_entry->mid == server->CurrentMid) &&
-                           (mid_entry->midState == MID_REQUEST_SUBMITTED)) {
+               num_mids = 0;
+               list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) {
+                       ++num_mids;
+                       if (mid_entry->mid == server->CurrentMid &&
+                           mid_entry->midState == MID_REQUEST_SUBMITTED) {
                                /* This mid is in use, try a different one */
-                               collision = 1;
+                               collision = true;
                                break;
                        }
                }
-               if (collision == 0) {
+
+               /*
+                * if we have more than 32k mids in the list, then something
+                * is very wrong. Possibly a local user is trying to DoS the
+                * box by issuing long-running calls and SIGKILL'ing them. If
+                * we get to 2^16 mids then we're in big trouble as this
+                * function could loop forever.
+                *
+                * Go ahead and assign out the mid in this situation, but force
+                * an eventual reconnect to clean out the pending_mid_q.
+                */
+               if (num_mids > 32768)
+                       server->tcpStatus = CifsNeedReconnect;
+
+               if (!collision) {
                        mid = server->CurrentMid;
                        break;
                }
@@ -381,29 +392,31 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
 }
 
 static int
-checkSMBhdr(struct smb_hdr *smb, __u16 mid)
+check_smb_hdr(struct smb_hdr *smb, __u16 mid)
 {
-       /* Make sure that this really is an SMB, that it is a response,
-          and that the message ids match */
-       if ((*(__le32 *) smb->Protocol == cpu_to_le32(0x424d53ff)) &&
-               (mid == smb->Mid)) {
-               if (smb->Flags & SMBFLG_RESPONSE)
-                       return 0;
-               else {
-               /* only one valid case where server sends us request */
-                       if (smb->Command == SMB_COM_LOCKING_ANDX)
-                               return 0;
-                       else
-                               cERROR(1, "Received Request not response");
-               }
-       } else { /* bad signature or mid */
-               if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff))
-                       cERROR(1, "Bad protocol string signature header %x",
-                               *(unsigned int *) smb->Protocol);
-               if (mid != smb->Mid)
-                       cERROR(1, "Mids do not match");
+       /* does it have the right SMB "signature" ? */
+       if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) {
+               cERROR(1, "Bad protocol string signature header 0x%x",
+                       *(unsigned int *)smb->Protocol);
+               return 1;
+       }
+
+       /* Make sure that message ids match */
+       if (mid != smb->Mid) {
+               cERROR(1, "Mids do not match. received=%u expected=%u",
+                       smb->Mid, mid);
+               return 1;
        }
-       cERROR(1, "bad smb detected. The Mid=%d", smb->Mid);
+
+       /* if it's a response then accept */
+       if (smb->Flags & SMBFLG_RESPONSE)
+               return 0;
+
+       /* only one valid case where server sends us request */
+       if (smb->Command == SMB_COM_LOCKING_ANDX)
+               return 0;
+
+       cERROR(1, "Server sent request, not response. mid=%u", smb->Mid);
        return 1;
 }
 
@@ -448,7 +461,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
                return 1;
        }
 
-       if (checkSMBhdr(smb, mid))
+       if (check_smb_hdr(smb, mid))
                return 1;
        clc_len = smbCalcSize_LE(smb);
 
@@ -465,25 +478,26 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
                        if (((4 + len) & 0xFFFF) == (clc_len & 0xFFFF))
                                return 0; /* bcc wrapped */
                }
-               cFYI(1, "Calculated size %d vs length %d mismatch for mid %d",
+               cFYI(1, "Calculated size %u vs length %u mismatch for mid=%u",
                                clc_len, 4 + len, smb->Mid);
-               /* Windows XP can return a few bytes too much, presumably
-               an illegal pad, at the end of byte range lock responses
-               so we allow for that three byte pad, as long as actual
-               received length is as long or longer than calculated length */
-               /* We have now had to extend this more, since there is a
-               case in which it needs to be bigger still to handle a
-               malformed response to transact2 findfirst from WinXP when
-               access denied is returned and thus bcc and wct are zero
-               but server says length is 0x21 bytes too long as if the server
-               forget to reset the smb rfc1001 length when it reset the
-               wct and bcc to minimum size and drop the t2 parms and data */
-               if ((4+len > clc_len) && (len <= clc_len + 512))
-                       return 0;
-               else {
-                       cERROR(1, "RFC1001 size %d bigger than SMB for Mid=%d",
+
+               if (4 + len < clc_len) {
+                       cERROR(1, "RFC1001 size %u smaller than SMB for mid=%u",
                                        len, smb->Mid);
                        return 1;
+               } else if (len > clc_len + 512) {
+                       /*
+                        * Some servers (Windows XP in particular) send more
+                        * data than the lengths in the SMB packet would
+                        * indicate on certain calls (byte range locks and
+                        * trans2 find first calls in particular). While the
+                        * client can handle such a frame by ignoring the
+                        * trailing data, we choose limit the amount of extra
+                        * data to 512 bytes.
+                        */
+                       cERROR(1, "RFC1001 size %u more than 512 bytes larger "
+                                 "than SMB for mid=%u", len, smb->Mid);
+                       return 1;
                }
        }
        return 0;
index 8d9189f..79f641e 100644 (file)
@@ -170,7 +170,7 @@ cifs_convert_address(struct sockaddr *dst, const char *src, int len)
 {
        int rc, alen, slen;
        const char *pct;
-       char *endp, scope_id[13];
+       char scope_id[13];
        struct sockaddr_in *s4 = (struct sockaddr_in *) dst;
        struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst;
 
@@ -197,9 +197,9 @@ cifs_convert_address(struct sockaddr *dst, const char *src, int len)
                memcpy(scope_id, pct + 1, slen);
                scope_id[slen] = '\0';
 
-               s6->sin6_scope_id = (u32) simple_strtoul(pct, &endp, 0);
-               if (endp != scope_id + slen)
-                       return 0;
+               rc = strict_strtoul(scope_id, 0,
+                                       (unsigned long *)&s6->sin6_scope_id);
+               rc = (rc == 0) ? 1 : 0;
        }
 
        return rc;
index 7f25cc3..f8e4cd2 100644 (file)
@@ -764,7 +764,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 {
        int rc = 0;
        int xid, i;
-       struct cifs_sb_info *cifs_sb;
        struct cifsTconInfo *pTcon;
        struct cifsFileInfo *cifsFile = NULL;
        char *current_entry;
@@ -775,8 +774,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 
        xid = GetXid();
 
-       cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-
        /*
         * Ensure FindFirst doesn't fail before doing filldir() for '.' and
         * '..'. Otherwise we won't be able to notify VFS in case of failure.
index 1adc962..1676570 100644 (file)
@@ -656,13 +656,13 @@ ssetup_ntlmssp_authenticate:
 
        if (type == LANMAN) {
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
-               char lnm_session_key[CIFS_SESS_KEY_SIZE];
+               char lnm_session_key[CIFS_AUTH_RESP_SIZE];
 
                pSMB->req.hdr.Flags2 &= ~SMBFLG2_UNICODE;
 
                /* no capabilities flags in old lanman negotiation */
 
-               pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
+               pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE);
 
                /* Calculate hash with password and copy into bcc_ptr.
                 * Encryption Key (stored as in cryptkey) gets used if the
@@ -675,8 +675,8 @@ ssetup_ntlmssp_authenticate:
                                        true : false, lnm_session_key);
 
                ses->flags |= CIFS_SES_LANMAN;
-               memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE);
-               bcc_ptr += CIFS_SESS_KEY_SIZE;
+               memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_AUTH_RESP_SIZE);
+               bcc_ptr += CIFS_AUTH_RESP_SIZE;
 
                /* can not sign if LANMAN negotiated so no need
                to calculate signing key? but what if server
index b6b6dcb..0472148 100644 (file)
@@ -45,7 +45,6 @@
    up with a different answer to the one above)
 */
 #include <linux/slab.h>
-#include "cifsencrypt.h"
 #define uchar unsigned char
 
 static uchar perm1[56] = { 57, 49, 41, 33, 25, 17, 9,
index 192ea51..b5041c8 100644 (file)
@@ -32,9 +32,8 @@
 #include "cifs_unicode.h"
 #include "cifspdu.h"
 #include "cifsglob.h"
-#include "md5.h"
 #include "cifs_debug.h"
-#include "cifsencrypt.h"
+#include "cifsproto.h"
 
 #ifndef false
 #define false 0
 #define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
 #define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val)))
 
-/*The following definitions come from  libsmb/smbencrypt.c  */
+/* produce a md4 message digest from data of length n bytes */
+int
+mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len)
+{
+       int rc;
+       unsigned int size;
+       struct crypto_shash *md4;
+       struct sdesc *sdescmd4;
+
+       md4 = crypto_alloc_shash("md4", 0, 0);
+       if (IS_ERR(md4)) {
+               rc = PTR_ERR(md4);
+               cERROR(1, "%s: Crypto md4 allocation error %d\n", __func__, rc);
+               return rc;
+       }
+       size = sizeof(struct shash_desc) + crypto_shash_descsize(md4);
+       sdescmd4 = kmalloc(size, GFP_KERNEL);
+       if (!sdescmd4) {
+               rc = -ENOMEM;
+               cERROR(1, "%s: Memory allocation failure\n", __func__);
+               goto mdfour_err;
+       }
+       sdescmd4->shash.tfm = md4;
+       sdescmd4->shash.flags = 0x0;
+
+       rc = crypto_shash_init(&sdescmd4->shash);
+       if (rc) {
+               cERROR(1, "%s: Could not init md4 shash\n", __func__);
+               goto mdfour_err;
+       }
+       crypto_shash_update(&sdescmd4->shash, link_str, link_len);
+       rc = crypto_shash_final(&sdescmd4->shash, md4_hash);
 
-void SMBencrypt(unsigned char *passwd, const unsigned char *c8,
-               unsigned char *p24);
-void E_md4hash(const unsigned char *passwd, unsigned char *p16);
-static void SMBOWFencrypt(unsigned char passwd[16], const unsigned char *c8,
-                  unsigned char p24[24]);
-void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
+mdfour_err:
+       crypto_free_shash(md4);
+       kfree(sdescmd4);
+
+       return rc;
+}
+
+/* Does the des encryption from the NT or LM MD4 hash. */
+static void
+SMBOWFencrypt(unsigned char passwd[16], const unsigned char *c8,
+             unsigned char p24[24])
+{
+       unsigned char p21[21];
+
+       memset(p21, '\0', 21);
+
+       memcpy(p21, passwd, 16);
+       E_P24(p21, c8, p24);
+}
 
 /*
    This implements the X/Open SMB password encryption
@@ -118,9 +161,10 @@ _my_mbstowcs(__u16 *dst, const unsigned char *src, int len)
  * Creates the MD4 Hash of the users password in NT UNICODE.
  */
 
-void
+int
 E_md4hash(const unsigned char *passwd, unsigned char *p16)
 {
+       int rc;
        int len;
        __u16 wpwd[129];
 
@@ -139,8 +183,10 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16)
        /* Calculate length in bytes */
        len = _my_wcslen(wpwd) * sizeof(__u16);
 
-       mdfour(p16, (unsigned char *) wpwd, len);
+       rc = mdfour(p16, (unsigned char *) wpwd, len);
        memset(wpwd, 0, 129 * 2);
+
+       return rc;
 }
 
 #if 0 /* currently unused */
@@ -212,19 +258,6 @@ ntv2_owf_gen(const unsigned char owf[16], const char *user_n,
 }
 #endif
 
-/* Does the des encryption from the NT or LM MD4 hash. */
-static void
-SMBOWFencrypt(unsigned char passwd[16], const unsigned char *c8,
-             unsigned char p24[24])
-{
-       unsigned char p21[21];
-
-       memset(p21, '\0', 21);
-
-       memcpy(p21, passwd, 16);
-       E_P24(p21, c8, p24);
-}
-
 /* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */
 #if 0 /* currently unused */
 static void
@@ -242,16 +275,21 @@ NTLMSSPOWFencrypt(unsigned char passwd[8],
 #endif
 
 /* Does the NT MD4 hash then des encryption. */
-
-void
+int
 SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
 {
+       int rc;
        unsigned char p21[21];
 
        memset(p21, '\0', 21);
 
-       E_md4hash(passwd, p21);
+       rc = E_md4hash(passwd, p21);
+       if (rc) {
+               cFYI(1, "%s Can't generate NT hash, error: %d", __func__, rc);
+               return rc;
+       }
        SMBOWFencrypt(p21, c8, p24);
+       return rc;
 }
 
 
index c1ccca1..46d8756 100644 (file)
@@ -236,9 +236,9 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
                server->tcpStatus = CifsNeedReconnect;
        }
 
-       if (rc < 0) {
+       if (rc < 0 && rc != -EINTR)
                cERROR(1, "Error %d sending data on socket to server", rc);
-       else
+       else
                rc = 0;
 
        /* Don't want to modify the buffer as a
@@ -359,6 +359,10 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
        if (rc)
                return rc;
 
+       /* enable signing if server requires it */
+       if (server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+               in_buf->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
        mutex_lock(&server->srv_mutex);
        mid = AllocMidQEntry(in_buf, server);
        if (mid == NULL) {
@@ -453,6 +457,9 @@ sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
        case MID_RETRY_NEEDED:
                rc = -EAGAIN;
                break;
+       case MID_RESPONSE_MALFORMED:
+               rc = -EIO;
+               break;
        default:
                cERROR(1, "%s: invalid mid state mid=%d state=%d", __func__,
                        mid->mid, mid->midState);
@@ -570,17 +577,33 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
 #endif
 
        mutex_unlock(&ses->server->srv_mutex);
-       cifs_small_buf_release(in_buf);
 
-       if (rc < 0)
+       if (rc < 0) {
+               cifs_small_buf_release(in_buf);
                goto out;
+       }
 
-       if (long_op == CIFS_ASYNC_OP)
+       if (long_op == CIFS_ASYNC_OP) {
+               cifs_small_buf_release(in_buf);
                goto out;
+       }
 
        rc = wait_for_response(ses->server, midQ);
-       if (rc != 0)
-               goto out;
+       if (rc != 0) {
+               send_nt_cancel(ses->server, in_buf, midQ);
+               spin_lock(&GlobalMid_Lock);
+               if (midQ->midState == MID_REQUEST_SUBMITTED) {
+                       midQ->callback = DeleteMidQEntry;
+                       spin_unlock(&GlobalMid_Lock);
+                       cifs_small_buf_release(in_buf);
+                       atomic_dec(&ses->server->inFlight);
+                       wake_up(&ses->server->request_q);
+                       return rc;
+               }
+               spin_unlock(&GlobalMid_Lock);
+       }
+
+       cifs_small_buf_release(in_buf);
 
        rc = sync_mid_result(midQ, ses->server);
        if (rc != 0) {
@@ -724,8 +747,19 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
                goto out;
 
        rc = wait_for_response(ses->server, midQ);
-       if (rc != 0)
-               goto out;
+       if (rc != 0) {
+               send_nt_cancel(ses->server, in_buf, midQ);
+               spin_lock(&GlobalMid_Lock);
+               if (midQ->midState == MID_REQUEST_SUBMITTED) {
+                       /* no longer considered to be "in-flight" */
+                       midQ->callback = DeleteMidQEntry;
+                       spin_unlock(&GlobalMid_Lock);
+                       atomic_dec(&ses->server->inFlight);
+                       wake_up(&ses->server->request_q);
+                       return rc;
+               }
+               spin_unlock(&GlobalMid_Lock);
+       }
 
        rc = sync_mid_result(midQ, ses->server);
        if (rc != 0) {
@@ -922,10 +956,21 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
                        }
                }
 
-               if (wait_for_response(ses->server, midQ) == 0) {
-                       /* We got the response - restart system call. */
-                       rstart = 1;
+               rc = wait_for_response(ses->server, midQ);
+               if (rc) {
+                       send_nt_cancel(ses->server, in_buf, midQ);
+                       spin_lock(&GlobalMid_Lock);
+                       if (midQ->midState == MID_REQUEST_SUBMITTED) {
+                               /* no longer considered to be "in-flight" */
+                               midQ->callback = DeleteMidQEntry;
+                               spin_unlock(&GlobalMid_Lock);
+                               return rc;
+                       }
+                       spin_unlock(&GlobalMid_Lock);
                }
+
+               /* We got the response - restart system call. */
+               rstart = 1;
        }
 
        rc = sync_mid_result(midQ, ses->server);
index f6fd0a0..c6d31a3 100644 (file)
@@ -262,35 +262,19 @@ static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *
  */
 asmlinkage long compat_sys_statfs(const char __user *pathname, struct compat_statfs __user *buf)
 {
-       struct path path;
-       int error;
-
-       error = user_path(pathname, &path);
-       if (!error) {
-               struct kstatfs tmp;
-               error = vfs_statfs(&path, &tmp);
-               if (!error)
-                       error = put_compat_statfs(buf, &tmp);
-               path_put(&path);
-       }
+       struct kstatfs tmp;
+       int error = user_statfs(pathname, &tmp);
+       if (!error)
+               error = put_compat_statfs(buf, &tmp);
        return error;
 }
 
 asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user *buf)
 {
-       struct file * file;
        struct kstatfs tmp;
-       int error;
-
-       error = -EBADF;
-       file = fget(fd);
-       if (!file)
-               goto out;
-       error = vfs_statfs(&file->f_path, &tmp);
+       int error = fd_statfs(fd, &tmp);
        if (!error)
                error = put_compat_statfs(buf, &tmp);
-       fput(file);
-out:
        return error;
 }
 
@@ -329,41 +313,29 @@ static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstat
 
 asmlinkage long compat_sys_statfs64(const char __user *pathname, compat_size_t sz, struct compat_statfs64 __user *buf)
 {
-       struct path path;
+       struct kstatfs tmp;
        int error;
 
        if (sz != sizeof(*buf))
                return -EINVAL;
 
-       error = user_path(pathname, &path);
-       if (!error) {
-               struct kstatfs tmp;
-               error = vfs_statfs(&path, &tmp);
-               if (!error)
-                       error = put_compat_statfs64(buf, &tmp);
-               path_put(&path);
-       }
+       error = user_statfs(pathname, &tmp);
+       if (!error)
+               error = put_compat_statfs64(buf, &tmp);
        return error;
 }
 
 asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct compat_statfs64 __user *buf)
 {
-       struct file * file;
        struct kstatfs tmp;
        int error;
 
        if (sz != sizeof(*buf))
                return -EINVAL;
 
-       error = -EBADF;
-       file = fget(fd);
-       if (!file)
-               goto out;
-       error = vfs_statfs(&file->f_path, &tmp);
+       error = fd_statfs(fd, &tmp);
        if (!error)
                error = put_compat_statfs64(buf, &tmp);
-       fput(file);
-out:
        return error;
 }
 
@@ -1228,7 +1200,9 @@ compat_sys_preadv(unsigned long fd, const struct compat_iovec __user *vec,
        file = fget_light(fd, &fput_needed);
        if (!file)
                return -EBADF;
-       ret = compat_readv(file, vec, vlen, &pos);
+       ret = -ESPIPE;
+       if (file->f_mode & FMODE_PREAD)
+               ret = compat_readv(file, vec, vlen, &pos);
        fput_light(file, fput_needed);
        return ret;
 }
@@ -1285,7 +1259,9 @@ compat_sys_pwritev(unsigned long fd, const struct compat_iovec __user *vec,
        file = fget_light(fd, &fput_needed);
        if (!file)
                return -EBADF;
-       ret = compat_writev(file, vec, vlen, &pos);
+       ret = -ESPIPE;
+       if (file->f_mode & FMODE_PWRITE)
+               ret = compat_writev(file, vec, vlen, &pos);
        fput_light(file, fput_needed);
        return ret;
 }
@@ -2308,3 +2284,16 @@ asmlinkage long compat_sys_timerfd_gettime(int ufd,
 }
 
 #endif /* CONFIG_TIMERFD */
+
+#ifdef CONFIG_FHANDLE
+/*
+ * Exactly like fs/open.c:sys_open_by_handle_at(), except that it
+ * doesn't set the O_LARGEFILE flag.
+ */
+asmlinkage long
+compat_sys_open_by_handle_at(int mountdirfd,
+                            struct file_handle __user *handle, int flags)
+{
+       return do_handle_open(mountdirfd, handle, flags);
+}
+#endif
index 2a6bd9a..a39fe47 100644 (file)
@@ -296,8 +296,12 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent)
        __releases(parent->d_lock)
        __releases(dentry->d_inode->i_lock)
 {
-       dentry->d_parent = NULL;
        list_del(&dentry->d_u.d_child);
+       /*
+        * Inform try_to_ascend() that we are no longer attached to the
+        * dentry tree
+        */
+       dentry->d_flags |= DCACHE_DISCONNECTED;
        if (parent)
                spin_unlock(&parent->d_lock);
        dentry_iput(dentry);
@@ -1011,6 +1015,35 @@ void shrink_dcache_for_umount(struct super_block *sb)
        }
 }
 
+/*
+ * This tries to ascend one level of parenthood, but
+ * we can race with renaming, so we need to re-check
+ * the parenthood after dropping the lock and check
+ * that the sequence number still matches.
+ */
+static struct dentry *try_to_ascend(struct dentry *old, int locked, unsigned seq)
+{
+       struct dentry *new = old->d_parent;
+
+       rcu_read_lock();
+       spin_unlock(&old->d_lock);
+       spin_lock(&new->d_lock);
+
+       /*
+        * might go back up the wrong parent if we have had a rename
+        * or deletion
+        */
+       if (new != old->d_parent ||
+                (old->d_flags & DCACHE_DISCONNECTED) ||
+                (!locked && read_seqretry(&rename_lock, seq))) {
+               spin_unlock(&new->d_lock);
+               new = NULL;
+       }
+       rcu_read_unlock();
+       return new;
+}
+
+
 /*
  * Search for at least 1 mount point in the dentry's subdirs.
  * We descend to the next level whenever the d_subdirs
@@ -1066,24 +1099,10 @@ resume:
         * All done at this level ... ascend and resume the search.
         */
        if (this_parent != parent) {
-               struct dentry *tmp;
-               struct dentry *child;
-
-               tmp = this_parent->d_parent;
-               rcu_read_lock();
-               spin_unlock(&this_parent->d_lock);
-               child = this_parent;
-               this_parent = tmp;
-               spin_lock(&this_parent->d_lock);
-               /* might go back up the wrong parent if we have had a rename
-                * or deletion */
-               if (this_parent != child->d_parent ||
-                        (!locked && read_seqretry(&rename_lock, seq))) {
-                       spin_unlock(&this_parent->d_lock);
-                       rcu_read_unlock();
+               struct dentry *child = this_parent;
+               this_parent = try_to_ascend(this_parent, locked, seq);
+               if (!this_parent)
                        goto rename_retry;
-               }
-               rcu_read_unlock();
                next = child->d_u.d_child.next;
                goto resume;
        }
@@ -1181,24 +1200,10 @@ resume:
         * All done at this level ... ascend and resume the search.
         */
        if (this_parent != parent) {
-               struct dentry *tmp;
-               struct dentry *child;
-
-               tmp = this_parent->d_parent;
-               rcu_read_lock();
-               spin_unlock(&this_parent->d_lock);
-               child = this_parent;
-               this_parent = tmp;
-               spin_lock(&this_parent->d_lock);
-               /* might go back up the wrong parent if we have had a rename
-                * or deletion */
-               if (this_parent != child->d_parent ||
-                       (!locked && read_seqretry(&rename_lock, seq))) {
-                       spin_unlock(&this_parent->d_lock);
-                       rcu_read_unlock();
+               struct dentry *child = this_parent;
+               this_parent = try_to_ascend(this_parent, locked, seq);
+               if (!this_parent)
                        goto rename_retry;
-               }
-               rcu_read_unlock();
                next = child->d_u.d_child.next;
                goto resume;
        }
@@ -1523,6 +1528,28 @@ struct dentry * d_alloc_root(struct inode * root_inode)
 }
 EXPORT_SYMBOL(d_alloc_root);
 
+static struct dentry * __d_find_any_alias(struct inode *inode)
+{
+       struct dentry *alias;
+
+       if (list_empty(&inode->i_dentry))
+               return NULL;
+       alias = list_first_entry(&inode->i_dentry, struct dentry, d_alias);
+       __dget(alias);
+       return alias;
+}
+
+static struct dentry * d_find_any_alias(struct inode *inode)
+{
+       struct dentry *de;
+
+       spin_lock(&inode->i_lock);
+       de = __d_find_any_alias(inode);
+       spin_unlock(&inode->i_lock);
+       return de;
+}
+
+
 /**
  * d_obtain_alias - find or allocate a dentry for a given inode
  * @inode: inode to allocate the dentry for
@@ -1552,7 +1579,7 @@ struct dentry *d_obtain_alias(struct inode *inode)
        if (IS_ERR(inode))
                return ERR_CAST(inode);
 
-       res = d_find_alias(inode);
+       res = d_find_any_alias(inode);
        if (res)
                goto out_iput;
 
@@ -1565,7 +1592,7 @@ struct dentry *d_obtain_alias(struct inode *inode)
 
 
        spin_lock(&inode->i_lock);
-       res = __d_find_alias(inode, 0);
+       res = __d_find_any_alias(inode);
        if (res) {
                spin_unlock(&inode->i_lock);
                dput(tmp);
@@ -2920,28 +2947,14 @@ resume:
                spin_unlock(&dentry->d_lock);
        }
        if (this_parent != root) {
-               struct dentry *tmp;
-               struct dentry *child;
-
-               tmp = this_parent->d_parent;
+               struct dentry *child = this_parent;
                if (!(this_parent->d_flags & DCACHE_GENOCIDE)) {
                        this_parent->d_flags |= DCACHE_GENOCIDE;
                        this_parent->d_count--;
                }
-               rcu_read_lock();
-               spin_unlock(&this_parent->d_lock);
-               child = this_parent;
-               this_parent = tmp;
-               spin_lock(&this_parent->d_lock);
-               /* might go back up the wrong parent if we have had a rename
-                * or deletion */
-               if (this_parent != child->d_parent ||
-                        (!locked && read_seqretry(&rename_lock, seq))) {
-                       spin_unlock(&this_parent->d_lock);
-                       rcu_read_unlock();
+               this_parent = try_to_ascend(this_parent, locked, seq);
+               if (!this_parent)
                        goto rename_retry;
-               }
-               rcu_read_unlock();
                next = child->d_u.d_child.next;
                goto resume;
        }
index 9c64ae9..2d8c87b 100644 (file)
@@ -1468,15 +1468,13 @@ static void work_stop(void)
 
 static int work_start(void)
 {
-       recv_workqueue = alloc_workqueue("dlm_recv", WQ_MEM_RECLAIM |
-                                        WQ_HIGHPRI | WQ_FREEZEABLE, 0);
+       recv_workqueue = create_singlethread_workqueue("dlm_recv");
        if (!recv_workqueue) {
                log_print("can't start dlm_recv");
                return -ENOMEM;
        }
 
-       send_workqueue = alloc_workqueue("dlm_send", WQ_MEM_RECLAIM |
-                                        WQ_HIGHPRI | WQ_FREEZEABLE, 0);
+       send_workqueue = create_singlethread_workqueue("dlm_send");
        if (!send_workqueue) {
                log_print("can't start dlm_send");
                destroy_workqueue(recv_workqueue);
index 6fc4f31..534c1d4 100644 (file)
@@ -46,24 +46,28 @@ static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
        struct dentry *lower_dentry;
        struct vfsmount *lower_mnt;
-       struct dentry *dentry_save;
-       struct vfsmount *vfsmount_save;
+       struct dentry *dentry_save = NULL;
+       struct vfsmount *vfsmount_save = NULL;
        int rc = 1;
 
-       if (nd->flags & LOOKUP_RCU)
+       if (nd && nd->flags & LOOKUP_RCU)
                return -ECHILD;
 
        lower_dentry = ecryptfs_dentry_to_lower(dentry);
        lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
        if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate)
                goto out;
-       dentry_save = nd->path.dentry;
-       vfsmount_save = nd->path.mnt;
-       nd->path.dentry = lower_dentry;
-       nd->path.mnt = lower_mnt;
+       if (nd) {
+               dentry_save = nd->path.dentry;
+               vfsmount_save = nd->path.mnt;
+               nd->path.dentry = lower_dentry;
+               nd->path.mnt = lower_mnt;
+       }
        rc = lower_dentry->d_op->d_revalidate(lower_dentry, nd);
-       nd->path.dentry = dentry_save;
-       nd->path.mnt = vfsmount_save;
+       if (nd) {
+               nd->path.dentry = dentry_save;
+               nd->path.mnt = vfsmount_save;
+       }
        if (dentry->d_inode) {
                struct inode *lower_inode =
                        ecryptfs_inode_to_lower(dentry->d_inode);
index dbc84ed..e007534 100644 (file)
@@ -632,8 +632,7 @@ int ecryptfs_interpose(struct dentry *hidden_dentry,
                       u32 flags);
 int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
                                        struct dentry *lower_dentry,
-                                       struct inode *ecryptfs_dir_inode,
-                                       struct nameidata *ecryptfs_nd);
+                                       struct inode *ecryptfs_dir_inode);
 int ecryptfs_decode_and_decrypt_filename(char **decrypted_name,
                                         size_t *decrypted_name_size,
                                         struct dentry *ecryptfs_dentry,
index 81e10e6..7d1050e 100644 (file)
@@ -317,6 +317,7 @@ ecryptfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
 const struct file_operations ecryptfs_dir_fops = {
        .readdir = ecryptfs_readdir,
+       .read = generic_read_dir,
        .unlocked_ioctl = ecryptfs_unlocked_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = ecryptfs_compat_ioctl,
index bd33f87..b592938 100644 (file)
@@ -74,16 +74,20 @@ ecryptfs_create_underlying_file(struct inode *lower_dir_inode,
        unsigned int flags_save;
        int rc;
 
-       dentry_save = nd->path.dentry;
-       vfsmount_save = nd->path.mnt;
-       flags_save = nd->flags;
-       nd->path.dentry = lower_dentry;
-       nd->path.mnt = lower_mnt;
-       nd->flags &= ~LOOKUP_OPEN;
+       if (nd) {
+               dentry_save = nd->path.dentry;
+               vfsmount_save = nd->path.mnt;
+               flags_save = nd->flags;
+               nd->path.dentry = lower_dentry;
+               nd->path.mnt = lower_mnt;
+               nd->flags &= ~LOOKUP_OPEN;
+       }
        rc = vfs_create(lower_dir_inode, lower_dentry, mode, nd);
-       nd->path.dentry = dentry_save;
-       nd->path.mnt = vfsmount_save;
-       nd->flags = flags_save;
+       if (nd) {
+               nd->path.dentry = dentry_save;
+               nd->path.mnt = vfsmount_save;
+               nd->flags = flags_save;
+       }
        return rc;
 }
 
@@ -241,8 +245,7 @@ out:
  */
 int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
                                        struct dentry *lower_dentry,
-                                       struct inode *ecryptfs_dir_inode,
-                                       struct nameidata *ecryptfs_nd)
+                                       struct inode *ecryptfs_dir_inode)
 {
        struct dentry *lower_dir_dentry;
        struct vfsmount *lower_mnt;
@@ -290,8 +293,6 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
                goto out;
        if (special_file(lower_inode->i_mode))
                goto out;
-       if (!ecryptfs_nd)
-               goto out;
        /* Released in this function */
        page_virt = kmem_cache_zalloc(ecryptfs_header_cache_2, GFP_USER);
        if (!page_virt) {
@@ -348,75 +349,6 @@ out:
        return rc;
 }
 
-/**
- * ecryptfs_new_lower_dentry
- * @name: The name of the new dentry.
- * @lower_dir_dentry: Parent directory of the new dentry.
- * @nd: nameidata from last lookup.
- *
- * Create a new dentry or get it from lower parent dir.
- */
-static struct dentry *
-ecryptfs_new_lower_dentry(struct qstr *name, struct dentry *lower_dir_dentry,
-                         struct nameidata *nd)
-{
-       struct dentry *new_dentry;
-       struct dentry *tmp;
-       struct inode *lower_dir_inode;
-
-       lower_dir_inode = lower_dir_dentry->d_inode;
-
-       tmp = d_alloc(lower_dir_dentry, name);
-       if (!tmp)
-               return ERR_PTR(-ENOMEM);
-
-       mutex_lock(&lower_dir_inode->i_mutex);
-       new_dentry = lower_dir_inode->i_op->lookup(lower_dir_inode, tmp, nd);
-       mutex_unlock(&lower_dir_inode->i_mutex);
-
-       if (!new_dentry)
-               new_dentry = tmp;
-       else
-               dput(tmp);
-
-       return new_dentry;
-}
-
-
-/**
- * ecryptfs_lookup_one_lower
- * @ecryptfs_dentry: The eCryptfs dentry that we are looking up
- * @lower_dir_dentry: lower parent directory
- * @name: lower file name
- *
- * Get the lower dentry from vfs. If lower dentry does not exist yet,
- * create it.
- */
-static struct dentry *
-ecryptfs_lookup_one_lower(struct dentry *ecryptfs_dentry,
-                         struct dentry *lower_dir_dentry, struct qstr *name)
-{
-       struct nameidata nd;
-       struct vfsmount *lower_mnt;
-       int err;
-
-       lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(
-                                   ecryptfs_dentry->d_parent));
-       err = vfs_path_lookup(lower_dir_dentry, lower_mnt, name->name , 0, &nd);
-       mntput(lower_mnt);
-
-       if (!err) {
-               /* we dont need the mount */
-               mntput(nd.path.mnt);
-               return nd.path.dentry;
-       }
-       if (err != -ENOENT)
-               return ERR_PTR(err);
-
-       /* create a new lower dentry */
-       return ecryptfs_new_lower_dentry(name, lower_dir_dentry, &nd);
-}
-
 /**
  * ecryptfs_lookup
  * @ecryptfs_dir_inode: The eCryptfs directory inode
@@ -434,7 +366,6 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
        size_t encrypted_and_encoded_name_size;
        struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL;
        struct dentry *lower_dir_dentry, *lower_dentry;
-       struct qstr lower_name;
        int rc = 0;
 
        if ((ecryptfs_dentry->d_name.len == 1
@@ -444,20 +375,14 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
                goto out_d_drop;
        }
        lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent);
-       lower_name.name = ecryptfs_dentry->d_name.name;
-       lower_name.len = ecryptfs_dentry->d_name.len;
-       lower_name.hash = ecryptfs_dentry->d_name.hash;
-       if (lower_dir_dentry->d_op && lower_dir_dentry->d_op->d_hash) {
-               rc = lower_dir_dentry->d_op->d_hash(lower_dir_dentry,
-                               lower_dir_dentry->d_inode, &lower_name);
-               if (rc < 0)
-                       goto out_d_drop;
-       }
-       lower_dentry = ecryptfs_lookup_one_lower(ecryptfs_dentry,
-                                                lower_dir_dentry, &lower_name);
+       mutex_lock(&lower_dir_dentry->d_inode->i_mutex);
+       lower_dentry = lookup_one_len(ecryptfs_dentry->d_name.name,
+                                     lower_dir_dentry,
+                                     ecryptfs_dentry->d_name.len);
+       mutex_unlock(&lower_dir_dentry->d_inode->i_mutex);
        if (IS_ERR(lower_dentry)) {
                rc = PTR_ERR(lower_dentry);
-               ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_lower() returned "
+               ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned "
                                "[%d] on lower_dentry = [%s]\n", __func__, rc,
                                encrypted_and_encoded_name);
                goto out_d_drop;
@@ -479,28 +404,21 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
                       "filename; rc = [%d]\n", __func__, rc);
                goto out_d_drop;
        }
-       lower_name.name = encrypted_and_encoded_name;
-       lower_name.len = encrypted_and_encoded_name_size;
-       lower_name.hash = full_name_hash(lower_name.name, lower_name.len);
-       if (lower_dir_dentry->d_op && lower_dir_dentry->d_op->d_hash) {
-               rc = lower_dir_dentry->d_op->d_hash(lower_dir_dentry,
-                               lower_dir_dentry->d_inode, &lower_name);
-               if (rc < 0)
-                       goto out_d_drop;
-       }
-       lower_dentry = ecryptfs_lookup_one_lower(ecryptfs_dentry,
-                                                lower_dir_dentry, &lower_name);
+       mutex_lock(&lower_dir_dentry->d_inode->i_mutex);
+       lower_dentry = lookup_one_len(encrypted_and_encoded_name,
+                                     lower_dir_dentry,
+                                     encrypted_and_encoded_name_size);
+       mutex_unlock(&lower_dir_dentry->d_inode->i_mutex);
        if (IS_ERR(lower_dentry)) {
                rc = PTR_ERR(lower_dentry);
-               ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_lower() returned "
+               ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned "
                                "[%d] on lower_dentry = [%s]\n", __func__, rc,
                                encrypted_and_encoded_name);
                goto out_d_drop;
        }
 lookup_and_interpose:
        rc = ecryptfs_lookup_and_interpose_lower(ecryptfs_dentry, lower_dentry,
-                                                ecryptfs_dir_inode,
-                                                ecryptfs_nd);
+                                                ecryptfs_dir_inode);
        goto out;
 out_d_drop:
        d_drop(ecryptfs_dentry);
@@ -1092,6 +1010,8 @@ int ecryptfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
        rc = vfs_getattr(ecryptfs_dentry_to_lower_mnt(dentry),
                         ecryptfs_dentry_to_lower(dentry), &lower_stat);
        if (!rc) {
+               fsstack_copy_attr_all(dentry->d_inode,
+                                     ecryptfs_inode_to_lower(dentry->d_inode));
                generic_fillattr(dentry->d_inode, stat);
                stat->blocks = lower_stat.blocks;
        }
index e0194b3..d9a5917 100644 (file)
@@ -99,7 +99,7 @@ EXPORT_SYMBOL_GPL(eventfd_ctx_get);
  * @ctx: [in] Pointer to eventfd context.
  *
  * The eventfd context reference must have been previously acquired either
- * with eventfd_ctx_get() or eventfd_ctx_fdget()).
+ * with eventfd_ctx_get() or eventfd_ctx_fdget().
  */
 void eventfd_ctx_put(struct eventfd_ctx *ctx)
 {
@@ -146,9 +146,9 @@ static void eventfd_ctx_do_read(struct eventfd_ctx *ctx, __u64 *cnt)
  * eventfd_ctx_remove_wait_queue - Read the current counter and removes wait queue.
  * @ctx: [in] Pointer to eventfd context.
  * @wait: [in] Wait queue to be removed.
- * @cnt: [out] Pointer to the 64bit conter value.
+ * @cnt: [out] Pointer to the 64-bit counter value.
  *
- * Returns zero if successful, or the following error codes:
+ * Returns %0 if successful, or the following error codes:
  *
  * -EAGAIN      : The operation would have blocked.
  *
@@ -175,11 +175,11 @@ EXPORT_SYMBOL_GPL(eventfd_ctx_remove_wait_queue);
  * eventfd_ctx_read - Reads the eventfd counter or wait if it is zero.
  * @ctx: [in] Pointer to eventfd context.
  * @no_wait: [in] Different from zero if the operation should not block.
- * @cnt: [out] Pointer to the 64bit conter value.
+ * @cnt: [out] Pointer to the 64-bit counter value.
  *
- * Returns zero if successful, or the following error codes:
+ * Returns %0 if successful, or the following error codes:
  *
- * -EAGAIN      : The operation would have blocked but @no_wait was nonzero.
+ * -EAGAIN      : The operation would have blocked but @no_wait was non-zero.
  * -ERESTARTSYS : A signal interrupted the wait operation.
  *
  * If @no_wait is zero, the function might sleep until the eventfd internal
index cc8a9b7..4a09af9 100644 (file)
  * cleanup path and it is also acquired by eventpoll_release_file()
  * if a file has been pushed inside an epoll set and it is then
  * close()d without a previous call toepoll_ctl(EPOLL_CTL_DEL).
+ * It is also acquired when inserting an epoll fd onto another epoll
+ * fd. We do this so that we walk the epoll tree and ensure that this
+ * insertion does not create a cycle of epoll file descriptors, which
+ * could lead to deadlock. We need a global mutex to prevent two
+ * simultaneous inserts (A into B and B into A) from racing and
+ * constructing a cycle without either insert observing that it is
+ * going to.
  * It is possible to drop the "ep->mtx" and to use the global
  * mutex "epmutex" (together with "ep->lock") to have it working,
  * but having "ep->mtx" will make the interface more scalable.
@@ -224,6 +231,9 @@ static long max_user_watches __read_mostly;
  */
 static DEFINE_MUTEX(epmutex);
 
+/* Used to check for epoll file descriptor inclusion loops */
+static struct nested_calls poll_loop_ncalls;
+
 /* Used for safe wake up implementation */
 static struct nested_calls poll_safewake_ncalls;
 
@@ -1114,6 +1124,17 @@ static int ep_send_events(struct eventpoll *ep,
        return ep_scan_ready_list(ep, ep_send_events_proc, &esed);
 }
 
+static inline struct timespec ep_set_mstimeout(long ms)
+{
+       struct timespec now, ts = {
+               .tv_sec = ms / MSEC_PER_SEC,
+               .tv_nsec = NSEC_PER_MSEC * (ms % MSEC_PER_SEC),
+       };
+
+       ktime_get_ts(&now);
+       return timespec_add_safe(now, ts);
+}
+
 static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
                   int maxevents, long timeout)
 {
@@ -1121,12 +1142,11 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
        unsigned long flags;
        long slack;
        wait_queue_t wait;
-       struct timespec end_time;
        ktime_t expires, *to = NULL;
 
        if (timeout > 0) {
-               ktime_get_ts(&end_time);
-               timespec_add_ns(&end_time, (u64)timeout * NSEC_PER_MSEC);
+               struct timespec end_time = ep_set_mstimeout(timeout);
+
                slack = select_estimate_accuracy(&end_time);
                to = &expires;
                *to = timespec_to_ktime(end_time);
@@ -1188,6 +1208,62 @@ retry:
        return res;
 }
 
+/**
+ * ep_loop_check_proc - Callback function to be passed to the @ep_call_nested()
+ *                      API, to verify that adding an epoll file inside another
+ *                      epoll structure, does not violate the constraints, in
+ *                      terms of closed loops, or too deep chains (which can
+ *                      result in excessive stack usage).
+ *
+ * @priv: Pointer to the epoll file to be currently checked.
+ * @cookie: Original cookie for this call. This is the top-of-the-chain epoll
+ *          data structure pointer.
+ * @call_nests: Current dept of the @ep_call_nested() call stack.
+ *
+ * Returns: Returns zero if adding the epoll @file inside current epoll
+ *          structure @ep does not violate the constraints, or -1 otherwise.
+ */
+static int ep_loop_check_proc(void *priv, void *cookie, int call_nests)
+{
+       int error = 0;
+       struct file *file = priv;
+       struct eventpoll *ep = file->private_data;
+       struct rb_node *rbp;
+       struct epitem *epi;
+
+       mutex_lock(&ep->mtx);
+       for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) {
+               epi = rb_entry(rbp, struct epitem, rbn);
+               if (unlikely(is_file_epoll(epi->ffd.file))) {
+                       error = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS,
+                                              ep_loop_check_proc, epi->ffd.file,
+                                              epi->ffd.file->private_data, current);
+                       if (error != 0)
+                               break;
+               }
+       }
+       mutex_unlock(&ep->mtx);
+
+       return error;
+}
+
+/**
+ * ep_loop_check - Performs a check to verify that adding an epoll file (@file)
+ *                 another epoll file (represented by @ep) does not create
+ *                 closed loops or too deep chains.
+ *
+ * @ep: Pointer to the epoll private data structure.
+ * @file: Pointer to the epoll file to be checked.
+ *
+ * Returns: Returns zero if adding the epoll @file inside current epoll
+ *          structure @ep does not violate the constraints, or -1 otherwise.
+ */
+static int ep_loop_check(struct eventpoll *ep, struct file *file)
+{
+       return ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS,
+                             ep_loop_check_proc, file, ep, current);
+}
+
 /*
  * Open an eventpoll file descriptor.
  */
@@ -1236,6 +1312,7 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
                struct epoll_event __user *, event)
 {
        int error;
+       int did_lock_epmutex = 0;
        struct file *file, *tfile;
        struct eventpoll *ep;
        struct epitem *epi;
@@ -1277,6 +1354,25 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
         */
        ep = file->private_data;
 
+       /*
+        * When we insert an epoll file descriptor, inside another epoll file
+        * descriptor, there is the change of creating closed loops, which are
+        * better be handled here, than in more critical paths.
+        *
+        * We hold epmutex across the loop check and the insert in this case, in
+        * order to prevent two separate inserts from racing and each doing the
+        * insert "at the same time" such that ep_loop_check passes on both
+        * before either one does the insert, thereby creating a cycle.
+        */
+       if (unlikely(is_file_epoll(tfile) && op == EPOLL_CTL_ADD)) {
+               mutex_lock(&epmutex);
+               did_lock_epmutex = 1;
+               error = -ELOOP;
+               if (ep_loop_check(ep, tfile) != 0)
+                       goto error_tgt_fput;
+       }
+
+
        mutex_lock(&ep->mtx);
 
        /*
@@ -1312,6 +1408,9 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
        mutex_unlock(&ep->mtx);
 
 error_tgt_fput:
+       if (unlikely(did_lock_epmutex))
+               mutex_unlock(&epmutex);
+
        fput(tfile);
 error_fput:
        fput(file);
@@ -1431,6 +1530,12 @@ static int __init eventpoll_init(void)
                EP_ITEM_COST;
        BUG_ON(max_user_watches < 0);
 
+       /*
+        * Initialize the structure used to perform epoll file descriptor
+        * inclusion loops checks.
+        */
+       ep_nested_calls_init(&poll_loop_ncalls);
+
        /* Initialize the structure used to perform safe poll wait head wake ups */
        ep_nested_calls_init(&poll_safewake_ncalls);
 
index c62efcb..ba99e1a 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -115,13 +115,16 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
        struct file *file;
        char *tmp = getname(library);
        int error = PTR_ERR(tmp);
+       static const struct open_flags uselib_flags = {
+               .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
+               .acc_mode = MAY_READ | MAY_EXEC | MAY_OPEN,
+               .intent = LOOKUP_OPEN
+       };
 
        if (IS_ERR(tmp))
                goto out;
 
-       file = do_filp_open(AT_FDCWD, tmp,
-                               O_LARGEFILE | O_RDONLY | FMODE_EXEC, 0,
-                               MAY_READ | MAY_EXEC | MAY_OPEN);
+       file = do_filp_open(AT_FDCWD, tmp, &uselib_flags, LOOKUP_FOLLOW);
        putname(tmp);
        error = PTR_ERR(file);
        if (IS_ERR(file))
@@ -721,10 +724,13 @@ struct file *open_exec(const char *name)
 {
        struct file *file;
        int err;
+       static const struct open_flags open_exec_flags = {
+               .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
+               .acc_mode = MAY_EXEC | MAY_OPEN,
+               .intent = LOOKUP_OPEN
+       };
 
-       file = do_filp_open(AT_FDCWD, name,
-                               O_LARGEFILE | O_RDONLY | FMODE_EXEC, 0,
-                               MAY_EXEC | MAY_OPEN);
+       file = do_filp_open(AT_FDCWD, name, &open_exec_flags, LOOKUP_FOLLOW);
        if (IS_ERR(file))
                goto out;
 
index 4268542..a755523 100644 (file)
@@ -1030,7 +1030,6 @@ struct inode *exofs_iget(struct super_block *sb, unsigned long ino)
                memcpy(oi->i_data, fcb.i_data, sizeof(fcb.i_data));
        }
 
-       inode->i_mapping->backing_dev_info = sb->s_bdi;
        if (S_ISREG(inode->i_mode)) {
                inode->i_op = &exofs_file_inode_operations;
                inode->i_fop = &exofs_file_operations;
@@ -1131,7 +1130,6 @@ struct inode *exofs_new_inode(struct inode *dir, int mode)
 
        sbi = sb->s_fs_info;
 
-       inode->i_mapping->backing_dev_info = sb->s_bdi;
        sb->s_dirt = 1;
        inode_init_owner(inode, dir, mode);
        inode->i_ino = sbi->s_nextid++;
index 264e95d..4d70db1 100644 (file)
@@ -272,7 +272,6 @@ static int exofs_rename(struct inode *old_dir, struct dentry *old_dentry,
                new_de = exofs_find_entry(new_dir, new_dentry, &new_page);
                if (!new_de)
                        goto out_dir;
-               inode_inc_link_count(old_inode);
                err = exofs_set_link(new_dir, new_de, new_page, old_inode);
                new_inode->i_ctime = CURRENT_TIME;
                if (dir_de)
@@ -286,12 +285,9 @@ static int exofs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        if (new_dir->i_nlink >= EXOFS_LINK_MAX)
                                goto out_dir;
                }
-               inode_inc_link_count(old_inode);
                err = exofs_add_link(new_dentry, old_inode);
-               if (err) {
-                       inode_dec_link_count(old_inode);
+               if (err)
                        goto out_dir;
-               }
                if (dir_de)
                        inode_inc_link_count(new_dir);
        }
@@ -299,7 +295,7 @@ static int exofs_rename(struct inode *old_dir, struct dentry *old_dentry,
        old_inode->i_ctime = CURRENT_TIME;
 
        exofs_delete_entry(old_de, old_page);
-       inode_dec_link_count(old_inode);
+       mark_inode_dirty(old_inode);
 
        if (dir_de) {
                err = exofs_set_link(old_inode, dir_de, dir_page, new_dir);
index 4b68257..b05acb7 100644 (file)
@@ -320,9 +320,14 @@ static int export_encode_fh(struct dentry *dentry, struct fid *fid,
        struct inode * inode = dentry->d_inode;
        int len = *max_len;
        int type = FILEID_INO32_GEN;
-       
-       if (len < 2 || (connectable && len < 4))
+
+       if (connectable && (len < 4)) {
+               *max_len = 4;
+               return 255;
+       } else if (len < 2) {
+               *max_len = 2;
                return 255;
+       }
 
        len = 2;
        fid->i32.ino = inode->i_ino;
@@ -369,6 +374,8 @@ struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
        /*
         * Try to get any dentry for the given file handle from the filesystem.
         */
+       if (!nop || !nop->fh_to_dentry)
+               return ERR_PTR(-ESTALE);
        result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type);
        if (!result)
                result = ERR_PTR(-ESTALE);
index 2e1d834..adb9185 100644 (file)
@@ -344,7 +344,6 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
                new_de = ext2_find_entry (new_dir, &new_dentry->d_name, &new_page);
                if (!new_de)
                        goto out_dir;
-               inode_inc_link_count(old_inode);
                ext2_set_link(new_dir, new_de, new_page, old_inode, 1);
                new_inode->i_ctime = CURRENT_TIME_SEC;
                if (dir_de)
@@ -356,12 +355,9 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
                        if (new_dir->i_nlink >= EXT2_LINK_MAX)
                                goto out_dir;
                }
-               inode_inc_link_count(old_inode);
                err = ext2_add_link(new_dentry, old_inode);
-               if (err) {
-                       inode_dec_link_count(old_inode);
+               if (err)
                        goto out_dir;
-               }
                if (dir_de)
                        inode_inc_link_count(new_dir);
        }
@@ -369,12 +365,11 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
        /*
         * Like most other Unix systems, set the ctime for inodes on a
         * rename.
-        * inode_dec_link_count() will mark the inode dirty.
         */
        old_inode->i_ctime = CURRENT_TIME_SEC;
+       mark_inode_dirty(old_inode);
 
        ext2_delete_entry (old_de, old_page);
-       inode_dec_link_count(old_inode);
 
        if (dir_de) {
                if (old_dir != new_dir)
index b27ba71..561f692 100644 (file)
@@ -2253,13 +2253,6 @@ static int ext3_link (struct dentry * old_dentry,
 
        dquot_initialize(dir);
 
-       /*
-        * Return -ENOENT if we've raced with unlink and i_nlink is 0.  Doing
-        * otherwise has the potential to corrupt the orphan inode list.
-        */
-       if (inode->i_nlink == 0)
-               return -ENOENT;
-
 retry:
        handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
                                        EXT3_INDEX_EXTRA_TRANS_BLOCKS);
index 85c8cc8..9cc19a1 100644 (file)
@@ -1936,6 +1936,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
        sb->s_qcop = &ext3_qctl_operations;
        sb->dq_op = &ext3_quota_operations;
 #endif
+       memcpy(sb->s_uuid, es->s_uuid, sizeof(es->s_uuid));
        INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
        mutex_init(&sbi->s_orphan_lock);
        mutex_init(&sbi->s_resize_lock);
index 0c8d97b..3aa0b72 100644 (file)
@@ -848,6 +848,7 @@ struct ext4_inode_info {
        atomic_t i_ioend_count; /* Number of outstanding io_end structs */
        /* current io_end structure for async DIO write*/
        ext4_io_end_t *cur_aio_dio;
+       atomic_t i_aiodio_unwritten; /* Nr. of inflight conversions pending */
 
        spinlock_t i_block_reservation_lock;
 
@@ -2119,6 +2120,15 @@ static inline void set_bitmap_uptodate(struct buffer_head *bh)
 
 #define in_range(b, first, len)        ((b) >= (first) && (b) <= (first) + (len) - 1)
 
+/* For ioend & aio unwritten conversion wait queues */
+#define EXT4_WQ_HASH_SZ                37
+#define ext4_ioend_wq(v)   (&ext4__ioend_wq[((unsigned long)(v)) %\
+                                           EXT4_WQ_HASH_SZ])
+#define ext4_aio_mutex(v)  (&ext4__aio_mutex[((unsigned long)(v)) %\
+                                            EXT4_WQ_HASH_SZ])
+extern wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ];
+extern struct mutex ext4__aio_mutex[EXT4_WQ_HASH_SZ];
+
 #endif /* __KERNEL__ */
 
 #endif /* _EXT4_H */
index 63a7581..ccce8a7 100644 (file)
@@ -3174,9 +3174,10 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
                 * that this IO needs to convertion to written when IO is
                 * completed
                 */
-               if (io)
+               if (io && !(io->flag & EXT4_IO_END_UNWRITTEN)) {
                        io->flag = EXT4_IO_END_UNWRITTEN;
-               else
+                       atomic_inc(&EXT4_I(inode)->i_aiodio_unwritten);
+               } else
                        ext4_set_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN);
                if (ext4_should_dioread_nolock(inode))
                        map->m_flags |= EXT4_MAP_UNINIT;
@@ -3463,9 +3464,10 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
                 * that we need to perform convertion when IO is done.
                 */
                if ((flags & EXT4_GET_BLOCKS_PRE_IO)) {
-                       if (io)
+                       if (io && !(io->flag & EXT4_IO_END_UNWRITTEN)) {
                                io->flag = EXT4_IO_END_UNWRITTEN;
-                       else
+                               atomic_inc(&EXT4_I(inode)->i_aiodio_unwritten);
+                       } else
                                ext4_set_inode_state(inode,
                                                     EXT4_STATE_DIO_UNWRITTEN);
                }
index 2e8322c..7b80d54 100644 (file)
@@ -55,11 +55,47 @@ static int ext4_release_file(struct inode *inode, struct file *filp)
        return 0;
 }
 
+static void ext4_aiodio_wait(struct inode *inode)
+{
+       wait_queue_head_t *wq = ext4_ioend_wq(inode);
+
+       wait_event(*wq, (atomic_read(&EXT4_I(inode)->i_aiodio_unwritten) == 0));
+}
+
+/*
+ * This tests whether the IO in question is block-aligned or not.
+ * Ext4 utilizes unwritten extents when hole-filling during direct IO, and they
+ * are converted to written only after the IO is complete.  Until they are
+ * mapped, these blocks appear as holes, so dio_zero_block() will assume that
+ * it needs to zero out portions of the start and/or end block.  If 2 AIO
+ * threads are at work on the same unwritten block, they must be synchronized
+ * or one thread will zero the other's data, causing corruption.
+ */
+static int
+ext4_unaligned_aio(struct inode *inode, const struct iovec *iov,
+                  unsigned long nr_segs, loff_t pos)
+{
+       struct super_block *sb = inode->i_sb;
+       int blockmask = sb->s_blocksize - 1;
+       size_t count = iov_length(iov, nr_segs);
+       loff_t final_size = pos + count;
+
+       if (pos >= inode->i_size)
+               return 0;
+
+       if ((pos & blockmask) || (final_size & blockmask))
+               return 1;
+
+       return 0;
+}
+
 static ssize_t
 ext4_file_write(struct kiocb *iocb, const struct iovec *iov,
                unsigned long nr_segs, loff_t pos)
 {
        struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode;
+       int unaligned_aio = 0;
+       int ret;
 
        /*
         * If we have encountered a bitmap-format file, the size limit
@@ -78,9 +114,31 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov,
                        nr_segs = iov_shorten((struct iovec *)iov, nr_segs,
                                              sbi->s_bitmap_maxbytes - pos);
                }
+       } else if (unlikely((iocb->ki_filp->f_flags & O_DIRECT) &&
+                  !is_sync_kiocb(iocb))) {
+               unaligned_aio = ext4_unaligned_aio(inode, iov, nr_segs, pos);
        }
 
-       return generic_file_aio_write(iocb, iov, nr_segs, pos);
+       /* Unaligned direct AIO must be serialized; see comment above */
+       if (unaligned_aio) {
+               static unsigned long unaligned_warn_time;
+
+               /* Warn about this once per day */
+               if (printk_timed_ratelimit(&unaligned_warn_time, 60*60*24*HZ))
+                       ext4_msg(inode->i_sb, KERN_WARNING,
+                                "Unaligned AIO/DIO on inode %ld by %s; "
+                                "performance will be poor.",
+                                inode->i_ino, current->comm);
+               mutex_lock(ext4_aio_mutex(inode));
+               ext4_aiodio_wait(inode);
+       }
+
+       ret = generic_file_aio_write(iocb, iov, nr_segs, pos);
+
+       if (unaligned_aio)
+               mutex_unlock(ext4_aio_mutex(inode));
+
+       return ret;
 }
 
 static const struct vm_operations_struct ext4_file_vm_ops = {
index 851f49b..d1fe09a 100644 (file)
@@ -342,10 +342,15 @@ static struct kmem_cache *ext4_free_ext_cachep;
 /* We create slab caches for groupinfo data structures based on the
  * superblock block size.  There will be one per mounted filesystem for
  * each unique s_blocksize_bits */
-#define NR_GRPINFO_CACHES      \
-       (EXT4_MAX_BLOCK_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE + 1)
+#define NR_GRPINFO_CACHES 8
 static struct kmem_cache *ext4_groupinfo_caches[NR_GRPINFO_CACHES];
 
+static const char *ext4_groupinfo_slab_names[NR_GRPINFO_CACHES] = {
+       "ext4_groupinfo_1k", "ext4_groupinfo_2k", "ext4_groupinfo_4k",
+       "ext4_groupinfo_8k", "ext4_groupinfo_16k", "ext4_groupinfo_32k",
+       "ext4_groupinfo_64k", "ext4_groupinfo_128k"
+};
+
 static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
                                        ext4_group_t group);
 static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap,
@@ -2414,6 +2419,55 @@ err_freesgi:
        return -ENOMEM;
 }
 
+static void ext4_groupinfo_destroy_slabs(void)
+{
+       int i;
+
+       for (i = 0; i < NR_GRPINFO_CACHES; i++) {
+               if (ext4_groupinfo_caches[i])
+                       kmem_cache_destroy(ext4_groupinfo_caches[i]);
+               ext4_groupinfo_caches[i] = NULL;
+       }
+}
+
+static int ext4_groupinfo_create_slab(size_t size)
+{
+       static DEFINE_MUTEX(ext4_grpinfo_slab_create_mutex);
+       int slab_size;
+       int blocksize_bits = order_base_2(size);
+       int cache_index = blocksize_bits - EXT4_MIN_BLOCK_LOG_SIZE;
+       struct kmem_cache *cachep;
+
+       if (cache_index >= NR_GRPINFO_CACHES)
+               return -EINVAL;
+
+       if (unlikely(cache_index < 0))
+               cache_index = 0;
+
+       mutex_lock(&ext4_grpinfo_slab_create_mutex);
+       if (ext4_groupinfo_caches[cache_index]) {
+               mutex_unlock(&ext4_grpinfo_slab_create_mutex);
+               return 0;       /* Already created */
+       }
+
+       slab_size = offsetof(struct ext4_group_info,
+                               bb_counters[blocksize_bits + 2]);
+
+       cachep = kmem_cache_create(ext4_groupinfo_slab_names[cache_index],
+                                       slab_size, 0, SLAB_RECLAIM_ACCOUNT,
+                                       NULL);
+
+       mutex_unlock(&ext4_grpinfo_slab_create_mutex);
+       if (!cachep) {
+               printk(KERN_EMERG "EXT4: no memory for groupinfo slab cache\n");
+               return -ENOMEM;
+       }
+
+       ext4_groupinfo_caches[cache_index] = cachep;
+
+       return 0;
+}
+
 int ext4_mb_init(struct super_block *sb, int needs_recovery)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
@@ -2421,9 +2475,6 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
        unsigned offset;
        unsigned max;
        int ret;
-       int cache_index;
-       struct kmem_cache *cachep;
-       char *namep = NULL;
 
        i = (sb->s_blocksize_bits + 2) * sizeof(*sbi->s_mb_offsets);
 
@@ -2440,30 +2491,9 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
                goto out;
        }
 
-       cache_index = sb->s_blocksize_bits - EXT4_MIN_BLOCK_LOG_SIZE;
-       cachep = ext4_groupinfo_caches[cache_index];
-       if (!cachep) {
-               char name[32];
-               int len = offsetof(struct ext4_group_info,
-                                       bb_counters[sb->s_blocksize_bits + 2]);
-
-               sprintf(name, "ext4_groupinfo_%d", sb->s_blocksize_bits);
-               namep = kstrdup(name, GFP_KERNEL);
-               if (!namep) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-
-               /* Need to free the kmem_cache_name() when we
-                * destroy the slab */
-               cachep = kmem_cache_create(namep, len, 0,
-                                            SLAB_RECLAIM_ACCOUNT, NULL);
-               if (!cachep) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-               ext4_groupinfo_caches[cache_index] = cachep;
-       }
+       ret = ext4_groupinfo_create_slab(sb->s_blocksize);
+       if (ret < 0)
+               goto out;
 
        /* order 0 is regular bitmap */
        sbi->s_mb_maxs[0] = sb->s_blocksize << 3;
@@ -2520,7 +2550,6 @@ out:
        if (ret) {
                kfree(sbi->s_mb_offsets);
                kfree(sbi->s_mb_maxs);
-               kfree(namep);
        }
        return ret;
 }
@@ -2734,7 +2763,6 @@ int __init ext4_init_mballoc(void)
 
 void ext4_exit_mballoc(void)
 {
-       int i;
        /*
         * Wait for completion of call_rcu()'s on ext4_pspace_cachep
         * before destroying the slab cache.
@@ -2743,15 +2771,7 @@ void ext4_exit_mballoc(void)
        kmem_cache_destroy(ext4_pspace_cachep);
        kmem_cache_destroy(ext4_ac_cachep);
        kmem_cache_destroy(ext4_free_ext_cachep);
-
-       for (i = 0; i < NR_GRPINFO_CACHES; i++) {
-               struct kmem_cache *cachep = ext4_groupinfo_caches[i];
-               if (cachep) {
-                       char *name = (char *)kmem_cache_name(cachep);
-                       kmem_cache_destroy(cachep);
-                       kfree(name);
-               }
-       }
+       ext4_groupinfo_destroy_slabs();
        ext4_remove_debugfs_entry();
 }
 
index 5485390..e781b7e 100644 (file)
@@ -2304,13 +2304,6 @@ static int ext4_link(struct dentry *old_dentry,
 
        dquot_initialize(dir);
 
-       /*
-        * Return -ENOENT if we've raced with unlink and i_nlink is 0.  Doing
-        * otherwise has the potential to corrupt the orphan inode list.
-        */
-       if (inode->i_nlink == 0)
-               return -ENOENT;
-
 retry:
        handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
                                        EXT4_INDEX_EXTRA_TRANS_BLOCKS);
index 7270dcf..955cc30 100644 (file)
 
 static struct kmem_cache *io_page_cachep, *io_end_cachep;
 
-#define WQ_HASH_SZ             37
-#define to_ioend_wq(v) (&ioend_wq[((unsigned long)v) % WQ_HASH_SZ])
-static wait_queue_head_t ioend_wq[WQ_HASH_SZ];
-
 int __init ext4_init_pageio(void)
 {
-       int i;
-
        io_page_cachep = KMEM_CACHE(ext4_io_page, SLAB_RECLAIM_ACCOUNT);
        if (io_page_cachep == NULL)
                return -ENOMEM;
@@ -48,9 +42,6 @@ int __init ext4_init_pageio(void)
                kmem_cache_destroy(io_page_cachep);
                return -ENOMEM;
        }
-       for (i = 0; i < WQ_HASH_SZ; i++)
-               init_waitqueue_head(&ioend_wq[i]);
-
        return 0;
 }
 
@@ -62,7 +53,7 @@ void ext4_exit_pageio(void)
 
 void ext4_ioend_wait(struct inode *inode)
 {
-       wait_queue_head_t *wq = to_ioend_wq(inode);
+       wait_queue_head_t *wq = ext4_ioend_wq(inode);
 
        wait_event(*wq, (atomic_read(&EXT4_I(inode)->i_ioend_count) == 0));
 }
@@ -87,7 +78,7 @@ void ext4_free_io_end(ext4_io_end_t *io)
        for (i = 0; i < io->num_io_pages; i++)
                put_io_page(io->pages[i]);
        io->num_io_pages = 0;
-       wq = to_ioend_wq(io->inode);
+       wq = ext4_ioend_wq(io->inode);
        if (atomic_dec_and_test(&EXT4_I(io->inode)->i_ioend_count) &&
            waitqueue_active(wq))
                wake_up_all(wq);
@@ -102,6 +93,7 @@ int ext4_end_io_nolock(ext4_io_end_t *io)
        struct inode *inode = io->inode;
        loff_t offset = io->offset;
        ssize_t size = io->size;
+       wait_queue_head_t *wq;
        int ret = 0;
 
        ext4_debug("ext4_end_io_nolock: io 0x%p from inode %lu,list->next 0x%p,"
@@ -126,7 +118,16 @@ int ext4_end_io_nolock(ext4_io_end_t *io)
        if (io->iocb)
                aio_complete(io->iocb, io->result, 0);
        /* clear the DIO AIO unwritten flag */
-       io->flag &= ~EXT4_IO_END_UNWRITTEN;
+       if (io->flag & EXT4_IO_END_UNWRITTEN) {
+               io->flag &= ~EXT4_IO_END_UNWRITTEN;
+               /* Wake up anyone waiting on unwritten extent conversion */
+               wq = ext4_ioend_wq(io->inode);
+               if (atomic_dec_and_test(&EXT4_I(inode)->i_aiodio_unwritten) &&
+                   waitqueue_active(wq)) {
+                       wake_up_all(wq);
+               }
+       }
+
        return ret;
 }
 
@@ -190,6 +191,7 @@ static void ext4_end_bio(struct bio *bio, int error)
        struct inode *inode;
        unsigned long flags;
        int i;
+       sector_t bi_sector = bio->bi_sector;
 
        BUG_ON(!io_end);
        bio->bi_private = NULL;
@@ -207,9 +209,7 @@ static void ext4_end_bio(struct bio *bio, int error)
                if (error)
                        SetPageError(page);
                BUG_ON(!head);
-               if (head->b_size == PAGE_CACHE_SIZE)
-                       clear_buffer_dirty(head);
-               else {
+               if (head->b_size != PAGE_CACHE_SIZE) {
                        loff_t offset;
                        loff_t io_end_offset = io_end->offset + io_end->size;
 
@@ -221,7 +221,6 @@ static void ext4_end_bio(struct bio *bio, int error)
                                        if (error)
                                                buffer_io_error(bh);
 
-                                       clear_buffer_dirty(bh);
                                }
                                if (buffer_delay(bh))
                                        partial_write = 1;
@@ -257,7 +256,7 @@ static void ext4_end_bio(struct bio *bio, int error)
                             (unsigned long long) io_end->offset,
                             (long) io_end->size,
                             (unsigned long long)
-                            bio->bi_sector >> (inode->i_blkbits - 9));
+                            bi_sector >> (inode->i_blkbits - 9));
        }
 
        /* Add the io_end to per-inode completed io list*/
@@ -380,6 +379,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
 
        blocksize = 1 << inode->i_blkbits;
 
+       BUG_ON(!PageLocked(page));
        BUG_ON(PageWriteback(page));
        set_page_writeback(page);
        ClearPageError(page);
@@ -397,12 +397,14 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
        for (bh = head = page_buffers(page), block_start = 0;
             bh != head || !block_start;
             block_start = block_end, bh = bh->b_this_page) {
+
                block_end = block_start + blocksize;
                if (block_start >= len) {
                        clear_buffer_dirty(bh);
                        set_buffer_uptodate(bh);
                        continue;
                }
+               clear_buffer_dirty(bh);
                ret = io_submit_add_bh(io, io_page, inode, wbc, bh);
                if (ret) {
                        /*
index 48ce561..203f9e4 100644 (file)
@@ -77,6 +77,7 @@ static struct dentry *ext4_mount(struct file_system_type *fs_type, int flags,
                       const char *dev_name, void *data);
 static void ext4_destroy_lazyinit_thread(void);
 static void ext4_unregister_li_request(struct super_block *sb);
+static void ext4_clear_request_list(void);
 
 #if !defined(CONFIG_EXT3_FS) && !defined(CONFIG_EXT3_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23)
 static struct file_system_type ext3_fs_type = {
@@ -832,6 +833,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
        ei->i_sync_tid = 0;
        ei->i_datasync_tid = 0;
        atomic_set(&ei->i_ioend_count, 0);
+       atomic_set(&ei->i_aiodio_unwritten, 0);
 
        return &ei->vfs_inode;
 }
@@ -2716,6 +2718,8 @@ static void ext4_unregister_li_request(struct super_block *sb)
        mutex_unlock(&ext4_li_info->li_list_mtx);
 }
 
+static struct task_struct *ext4_lazyinit_task;
+
 /*
  * This is the function where ext4lazyinit thread lives. It walks
  * through the request list searching for next scheduled filesystem.
@@ -2784,6 +2788,10 @@ cont_thread:
                if (time_before(jiffies, next_wakeup))
                        schedule();
                finish_wait(&eli->li_wait_daemon, &wait);
+               if (kthread_should_stop()) {
+                       ext4_clear_request_list();
+                       goto exit_thread;
+               }
        }
 
 exit_thread:
@@ -2808,6 +2816,7 @@ exit_thread:
        wake_up(&eli->li_wait_task);
 
        kfree(ext4_li_info);
+       ext4_lazyinit_task = NULL;
        ext4_li_info = NULL;
        mutex_unlock(&ext4_li_mtx);
 
@@ -2830,11 +2839,10 @@ static void ext4_clear_request_list(void)
 
 static int ext4_run_lazyinit_thread(void)
 {
-       struct task_struct *t;
-
-       t = kthread_run(ext4_lazyinit_thread, ext4_li_info, "ext4lazyinit");
-       if (IS_ERR(t)) {
-               int err = PTR_ERR(t);
+       ext4_lazyinit_task = kthread_run(ext4_lazyinit_thread,
+                                        ext4_li_info, "ext4lazyinit");
+       if (IS_ERR(ext4_lazyinit_task)) {
+               int err = PTR_ERR(ext4_lazyinit_task);
                ext4_clear_request_list();
                del_timer_sync(&ext4_li_info->li_timer);
                kfree(ext4_li_info);
@@ -2985,16 +2993,10 @@ static void ext4_destroy_lazyinit_thread(void)
         * If thread exited earlier
         * there's nothing to be done.
         */
-       if (!ext4_li_info)
+       if (!ext4_li_info || !ext4_lazyinit_task)
                return;
 
-       ext4_clear_request_list();
-
-       while (ext4_li_info->li_task) {
-               wake_up(&ext4_li_info->li_wait_daemon);
-               wait_event(ext4_li_info->li_wait_task,
-                          ext4_li_info->li_task == NULL);
-       }
+       kthread_stop(ext4_lazyinit_task);
 }
 
 static int ext4_fill_super(struct super_block *sb, void *data, int silent)
@@ -3413,6 +3415,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_qcop = &ext4_qctl_operations;
        sb->dq_op = &ext4_quota_operations;
 #endif
+       memcpy(sb->s_uuid, es->s_uuid, sizeof(es->s_uuid));
+
        INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
        mutex_init(&sbi->s_orphan_lock);
        mutex_init(&sbi->s_resize_lock);
@@ -3507,7 +3511,12 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        percpu_counter_set(&sbi->s_dirtyblocks_counter, 0);
 
 no_journal:
-       EXT4_SB(sb)->dio_unwritten_wq = create_workqueue("ext4-dio-unwritten");
+       /*
+        * The maximum number of concurrent works can be high and
+        * concurrency isn't really necessary.  Limit it to 1.
+        */
+       EXT4_SB(sb)->dio_unwritten_wq =
+               alloc_workqueue("ext4-dio-unwritten", WQ_MEM_RECLAIM, 1);
        if (!EXT4_SB(sb)->dio_unwritten_wq) {
                printk(KERN_ERR "EXT4-fs: failed to create DIO workqueue\n");
                goto failed_mount_wq;
@@ -4768,7 +4777,7 @@ static struct file_system_type ext4_fs_type = {
        .fs_flags       = FS_REQUIRES_DEV,
 };
 
-int __init ext4_init_feat_adverts(void)
+static int __init ext4_init_feat_adverts(void)
 {
        struct ext4_features *ef;
        int ret = -ENOMEM;
@@ -4792,23 +4801,44 @@ out:
        return ret;
 }
 
+static void ext4_exit_feat_adverts(void)
+{
+       kobject_put(&ext4_feat->f_kobj);
+       wait_for_completion(&ext4_feat->f_kobj_unregister);
+       kfree(ext4_feat);
+}
+
+/* Shared across all ext4 file systems */
+wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ];
+struct mutex ext4__aio_mutex[EXT4_WQ_HASH_SZ];
+
 static int __init ext4_init_fs(void)
 {
-       int err;
+       int i, err;
 
        ext4_check_flag_values();
+
+       for (i = 0; i < EXT4_WQ_HASH_SZ; i++) {
+               mutex_init(&ext4__aio_mutex[i]);
+               init_waitqueue_head(&ext4__ioend_wq[i]);
+       }
+
        err = ext4_init_pageio();
        if (err)
                return err;
        err = ext4_init_system_zone();
        if (err)
-               goto out5;
+               goto out7;
        ext4_kset = kset_create_and_add("ext4", NULL, fs_kobj);
        if (!ext4_kset)
-               goto out4;
+               goto out6;
        ext4_proc_root = proc_mkdir("fs/ext4", NULL);
+       if (!ext4_proc_root)
+               goto out5;
 
        err = ext4_init_feat_adverts();
+       if (err)
+               goto out4;
 
        err = ext4_init_mballoc();
        if (err)
@@ -4838,12 +4868,14 @@ out1:
 out2:
        ext4_exit_mballoc();
 out3:
-       kfree(ext4_feat);
+       ext4_exit_feat_adverts();
+out4:
        remove_proc_entry("fs/ext4", NULL);
+out5:
        kset_unregister(ext4_kset);
-out4:
+out6:
        ext4_exit_system_zone();
-out5:
+out7:
        ext4_exit_pageio();
        return err;
 }
@@ -4857,6 +4889,7 @@ static void __exit ext4_exit_fs(void)
        destroy_inodecache();
        ext4_exit_xattr();
        ext4_exit_mballoc();
+       ext4_exit_feat_adverts();
        remove_proc_entry("fs/ext4", NULL);
        kset_unregister(ext4_kset);
        ext4_exit_system_zone();
index 86753fe..0e277ec 100644 (file)
@@ -757,8 +757,10 @@ fat_encode_fh(struct dentry *de, __u32 *fh, int *lenp, int connectable)
        struct inode *inode =  de->d_inode;
        u32 ipos_h, ipos_m, ipos_l;
 
-       if (len < 5)
+       if (len < 5) {
+               *lenp = 5;
                return 255; /* no room */
+       }
 
        ipos_h = MSDOS_I(inode)->i_pos >> 8;
        ipos_m = (MSDOS_I(inode)->i_pos & 0xf0) << 24;
index f88f752..adae3fb 100644 (file)
@@ -43,7 +43,7 @@ static int vfat_revalidate_shortname(struct dentry *dentry)
 
 static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
-       if (nd->flags & LOOKUP_RCU)
+       if (nd && nd->flags & LOOKUP_RCU)
                return -ECHILD;
 
        /* This is not negative dentry. Always valid. */
@@ -54,7 +54,7 @@ static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd)
 
 static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd)
 {
-       if (nd->flags & LOOKUP_RCU)
+       if (nd && nd->flags & LOOKUP_RCU)
                return -ECHILD;
 
        /*
index ecc8b39..6c82e5b 100644 (file)
@@ -131,7 +131,7 @@ SYSCALL_DEFINE2(dup2, unsigned int, oldfd, unsigned int, newfd)
 SYSCALL_DEFINE1(dup, unsigned int, fildes)
 {
        int ret = -EBADF;
-       struct file *file = fget(fildes);
+       struct file *file = fget_raw(fildes);
 
        if (file) {
                ret = get_unused_fd();
@@ -426,15 +426,35 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
        return err;
 }
 
+static int check_fcntl_cmd(unsigned cmd)
+{
+       switch (cmd) {
+       case F_DUPFD:
+       case F_DUPFD_CLOEXEC:
+       case F_GETFD:
+       case F_SETFD:
+       case F_GETFL:
+               return 1;
+       }
+       return 0;
+}
+
 SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
 {      
        struct file *filp;
        long err = -EBADF;
 
-       filp = fget(fd);
+       filp = fget_raw(fd);
        if (!filp)
                goto out;
 
+       if (unlikely(filp->f_mode & FMODE_PATH)) {
+               if (!check_fcntl_cmd(cmd)) {
+                       fput(filp);
+                       goto out;
+               }
+       }
+
        err = security_file_fcntl(filp, cmd, arg);
        if (err) {
                fput(filp);
@@ -456,10 +476,17 @@ SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
        long err;
 
        err = -EBADF;
-       filp = fget(fd);
+       filp = fget_raw(fd);
        if (!filp)
                goto out;
 
+       if (unlikely(filp->f_mode & FMODE_PATH)) {
+               if (!check_fcntl_cmd(cmd)) {
+                       fput(filp);
+                       goto out;
+               }
+       }
+
        err = security_file_fcntl(filp, cmd, arg);
        if (err) {
                fput(filp);
@@ -808,14 +835,14 @@ static int __init fcntl_init(void)
         * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY
         * is defined as O_NONBLOCK on some platforms and not on others.
         */
-       BUILD_BUG_ON(18 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32(
+       BUILD_BUG_ON(19 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32(
                O_RDONLY        | O_WRONLY      | O_RDWR        |
                O_CREAT         | O_EXCL        | O_NOCTTY      |
                O_TRUNC         | O_APPEND      | /* O_NONBLOCK | */
                __O_SYNC        | O_DSYNC       | FASYNC        |
                O_DIRECT        | O_LARGEFILE   | O_DIRECTORY   |
                O_NOFOLLOW      | O_NOATIME     | O_CLOEXEC     |
-               FMODE_EXEC
+               __FMODE_EXEC    | O_PATH
                ));
 
        fasync_cache = kmem_cache_create("fasync_cache",
diff --git a/fs/fhandle.c b/fs/fhandle.c
new file mode 100644 (file)
index 0000000..bf93ad2
--- /dev/null
@@ -0,0 +1,265 @@
+#include <linux/syscalls.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/exportfs.h>
+#include <linux/fs_struct.h>
+#include <linux/fsnotify.h>
+#include <asm/uaccess.h>
+#include "internal.h"
+
+static long do_sys_name_to_handle(struct path *path,
+                                 struct file_handle __user *ufh,
+                                 int __user *mnt_id)
+{
+       long retval;
+       struct file_handle f_handle;
+       int handle_dwords, handle_bytes;
+       struct file_handle *handle = NULL;
+
+       /*
+        * We need t make sure wether the file system
+        * support decoding of the file handle
+        */
+       if (!path->mnt->mnt_sb->s_export_op ||
+           !path->mnt->mnt_sb->s_export_op->fh_to_dentry)
+               return -EOPNOTSUPP;
+
+       if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
+               return -EFAULT;
+
+       if (f_handle.handle_bytes > MAX_HANDLE_SZ)
+               return -EINVAL;
+
+       handle = kmalloc(sizeof(struct file_handle) + f_handle.handle_bytes,
+                        GFP_KERNEL);
+       if (!handle)
+               return -ENOMEM;
+
+       /* convert handle size to  multiple of sizeof(u32) */
+       handle_dwords = f_handle.handle_bytes >> 2;
+
+       /* we ask for a non connected handle */
+       retval = exportfs_encode_fh(path->dentry,
+                                   (struct fid *)handle->f_handle,
+                                   &handle_dwords,  0);
+       handle->handle_type = retval;
+       /* convert handle size to bytes */
+       handle_bytes = handle_dwords * sizeof(u32);
+       handle->handle_bytes = handle_bytes;
+       if ((handle->handle_bytes > f_handle.handle_bytes) ||
+           (retval == 255) || (retval == -ENOSPC)) {
+               /* As per old exportfs_encode_fh documentation
+                * we could return ENOSPC to indicate overflow
+                * But file system returned 255 always. So handle
+                * both the values
+                */
+               /*
+                * set the handle size to zero so we copy only
+                * non variable part of the file_handle
+                */
+               handle_bytes = 0;
+               retval = -EOVERFLOW;
+       } else
+               retval = 0;
+       /* copy the mount id */
+       if (copy_to_user(mnt_id, &path->mnt->mnt_id, sizeof(*mnt_id)) ||
+           copy_to_user(ufh, handle,
+                        sizeof(struct file_handle) + handle_bytes))
+               retval = -EFAULT;
+       kfree(handle);
+       return retval;
+}
+
+/**
+ * sys_name_to_handle_at: convert name to handle
+ * @dfd: directory relative to which name is interpreted if not absolute
+ * @name: name that should be converted to handle.
+ * @handle: resulting file handle
+ * @mnt_id: mount id of the file system containing the file
+ * @flag: flag value to indicate whether to follow symlink or not
+ *
+ * @handle->handle_size indicate the space available to store the
+ * variable part of the file handle in bytes. If there is not
+ * enough space, the field is updated to return the minimum
+ * value required.
+ */
+SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
+               struct file_handle __user *, handle, int __user *, mnt_id,
+               int, flag)
+{
+       struct path path;
+       int lookup_flags;
+       int err;
+
+       if ((flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
+               return -EINVAL;
+
+       lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0;
+       if (flag & AT_EMPTY_PATH)
+               lookup_flags |= LOOKUP_EMPTY;
+       err = user_path_at(dfd, name, lookup_flags, &path);
+       if (!err) {
+               err = do_sys_name_to_handle(&path, handle, mnt_id);
+               path_put(&path);
+       }
+       return err;
+}
+
+static struct vfsmount *get_vfsmount_from_fd(int fd)
+{
+       struct path path;
+
+       if (fd == AT_FDCWD) {
+               struct fs_struct *fs = current->fs;
+               spin_lock(&fs->lock);
+               path = fs->pwd;
+               mntget(path.mnt);
+               spin_unlock(&fs->lock);
+       } else {
+               int fput_needed;
+               struct file *file = fget_light(fd, &fput_needed);
+               if (!file)
+                       return ERR_PTR(-EBADF);
+               path = file->f_path;
+               mntget(path.mnt);
+               fput_light(file, fput_needed);
+       }
+       return path.mnt;
+}
+
+static int vfs_dentry_acceptable(void *context, struct dentry *dentry)
+{
+       return 1;
+}
+
+static int do_handle_to_path(int mountdirfd, struct file_handle *handle,
+                            struct path *path)
+{
+       int retval = 0;
+       int handle_dwords;
+
+       path->mnt = get_vfsmount_from_fd(mountdirfd);
+       if (IS_ERR(path->mnt)) {
+               retval = PTR_ERR(path->mnt);
+               goto out_err;
+       }
+       /* change the handle size to multiple of sizeof(u32) */
+       handle_dwords = handle->handle_bytes >> 2;
+       path->dentry = exportfs_decode_fh(path->mnt,
+                                         (struct fid *)handle->f_handle,
+                                         handle_dwords, handle->handle_type,
+                                         vfs_dentry_acceptable, NULL);
+       if (IS_ERR(path->dentry)) {
+               retval = PTR_ERR(path->dentry);
+               goto out_mnt;
+       }
+       return 0;
+out_mnt:
+       mntput(path->mnt);
+out_err:
+       return retval;
+}
+
+static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
+                  struct path *path)
+{
+       int retval = 0;
+       struct file_handle f_handle;
+       struct file_handle *handle = NULL;
+
+       /*
+        * With handle we don't look at the execute bit on the
+        * the directory. Ideally we would like CAP_DAC_SEARCH.
+        * But we don't have that
+        */
+       if (!capable(CAP_DAC_READ_SEARCH)) {
+               retval = -EPERM;
+               goto out_err;
+       }
+       if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle))) {
+               retval = -EFAULT;
+               goto out_err;
+       }
+       if ((f_handle.handle_bytes > MAX_HANDLE_SZ) ||
+           (f_handle.handle_bytes == 0)) {
+               retval = -EINVAL;
+               goto out_err;
+       }
+       handle = kmalloc(sizeof(struct file_handle) + f_handle.handle_bytes,
+                        GFP_KERNEL);
+       if (!handle) {
+               retval = -ENOMEM;
+               goto out_err;
+       }
+       /* copy the full handle */
+       if (copy_from_user(handle, ufh,
+                          sizeof(struct file_handle) +
+                          f_handle.handle_bytes)) {
+               retval = -EFAULT;
+               goto out_handle;
+       }
+
+       retval = do_handle_to_path(mountdirfd, handle, path);
+
+out_handle:
+       kfree(handle);
+out_err:
+       return retval;
+}
+
+long do_handle_open(int mountdirfd,
+                   struct file_handle __user *ufh, int open_flag)
+{
+       long retval = 0;
+       struct path path;
+       struct file *file;
+       int fd;
+
+       retval = handle_to_path(mountdirfd, ufh, &path);
+       if (retval)
+               return retval;
+
+       fd = get_unused_fd_flags(open_flag);
+       if (fd < 0) {
+               path_put(&path);
+               return fd;
+       }
+       file = file_open_root(path.dentry, path.mnt, "", open_flag);
+       if (IS_ERR(file)) {
+               put_unused_fd(fd);
+               retval =  PTR_ERR(file);
+       } else {
+               retval = fd;
+               fsnotify_open(file);
+               fd_install(fd, file);
+       }
+       path_put(&path);
+       return retval;
+}
+
+/**
+ * sys_open_by_handle_at: Open the file handle
+ * @mountdirfd: directory file descriptor
+ * @handle: file handle to be opened
+ * @flag: open flags.
+ *
+ * @mountdirfd indicate the directory file descriptor
+ * of the mount point. file handle is decoded relative
+ * to the vfsmount pointed by the @mountdirfd. @flags
+ * value is same as the open(2) flags.
+ */
+SYSCALL_DEFINE3(open_by_handle_at, int, mountdirfd,
+               struct file_handle __user *, handle,
+               int, flags)
+{
+       long ret;
+
+       if (force_o_largefile())
+               flags |= O_LARGEFILE;
+
+       ret = do_handle_open(mountdirfd, handle, flags);
+       return ret;
+}
index c3e89ad..74a9544 100644 (file)
@@ -125,13 +125,13 @@ struct file *get_empty_filp(void)
                goto fail;
 
        percpu_counter_inc(&nr_files);
+       f->f_cred = get_cred(cred);
        if (security_file_alloc(f))
                goto fail_sec;
 
        INIT_LIST_HEAD(&f->f_u.fu_list);
        atomic_long_set(&f->f_count, 1);
        rwlock_init(&f->f_owner.lock);
-       f->f_cred = get_cred(cred);
        spin_lock_init(&f->f_lock);
        eventpoll_init_file(f);
        /* f->f_version: 0 */
@@ -276,11 +276,10 @@ struct file *fget(unsigned int fd)
        rcu_read_lock();
        file = fcheck_files(files, fd);
        if (file) {
-               if (!atomic_long_inc_not_zero(&file->f_count)) {
-                       /* File object ref couldn't be taken */
-                       rcu_read_unlock();
-                       return NULL;
-               }
+               /* File object ref couldn't be taken */
+               if (file->f_mode & FMODE_PATH ||
+                   !atomic_long_inc_not_zero(&file->f_count))
+                       file = NULL;
        }
        rcu_read_unlock();
 
@@ -289,6 +288,25 @@ struct file *fget(unsigned int fd)
 
 EXPORT_SYMBOL(fget);
 
+struct file *fget_raw(unsigned int fd)
+{
+       struct file *file;
+       struct files_struct *files = current->files;
+
+       rcu_read_lock();
+       file = fcheck_files(files, fd);
+       if (file) {
+               /* File object ref couldn't be taken */
+               if (!atomic_long_inc_not_zero(&file->f_count))
+                       file = NULL;
+       }
+       rcu_read_unlock();
+
+       return file;
+}
+
+EXPORT_SYMBOL(fget_raw);
+
 /*
  * Lightweight file lookup - no refcnt increment if fd table isn't shared.
  *
@@ -310,6 +328,33 @@ struct file *fget_light(unsigned int fd, int *fput_needed)
        struct file *file;
        struct files_struct *files = current->files;
 
+       *fput_needed = 0;
+       if (atomic_read(&files->count) == 1) {
+               file = fcheck_files(files, fd);
+               if (file && (file->f_mode & FMODE_PATH))
+                       file = NULL;
+       } else {
+               rcu_read_lock();
+               file = fcheck_files(files, fd);
+               if (file) {
+                       if (!(file->f_mode & FMODE_PATH) &&
+                           atomic_long_inc_not_zero(&file->f_count))
+                               *fput_needed = 1;
+                       else
+                               /* Didn't get the reference, someone's freed */
+                               file = NULL;
+               }
+               rcu_read_unlock();
+       }
+
+       return file;
+}
+
+struct file *fget_raw_light(unsigned int fd, int *fput_needed)
+{
+       struct file *file;
+       struct files_struct *files = current->files;
+
        *fput_needed = 0;
        if (atomic_read(&files->count) == 1) {
                file = fcheck_files(files, fd);
index bfed844..8bd0ef9 100644 (file)
@@ -158,7 +158,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
 {
        struct inode *inode;
 
-       if (nd->flags & LOOKUP_RCU)
+       if (nd && nd->flags & LOOKUP_RCU)
                return -ECHILD;
 
        inode = entry->d_inode;
@@ -1283,8 +1283,11 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
        if (err)
                return err;
 
-       if ((attr->ia_valid & ATTR_OPEN) && fc->atomic_o_trunc)
-               return 0;
+       if (attr->ia_valid & ATTR_OPEN) {
+               if (fc->atomic_o_trunc)
+                       return 0;
+               file = NULL;
+       }
 
        if (attr->ia_valid & ATTR_SIZE)
                is_truncate = true;
index 95da1bc..9e0832d 100644 (file)
@@ -86,18 +86,52 @@ struct fuse_file *fuse_file_get(struct fuse_file *ff)
        return ff;
 }
 
+static void fuse_release_async(struct work_struct *work)
+{
+       struct fuse_req *req;
+       struct fuse_conn *fc;
+       struct path path;
+
+       req = container_of(work, struct fuse_req, misc.release.work);
+       path = req->misc.release.path;
+       fc = get_fuse_conn(path.dentry->d_inode);
+
+       fuse_put_request(fc, req);
+       path_put(&path);
+}
+
 static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req)
 {
-       path_put(&req->misc.release.path);
+       if (fc->destroy_req) {
+               /*
+                * If this is a fuseblk mount, then it's possible that
+                * releasing the path will result in releasing the
+                * super block and sending the DESTROY request.  If
+                * the server is single threaded, this would hang.
+                * For this reason do the path_put() in a separate
+                * thread.
+                */
+               atomic_inc(&req->count);
+               INIT_WORK(&req->misc.release.work, fuse_release_async);
+               schedule_work(&req->misc.release.work);
+       } else {
+               path_put(&req->misc.release.path);
+       }
 }
 
-static void fuse_file_put(struct fuse_file *ff)
+static void fuse_file_put(struct fuse_file *ff, bool sync)
 {
        if (atomic_dec_and_test(&ff->count)) {
                struct fuse_req *req = ff->reserved_req;
 
-               req->end = fuse_release_end;
-               fuse_request_send_background(ff->fc, req);
+               if (sync) {
+                       fuse_request_send(ff->fc, req);
+                       path_put(&req->misc.release.path);
+                       fuse_put_request(ff->fc, req);
+               } else {
+                       req->end = fuse_release_end;
+                       fuse_request_send_background(ff->fc, req);
+               }
                kfree(ff);
        }
 }
@@ -219,8 +253,12 @@ void fuse_release_common(struct file *file, int opcode)
         * Normally this will send the RELEASE request, however if
         * some asynchronous READ or WRITE requests are outstanding,
         * the sending will be delayed.
+        *
+        * Make the release synchronous if this is a fuseblk mount,
+        * synchronous RELEASE is allowed (and desirable) in this case
+        * because the server can be trusted not to screw up.
         */
-       fuse_file_put(ff);
+       fuse_file_put(ff, ff->fc->destroy_req != NULL);
 }
 
 static int fuse_open(struct inode *inode, struct file *file)
@@ -558,7 +596,7 @@ static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req)
                page_cache_release(page);
        }
        if (req->ff)
-               fuse_file_put(req->ff);
+               fuse_file_put(req->ff, false);
 }
 
 static void fuse_send_readpages(struct fuse_req *req, struct file *file)
@@ -1137,7 +1175,7 @@ static ssize_t fuse_direct_write(struct file *file, const char __user *buf,
 static void fuse_writepage_free(struct fuse_conn *fc, struct fuse_req *req)
 {
        __free_page(req->pages[0]);
-       fuse_file_put(req->ff);
+       fuse_file_put(req->ff, false);
 }
 
 static void fuse_writepage_finish(struct fuse_conn *fc, struct fuse_req *req)
index ae5744a..d428694 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/rwsem.h>
 #include <linux/rbtree.h>
 #include <linux/poll.h>
+#include <linux/workqueue.h>
 
 /** Max number of pages that can be used in a single read request */
 #define FUSE_MAX_PAGES_PER_REQ 32
@@ -262,7 +263,10 @@ struct fuse_req {
        /** Data for asynchronous requests */
        union {
                struct {
-                       struct fuse_release_in in;
+                       union {
+                               struct fuse_release_in in;
+                               struct work_struct work;
+                       };
                        struct path path;
                } release;
                struct fuse_init_in init_in;
index 9e3f68c..051b1a0 100644 (file)
@@ -637,8 +637,10 @@ static int fuse_encode_fh(struct dentry *dentry, u32 *fh, int *max_len,
        u64 nodeid;
        u32 generation;
 
-       if (*max_len < len)
+       if (*max_len < len) {
+               *max_len = len;
                return  255;
+       }
 
        nodeid = get_fuse_inode(inode)->nodeid;
        generation = inode->i_generation;
index 4a45633..0da8da2 100644 (file)
@@ -44,7 +44,7 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
        int error;
        int had_lock = 0;
 
-       if (nd->flags & LOOKUP_RCU)
+       if (nd && nd->flags & LOOKUP_RCU)
                return -ECHILD;
 
        parent = dget_parent(dentry);
index 9023db8..b5a5e60 100644 (file)
@@ -36,9 +36,13 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *p, int *len,
        struct super_block *sb = inode->i_sb;
        struct gfs2_inode *ip = GFS2_I(inode);
 
-       if (*len < GFS2_SMALL_FH_SIZE ||
-           (connectable && *len < GFS2_LARGE_FH_SIZE))
+       if (connectable && (*len < GFS2_LARGE_FH_SIZE)) {
+               *len = GFS2_LARGE_FH_SIZE;
                return 255;
+       } else if (*len < GFS2_SMALL_FH_SIZE) {
+               *len = GFS2_SMALL_FH_SIZE;
+               return 255;
+       }
 
        fh[0] = cpu_to_be32(ip->i_no_formal_ino >> 32);
        fh[1] = cpu_to_be32(ip->i_no_formal_ino & 0xFFFFFFFF);
index 08a8beb..7cd9a5a 100644 (file)
@@ -1779,11 +1779,11 @@ int __init gfs2_glock_init(void)
 #endif
 
        glock_workqueue = alloc_workqueue("glock_workqueue", WQ_MEM_RECLAIM |
-                                         WQ_HIGHPRI | WQ_FREEZEABLE, 0);
+                                         WQ_HIGHPRI | WQ_FREEZABLE, 0);
        if (IS_ERR(glock_workqueue))
                return PTR_ERR(glock_workqueue);
        gfs2_delete_workqueue = alloc_workqueue("delete_workqueue",
-                                               WQ_MEM_RECLAIM | WQ_FREEZEABLE,
+                                               WQ_MEM_RECLAIM | WQ_FREEZABLE,
                                                0);
        if (IS_ERR(gfs2_delete_workqueue)) {
                destroy_workqueue(glock_workqueue);
index ebef7ab..72c31a3 100644 (file)
@@ -59,14 +59,7 @@ static void gfs2_init_gl_aspace_once(void *foo)
        struct address_space *mapping = (struct address_space *)(gl + 1);
 
        gfs2_init_glock_once(gl);
-       memset(mapping, 0, sizeof(*mapping));
-       INIT_RADIX_TREE(&mapping->page_tree, GFP_ATOMIC);
-       spin_lock_init(&mapping->tree_lock);
-       spin_lock_init(&mapping->i_mmap_lock);
-       INIT_LIST_HEAD(&mapping->private_list);
-       spin_lock_init(&mapping->private_lock);
-       INIT_RAW_PRIO_TREE_ROOT(&mapping->i_mmap);
-       INIT_LIST_HEAD(&mapping->i_mmap_nonlinear);
+       address_space_init_once(mapping);
 }
 
 /**
@@ -144,7 +137,7 @@ static int __init init_gfs2_fs(void)
 
        error = -ENOMEM;
        gfs_recovery_wq = alloc_workqueue("gfs_recovery",
-                                         WQ_MEM_RECLAIM | WQ_FREEZEABLE, 0);
+                                         WQ_MEM_RECLAIM | WQ_FREEZABLE, 0);
        if (!gfs_recovery_wq)
                goto fail_wq;
 
index afa66aa..b4d70b1 100644 (file)
@@ -238,46 +238,22 @@ static int hfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 }
 
 /*
- * hfs_unlink()
+ * hfs_remove()
  *
- * This is the unlink() entry in the inode_operations structure for
- * regular HFS directories.  The purpose is to delete an existing
- * file, given the inode for the parent directory and the name
- * (and its length) of the existing file.
- */
-static int hfs_unlink(struct inode *dir, struct dentry *dentry)
-{
-       struct inode *inode;
-       int res;
-
-       inode = dentry->d_inode;
-       res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name);
-       if (res)
-               return res;
-
-       drop_nlink(inode);
-       hfs_delete_inode(inode);
-       inode->i_ctime = CURRENT_TIME_SEC;
-       mark_inode_dirty(inode);
-
-       return res;
-}
-
-/*
- * hfs_rmdir()
+ * This serves as both unlink() and rmdir() in the inode_operations
+ * structure for regular HFS directories.  The purpose is to delete
+ * an existing child, given the inode for the parent directory and
+ * the name (and its length) of the existing directory.
  *
- * This is the rmdir() entry in the inode_operations structure for
- * regular HFS directories.  The purpose is to delete an existing
- * directory, given the inode for the parent directory and the name
- * (and its length) of the existing directory.
+ * HFS does not have hardlinks, so both rmdir and unlink set the
+ * link count to 0.  The only difference is the emptiness check.
  */
-static int hfs_rmdir(struct inode *dir, struct dentry *dentry)
+static int hfs_remove(struct inode *dir, struct dentry *dentry)
 {
-       struct inode *inode;
+       struct inode *inode = dentry->d_inode;
        int res;
 
-       inode = dentry->d_inode;
-       if (inode->i_size != 2)
+       if (S_ISDIR(inode->i_mode) && inode->i_size != 2)
                return -ENOTEMPTY;
        res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name);
        if (res)
@@ -307,7 +283,7 @@ static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
        /* Unlink destination if it already exists */
        if (new_dentry->d_inode) {
-               res = hfs_unlink(new_dir, new_dentry);
+               res = hfs_remove(new_dir, new_dentry);
                if (res)
                        return res;
        }
@@ -332,9 +308,9 @@ const struct file_operations hfs_dir_operations = {
 const struct inode_operations hfs_dir_inode_operations = {
        .create         = hfs_create,
        .lookup         = hfs_lookup,
-       .unlink         = hfs_unlink,
+       .unlink         = hfs_remove,
        .mkdir          = hfs_mkdir,
-       .rmdir          = hfs_rmdir,
+       .rmdir          = hfs_remove,
        .rename         = hfs_rename,
        .setattr        = hfs_inode_setattr,
 };
index 52a0bca..b1991a2 100644 (file)
@@ -397,8 +397,8 @@ int hfsplus_file_extend(struct inode *inode)
        u32 start, len, goal;
        int res;
 
-       if (sbi->total_blocks - sbi->free_blocks + 8 >
-                       sbi->alloc_file->i_size * 8) {
+       if (sbi->alloc_file->i_size * 8 <
+           sbi->total_blocks - sbi->free_blocks + 8) {
                /* extend alloc file */
                printk(KERN_ERR "hfs: extend alloc file! "
                                "(%llu,%u,%u)\n",
index d66ad11..40ad88c 100644 (file)
@@ -134,7 +134,7 @@ int hfs_part_find(struct super_block *sb,
        res = hfsplus_submit_bio(sb->s_bdev, *part_start + HFS_PMAP_BLK,
                                 data, READ);
        if (res)
-               return res;
+               goto out;
 
        switch (be16_to_cpu(*((__be16 *)data))) {
        case HFS_OLD_PMAP_MAGIC:
@@ -147,7 +147,7 @@ int hfs_part_find(struct super_block *sb,
                res = -ENOENT;
                break;
        }
-
+out:
        kfree(data);
        return res;
 }
index 9a3b479..b49b555 100644 (file)
@@ -338,20 +338,22 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        struct inode *root, *inode;
        struct qstr str;
        struct nls_table *nls = NULL;
-       int err = -EINVAL;
+       int err;
 
+       err = -EINVAL;
        sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
        if (!sbi)
-               return -ENOMEM;
+               goto out;
 
        sb->s_fs_info = sbi;
        mutex_init(&sbi->alloc_mutex);
        mutex_init(&sbi->vh_mutex);
        hfsplus_fill_defaults(sbi);
+
+       err = -EINVAL;
        if (!hfsplus_parse_options(data, sbi)) {
                printk(KERN_ERR "hfs: unable to parse mount options\n");
-               err = -EINVAL;
-               goto cleanup;
+               goto out_unload_nls;
        }
 
        /* temporarily use utf8 to correctly find the hidden dir below */
@@ -359,16 +361,14 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        sbi->nls = load_nls("utf8");
        if (!sbi->nls) {
                printk(KERN_ERR "hfs: unable to load nls for utf8\n");
-               err = -EINVAL;
-               goto cleanup;
+               goto out_unload_nls;
        }
 
        /* Grab the volume header */
        if (hfsplus_read_wrapper(sb)) {
                if (!silent)
                        printk(KERN_WARNING "hfs: unable to find HFS+ superblock\n");
-               err = -EINVAL;
-               goto cleanup;
+               goto out_unload_nls;
        }
        vhdr = sbi->s_vhdr;
 
@@ -377,7 +377,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        if (be16_to_cpu(vhdr->version) < HFSPLUS_MIN_VERSION ||
            be16_to_cpu(vhdr->version) > HFSPLUS_CURRENT_VERSION) {
                printk(KERN_ERR "hfs: wrong filesystem version\n");
-               goto cleanup;
+               goto out_free_vhdr;
        }
        sbi->total_blocks = be32_to_cpu(vhdr->total_blocks);
        sbi->free_blocks = be32_to_cpu(vhdr->free_blocks);
@@ -421,19 +421,19 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        sbi->ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID);
        if (!sbi->ext_tree) {
                printk(KERN_ERR "hfs: failed to load extents file\n");
-               goto cleanup;
+               goto out_free_vhdr;
        }
        sbi->cat_tree = hfs_btree_open(sb, HFSPLUS_CAT_CNID);
        if (!sbi->cat_tree) {
                printk(KERN_ERR "hfs: failed to load catalog file\n");
-               goto cleanup;
+               goto out_close_ext_tree;
        }
 
        inode = hfsplus_iget(sb, HFSPLUS_ALLOC_CNID);
        if (IS_ERR(inode)) {
                printk(KERN_ERR "hfs: failed to load allocation file\n");
                err = PTR_ERR(inode);
-               goto cleanup;
+               goto out_close_cat_tree;
        }
        sbi->alloc_file = inode;
 
@@ -442,14 +442,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        if (IS_ERR(root)) {
                printk(KERN_ERR "hfs: failed to load root directory\n");
                err = PTR_ERR(root);
-               goto cleanup;
-       }
-       sb->s_d_op = &hfsplus_dentry_operations;
-       sb->s_root = d_alloc_root(root);
-       if (!sb->s_root) {
-               iput(root);
-               err = -ENOMEM;
-               goto cleanup;
+               goto out_put_alloc_file;
        }
 
        str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1;
@@ -459,46 +452,69 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        if (!hfs_brec_read(&fd, &entry, sizeof(entry))) {
                hfs_find_exit(&fd);
                if (entry.type != cpu_to_be16(HFSPLUS_FOLDER))
-                       goto cleanup;
+                       goto out_put_root;
                inode = hfsplus_iget(sb, be32_to_cpu(entry.folder.id));
                if (IS_ERR(inode)) {
                        err = PTR_ERR(inode);
-                       goto cleanup;
+                       goto out_put_root;
                }
                sbi->hidden_dir = inode;
        } else
                hfs_find_exit(&fd);
 
-       if (sb->s_flags & MS_RDONLY)
-               goto out;
+       if (!(sb->s_flags & MS_RDONLY)) {
+               /*
+                * H+LX == hfsplusutils, H+Lx == this driver, H+lx is unused
+                * all three are registered with Apple for our use
+                */
+               vhdr->last_mount_vers = cpu_to_be32(HFSP_MOUNT_VERSION);
+               vhdr->modify_date = hfsp_now2mt();
+               be32_add_cpu(&vhdr->write_count, 1);
+               vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT);
+               vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT);
+               hfsplus_sync_fs(sb, 1);
 
-       /* H+LX == hfsplusutils, H+Lx == this driver, H+lx is unused
-        * all three are registered with Apple for our use
-        */
-       vhdr->last_mount_vers = cpu_to_be32(HFSP_MOUNT_VERSION);
-       vhdr->modify_date = hfsp_now2mt();
-       be32_add_cpu(&vhdr->write_count, 1);
-       vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT);
-       vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT);
-       hfsplus_sync_fs(sb, 1);
-
-       if (!sbi->hidden_dir) {
-               mutex_lock(&sbi->vh_mutex);
-               sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR);
-               hfsplus_create_cat(sbi->hidden_dir->i_ino, sb->s_root->d_inode,
-                                  &str, sbi->hidden_dir);
-               mutex_unlock(&sbi->vh_mutex);
-
-               hfsplus_mark_inode_dirty(sbi->hidden_dir, HFSPLUS_I_CAT_DIRTY);
+               if (!sbi->hidden_dir) {
+                       mutex_lock(&sbi->vh_mutex);
+                       sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR);
+                       hfsplus_create_cat(sbi->hidden_dir->i_ino, root, &str,
+                                          sbi->hidden_dir);
+                       mutex_unlock(&sbi->vh_mutex);
+
+                       hfsplus_mark_inode_dirty(sbi->hidden_dir,
+                                                HFSPLUS_I_CAT_DIRTY);
+               }
        }
-out:
+
+       sb->s_d_op = &hfsplus_dentry_operations;
+       sb->s_root = d_alloc_root(root);
+       if (!sb->s_root) {
+               err = -ENOMEM;
+               goto out_put_hidden_dir;
+       }
+
        unload_nls(sbi->nls);
        sbi->nls = nls;
        return 0;
 
-cleanup:
-       hfsplus_put_super(sb);
+out_put_hidden_dir:
+       iput(sbi->hidden_dir);
+out_put_root:
+       iput(sbi->alloc_file);
+out_put_alloc_file:
+       iput(sbi->alloc_file);
+out_close_cat_tree:
+       hfs_btree_close(sbi->cat_tree);
+out_close_ext_tree:
+       hfs_btree_close(sbi->ext_tree);
+out_free_vhdr:
+       kfree(sbi->s_vhdr);
+       kfree(sbi->s_backup_vhdr);
+out_unload_nls:
+       unload_nls(sbi->nls);
        unload_nls(nls);
+       kfree(sbi);
+out:
        return err;
 }
 
index 1962317..3031d81 100644 (file)
@@ -167,7 +167,7 @@ reread:
                break;
        case cpu_to_be16(HFSP_WRAP_MAGIC):
                if (!hfsplus_read_mdb(sbi->s_vhdr, &wd))
-                       goto out;
+                       goto out_free_backup_vhdr;
                wd.ablk_size >>= HFSPLUS_SECTOR_SHIFT;
                part_start += wd.ablk_start + wd.embed_start * wd.ablk_size;
                part_size = wd.embed_count * wd.ablk_size;
@@ -179,7 +179,7 @@ reread:
                 * (should do this only for cdrom/loop though)
                 */
                if (hfs_part_find(sb, &part_start, &part_size))
-                       goto out;
+                       goto out_free_backup_vhdr;
                goto reread;
        }
 
index da85e56..9910c03 100644 (file)
@@ -84,16 +84,13 @@ static struct hlist_head *inode_hashtable __read_mostly;
 DEFINE_SPINLOCK(inode_lock);
 
 /*
- * iprune_sem provides exclusion between the kswapd or try_to_free_pages
- * icache shrinking path, and the umount path.  Without this exclusion,
- * by the time prune_icache calls iput for the inode whose pages it has
- * been invalidating, or by the time it calls clear_inode & destroy_inode
- * from its final dispose_list, the struct super_block they refer to
- * (for inode->i_sb->s_op) may already have been freed and reused.
+ * iprune_sem provides exclusion between the icache shrinking and the
+ * umount path.
  *
- * We make this an rwsem because the fastpath is icache shrinking. In
- * some cases a filesystem may be doing a significant amount of work in
- * its inode reclaim code, so this should improve parallelism.
+ * We don't actually need it to protect anything in the umount path,
+ * but only need to cycle through it to make sure any inode that
+ * prune_icache took off the LRU list has been fully torn down by the
+ * time we are past evict_inodes.
  */
 static DECLARE_RWSEM(iprune_sem);
 
@@ -295,6 +292,20 @@ static void destroy_inode(struct inode *inode)
                call_rcu(&inode->i_rcu, i_callback);
 }
 
+void address_space_init_once(struct address_space *mapping)
+{
+       memset(mapping, 0, sizeof(*mapping));
+       INIT_RADIX_TREE(&mapping->page_tree, GFP_ATOMIC);
+       spin_lock_init(&mapping->tree_lock);
+       spin_lock_init(&mapping->i_mmap_lock);
+       INIT_LIST_HEAD(&mapping->private_list);
+       spin_lock_init(&mapping->private_lock);
+       INIT_RAW_PRIO_TREE_ROOT(&mapping->i_mmap);
+       INIT_LIST_HEAD(&mapping->i_mmap_nonlinear);
+       mutex_init(&mapping->unmap_mutex);
+}
+EXPORT_SYMBOL(address_space_init_once);
+
 /*
  * These are initializations that only need to be done
  * once, because the fields are idempotent across use
@@ -308,13 +319,7 @@ void inode_init_once(struct inode *inode)
        INIT_LIST_HEAD(&inode->i_devices);
        INIT_LIST_HEAD(&inode->i_wb_list);
        INIT_LIST_HEAD(&inode->i_lru);
-       INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC);
-       spin_lock_init(&inode->i_data.tree_lock);
-       spin_lock_init(&inode->i_data.i_mmap_lock);
-       INIT_LIST_HEAD(&inode->i_data.private_list);
-       spin_lock_init(&inode->i_data.private_lock);
-       INIT_RAW_PRIO_TREE_ROOT(&inode->i_data.i_mmap);
-       INIT_LIST_HEAD(&inode->i_data.i_mmap_nonlinear);
+       address_space_init_once(&inode->i_data);
        i_size_ordered_init(inode);
 #ifdef CONFIG_FSNOTIFY
        INIT_HLIST_HEAD(&inode->i_fsnotify_marks);
@@ -508,17 +513,12 @@ void evict_inodes(struct super_block *sb)
        struct inode *inode, *next;
        LIST_HEAD(dispose);
 
-       down_write(&iprune_sem);
-
        spin_lock(&inode_lock);
        list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) {
                if (atomic_read(&inode->i_count))
                        continue;
-
-               if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) {
-                       WARN_ON(1);
+               if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE))
                        continue;
-               }
 
                inode->i_state |= I_FREEING;
 
@@ -534,28 +534,40 @@ void evict_inodes(struct super_block *sb)
        spin_unlock(&inode_lock);
 
        dispose_list(&dispose);
+
+       /*
+        * Cycle through iprune_sem to make sure any inode that prune_icache
+        * moved off the list before we took the lock has been fully torn
+        * down.
+        */
+       down_write(&iprune_sem);
        up_write(&iprune_sem);
 }
 
 /**
  * invalidate_inodes   - attempt to free all inodes on a superblock
  * @sb:                superblock to operate on
+ * @kill_dirty: flag to guide handling of dirty inodes
  *
  * Attempts to free all inodes for a given superblock.  If there were any
  * busy inodes return a non-zero value, else zero.
+ * If @kill_dirty is set, discard dirty inodes too, otherwise treat
+ * them as busy.
  */
-int invalidate_inodes(struct super_block *sb)
+int invalidate_inodes(struct super_block *sb, bool kill_dirty)
 {
        int busy = 0;
        struct inode *inode, *next;
        LIST_HEAD(dispose);
 
-       down_write(&iprune_sem);
-
        spin_lock(&inode_lock);
        list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) {
                if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE))
                        continue;
+               if (inode->i_state & I_DIRTY && !kill_dirty) {
+                       busy = 1;
+                       continue;
+               }
                if (atomic_read(&inode->i_count)) {
                        busy = 1;
                        continue;
@@ -575,7 +587,6 @@ int invalidate_inodes(struct super_block *sb)
        spin_unlock(&inode_lock);
 
        dispose_list(&dispose);
-       up_write(&iprune_sem);
 
        return busy;
 }
index 0663568..f3d15de 100644 (file)
@@ -106,10 +106,23 @@ extern void put_super(struct super_block *sb);
 struct nameidata;
 extern struct file *nameidata_to_filp(struct nameidata *);
 extern void release_open_intent(struct nameidata *);
+struct open_flags {
+       int open_flag;
+       int mode;
+       int acc_mode;
+       int intent;
+};
+extern struct file *do_filp_open(int dfd, const char *pathname,
+               const struct open_flags *op, int lookup_flags);
+extern struct file *do_file_open_root(struct dentry *, struct vfsmount *,
+               const char *, const struct open_flags *, int lookup_flags);
+
+extern long do_handle_open(int mountdirfd,
+                          struct file_handle __user *ufh, int open_flag);
 
 /*
  * inode.c
  */
 extern int get_nr_dirty_inodes(void);
 extern void evict_inodes(struct super_block *);
-extern int invalidate_inodes(struct super_block *);
+extern int invalidate_inodes(struct super_block *, bool);
index a59635e..1eebeb7 100644 (file)
@@ -273,6 +273,13 @@ int __generic_block_fiemap(struct inode *inode,
                len = isize;
        }
 
+       /*
+        * Some filesystems can't deal with being asked to map less than
+        * blocksize, so make sure our len is at least block length.
+        */
+       if (logical_to_blk(inode, len) == 0)
+               len = blk_to_logical(inode, 1);
+
        start_blk = logical_to_blk(inode, start);
        last_blk = logical_to_blk(inode, start + len - 1);
 
index ed752cb..dd4687f 100644 (file)
@@ -124,9 +124,13 @@ isofs_export_encode_fh(struct dentry *dentry,
         * offset of the inode and the upper 16 bits of fh32[1] to
         * hold the offset of the parent.
         */
-
-       if (len < 3 || (connectable && len < 5))
+       if (connectable && (len < 5)) {
+               *max_len = 5;
+               return 255;
+       } else if (len < 3) {
+               *max_len = 3;
                return 255;
+       }
 
        len = 3;
        fh32[0] = ei->i_iget5_block;
index 9e46869..97e7346 100644 (file)
@@ -473,7 +473,8 @@ int __jbd2_log_space_left(journal_t *journal)
 }
 
 /*
- * Called under j_state_lock.  Returns true if a transaction commit was started.
+ * Called with j_state_lock locked for writing.
+ * Returns true if a transaction commit was started.
  */
 int __jbd2_log_start_commit(journal_t *journal, tid_t target)
 {
@@ -520,11 +521,13 @@ int jbd2_journal_force_commit_nested(journal_t *journal)
 {
        transaction_t *transaction = NULL;
        tid_t tid;
+       int need_to_start = 0;
 
        read_lock(&journal->j_state_lock);
        if (journal->j_running_transaction && !current->journal_info) {
                transaction = journal->j_running_transaction;
-               __jbd2_log_start_commit(journal, transaction->t_tid);
+               if (!tid_geq(journal->j_commit_request, transaction->t_tid))
+                       need_to_start = 1;
        } else if (journal->j_committing_transaction)
                transaction = journal->j_committing_transaction;
 
@@ -535,6 +538,8 @@ int jbd2_journal_force_commit_nested(journal_t *journal)
 
        tid = transaction->t_tid;
        read_unlock(&journal->j_state_lock);
+       if (need_to_start)
+               jbd2_log_start_commit(journal, tid);
        jbd2_log_wait_commit(journal, tid);
        return 1;
 }
index faad2bd..1d11910 100644 (file)
@@ -117,10 +117,10 @@ static inline void update_t_max_wait(transaction_t *transaction)
 static int start_this_handle(journal_t *journal, handle_t *handle,
                             int gfp_mask)
 {
-       transaction_t *transaction;
-       int needed;
-       int nblocks = handle->h_buffer_credits;
-       transaction_t *new_transaction = NULL;
+       transaction_t   *transaction, *new_transaction = NULL;
+       tid_t           tid;
+       int             needed, need_to_start;
+       int             nblocks = handle->h_buffer_credits;
 
        if (nblocks > journal->j_max_transaction_buffers) {
                printk(KERN_ERR "JBD: %s wants too many credits (%d > %d)\n",
@@ -222,8 +222,11 @@ repeat:
                atomic_sub(nblocks, &transaction->t_outstanding_credits);
                prepare_to_wait(&journal->j_wait_transaction_locked, &wait,
                                TASK_UNINTERRUPTIBLE);
-               __jbd2_log_start_commit(journal, transaction->t_tid);
+               tid = transaction->t_tid;
+               need_to_start = !tid_geq(journal->j_commit_request, tid);
                read_unlock(&journal->j_state_lock);
+               if (need_to_start)
+                       jbd2_log_start_commit(journal, tid);
                schedule();
                finish_wait(&journal->j_wait_transaction_locked, &wait);
                goto repeat;
@@ -442,7 +445,8 @@ int jbd2__journal_restart(handle_t *handle, int nblocks, int gfp_mask)
 {
        transaction_t *transaction = handle->h_transaction;
        journal_t *journal = transaction->t_journal;
-       int ret;
+       tid_t           tid;
+       int             need_to_start, ret;
 
        /* If we've had an abort of any type, don't even think about
         * actually doing the restart! */
@@ -465,8 +469,11 @@ int jbd2__journal_restart(handle_t *handle, int nblocks, int gfp_mask)
        spin_unlock(&transaction->t_handle_lock);
 
        jbd_debug(2, "restarting handle %p\n", handle);
-       __jbd2_log_start_commit(journal, transaction->t_tid);
+       tid = transaction->t_tid;
+       need_to_start = !tid_geq(journal->j_commit_request, tid);
        read_unlock(&journal->j_state_lock);
+       if (need_to_start)
+               jbd2_log_start_commit(journal, tid);
 
        lock_map_release(&handle->h_lockdep_map);
        handle->h_buffer_credits = nblocks;
index 81ead85..3f04a18 100644 (file)
@@ -809,9 +809,6 @@ static int jfs_link(struct dentry *old_dentry,
        if (ip->i_nlink == JFS_LINK_MAX)
                return -EMLINK;
 
-       if (ip->i_nlink == 0)
-               return -ENOENT;
-
        dquot_initialize(dir);
 
        tid = txBegin(ip->i_sb, 0);
@@ -1600,7 +1597,7 @@ out:
 
 static int jfs_ci_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
-       if (nd->flags & LOOKUP_RCU)
+       if (nd && nd->flags & LOOKUP_RCU)
                return -ECHILD;
        /*
         * This is not negative dentry. Always valid.
index 5f1bcb2..b7c99bf 100644 (file)
@@ -520,7 +520,7 @@ static struct nlm_host *next_host_state(struct hlist_head *cache,
                                        struct nsm_handle *nsm,
                                        const struct nlm_reboot *info)
 {
-       struct nlm_host *host = NULL;
+       struct nlm_host *host;
        struct hlist_head *chain;
        struct hlist_node *pos;
 
@@ -532,12 +532,13 @@ static struct nlm_host *next_host_state(struct hlist_head *cache,
                        host->h_state++;
 
                        nlm_get_host(host);
-                       goto out;
+                       mutex_unlock(&nlm_host_mutex);
+                       return host;
                }
        }
-out:
+
        mutex_unlock(&nlm_host_mutex);
-       return host;
+       return NULL;
 }
 
 /**
index ce7337d..6e6777f 100644 (file)
@@ -213,7 +213,6 @@ static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
                new_de = minix_find_entry(new_dentry, &new_page);
                if (!new_de)
                        goto out_dir;
-               inode_inc_link_count(old_inode);
                minix_set_link(new_de, new_page, old_inode);
                new_inode->i_ctime = CURRENT_TIME_SEC;
                if (dir_de)
@@ -225,18 +224,15 @@ static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
                        if (new_dir->i_nlink >= info->s_link_max)
                                goto out_dir;
                }
-               inode_inc_link_count(old_inode);
                err = minix_add_link(new_dentry, old_inode);
-               if (err) {
-                       inode_dec_link_count(old_inode);
+               if (err)
                        goto out_dir;
-               }
                if (dir_de)
                        inode_inc_link_count(new_dir);
        }
 
        minix_delete_entry(old_de, old_page);
-       inode_dec_link_count(old_inode);
+       mark_inode_dirty(old_inode);
 
        if (dir_de) {
                minix_set_link(dir_de, dir_page, new_dir);
index 7d77f24..b912b7a 100644 (file)
@@ -136,7 +136,7 @@ static int do_getname(const char __user *filename, char *page)
        return retval;
 }
 
-char * getname(const char __user * filename)
+static char *getname_flags(const char __user * filename, int flags)
 {
        char *tmp, *result;
 
@@ -147,14 +147,21 @@ char * getname(const char __user * filename)
 
                result = tmp;
                if (retval < 0) {
-                       __putname(tmp);
-                       result = ERR_PTR(retval);
+                       if (retval != -ENOENT || !(flags & LOOKUP_EMPTY)) {
+                               __putname(tmp);
+                               result = ERR_PTR(retval);
+                       }
                }
        }
        audit_getname(result);
        return result;
 }
 
+char *getname(const char __user * filename)
+{
+       return getname_flags(filename, 0);
+}
+
 #ifdef CONFIG_AUDITSYSCALL
 void putname(const char *name)
 {
@@ -401,9 +408,11 @@ static int nameidata_drop_rcu(struct nameidata *nd)
 {
        struct fs_struct *fs = current->fs;
        struct dentry *dentry = nd->path.dentry;
+       int want_root = 0;
 
        BUG_ON(!(nd->flags & LOOKUP_RCU));
-       if (nd->root.mnt) {
+       if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) {
+               want_root = 1;
                spin_lock(&fs->lock);
                if (nd->root.mnt != fs->root.mnt ||
                                nd->root.dentry != fs->root.dentry)
@@ -414,7 +423,7 @@ static int nameidata_drop_rcu(struct nameidata *nd)
                goto err;
        BUG_ON(nd->inode != dentry->d_inode);
        spin_unlock(&dentry->d_lock);
-       if (nd->root.mnt) {
+       if (want_root) {
                path_get(&nd->root);
                spin_unlock(&fs->lock);
        }
@@ -427,7 +436,7 @@ static int nameidata_drop_rcu(struct nameidata *nd)
 err:
        spin_unlock(&dentry->d_lock);
 err_root:
-       if (nd->root.mnt)
+       if (want_root)
                spin_unlock(&fs->lock);
        return -ECHILD;
 }
@@ -454,17 +463,11 @@ static int nameidata_dentry_drop_rcu(struct nameidata *nd, struct dentry *dentry
 {
        struct fs_struct *fs = current->fs;
        struct dentry *parent = nd->path.dentry;
-
-       /*
-        * It can be possible to revalidate the dentry that we started
-        * the path walk with. force_reval_path may also revalidate the
-        * dentry already committed to the nameidata.
-        */
-       if (unlikely(parent == dentry))
-               return nameidata_drop_rcu(nd);
+       int want_root = 0;
 
        BUG_ON(!(nd->flags & LOOKUP_RCU));
-       if (nd->root.mnt) {
+       if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) {
+               want_root = 1;
                spin_lock(&fs->lock);
                if (nd->root.mnt != fs->root.mnt ||
                                nd->root.dentry != fs->root.dentry)
@@ -484,7 +487,7 @@ static int nameidata_dentry_drop_rcu(struct nameidata *nd, struct dentry *dentry
        parent->d_count++;
        spin_unlock(&dentry->d_lock);
        spin_unlock(&parent->d_lock);
-       if (nd->root.mnt) {
+       if (want_root) {
                path_get(&nd->root);
                spin_unlock(&fs->lock);
        }
@@ -498,7 +501,7 @@ err:
        spin_unlock(&dentry->d_lock);
        spin_unlock(&parent->d_lock);
 err_root:
-       if (nd->root.mnt)
+       if (want_root)
                spin_unlock(&fs->lock);
        return -ECHILD;
 }
@@ -506,8 +509,16 @@ err_root:
 /* Try to drop out of rcu-walk mode if we were in it, otherwise do nothing.  */
 static inline int nameidata_dentry_drop_rcu_maybe(struct nameidata *nd, struct dentry *dentry)
 {
-       if (nd->flags & LOOKUP_RCU)
-               return nameidata_dentry_drop_rcu(nd, dentry);
+       if (nd->flags & LOOKUP_RCU) {
+               if (unlikely(nameidata_dentry_drop_rcu(nd, dentry))) {
+                       nd->flags &= ~LOOKUP_RCU;
+                       if (!(nd->flags & LOOKUP_ROOT))
+                               nd->root.mnt = NULL;
+                       rcu_read_unlock();
+                       br_read_unlock(vfsmount_lock);
+                       return -ECHILD;
+               }
+       }
        return 0;
 }
 
@@ -526,7 +537,8 @@ static int nameidata_drop_rcu_last(struct nameidata *nd)
 
        BUG_ON(!(nd->flags & LOOKUP_RCU));
        nd->flags &= ~LOOKUP_RCU;
-       nd->root.mnt = NULL;
+       if (!(nd->flags & LOOKUP_ROOT))
+               nd->root.mnt = NULL;
        spin_lock(&dentry->d_lock);
        if (!__d_rcu_to_refcount(dentry, nd->seq))
                goto err_unlock;
@@ -547,53 +559,31 @@ err_unlock:
        return -ECHILD;
 }
 
-/* Try to drop out of rcu-walk mode if we were in it, otherwise do nothing.  */
-static inline int nameidata_drop_rcu_last_maybe(struct nameidata *nd)
-{
-       if (likely(nd->flags & LOOKUP_RCU))
-               return nameidata_drop_rcu_last(nd);
-       return 0;
-}
-
 /**
  * release_open_intent - free up open intent resources
  * @nd: pointer to nameidata
  */
 void release_open_intent(struct nameidata *nd)
 {
-       if (nd->intent.open.file->f_path.dentry == NULL)
-               put_filp(nd->intent.open.file);
-       else
-               fput(nd->intent.open.file);
-}
-
-/*
- * Call d_revalidate and handle filesystems that request rcu-walk
- * to be dropped. This may be called and return in rcu-walk mode,
- * regardless of success or error. If -ECHILD is returned, the caller
- * must return -ECHILD back up the path walk stack so path walk may
- * be restarted in ref-walk mode.
- */
-static int d_revalidate(struct dentry *dentry, struct nameidata *nd)
-{
-       int status;
+       struct file *file = nd->intent.open.file;
 
-       status = dentry->d_op->d_revalidate(dentry, nd);
-       if (status == -ECHILD) {
-               if (nameidata_dentry_drop_rcu(nd, dentry))
-                       return status;
-               status = dentry->d_op->d_revalidate(dentry, nd);
+       if (file && !IS_ERR(file)) {
+               if (file->f_path.dentry == NULL)
+                       put_filp(file);
+               else
+                       fput(file);
        }
+}
 
-       return status;
+static inline int d_revalidate(struct dentry *dentry, struct nameidata *nd)
+{
+       return dentry->d_op->d_revalidate(dentry, nd);
 }
 
-static inline struct dentry *
+static struct dentry *
 do_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
-       int status;
-
-       status = d_revalidate(dentry, nd);
+       int status = d_revalidate(dentry, nd);
        if (unlikely(status <= 0)) {
                /*
                 * The dentry failed validation.
@@ -602,37 +592,18 @@ do_revalidate(struct dentry *dentry, struct nameidata *nd)
                 * to return a fail status.
                 */
                if (status < 0) {
-                       /* If we're in rcu-walk, we don't have a ref */
-                       if (!(nd->flags & LOOKUP_RCU))
-                               dput(dentry);
+                       dput(dentry);
                        dentry = ERR_PTR(status);
-
-               } else {
-                       /* Don't d_invalidate in rcu-walk mode */
-                       if (nameidata_dentry_drop_rcu_maybe(nd, dentry))
-                               return ERR_PTR(-ECHILD);
-                       if (!d_invalidate(dentry)) {
-                               dput(dentry);
-                               dentry = NULL;
-                       }
+               } else if (!d_invalidate(dentry)) {
+                       dput(dentry);
+                       dentry = NULL;
                }
        }
        return dentry;
 }
 
-static inline int need_reval_dot(struct dentry *dentry)
-{
-       if (likely(!(dentry->d_flags & DCACHE_OP_REVALIDATE)))
-               return 0;
-
-       if (likely(!(dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)))
-               return 0;
-
-       return 1;
-}
-
 /*
- * force_reval_path - force revalidation of a dentry
+ * handle_reval_path - force revalidation of a dentry
  *
  * In some situations the path walking code will trust dentries without
  * revalidating them. This causes problems for filesystems that depend on
@@ -646,30 +617,28 @@ static inline int need_reval_dot(struct dentry *dentry)
  * invalidate the dentry. It's up to the caller to handle putting references
  * to the path if necessary.
  */
-static int
-force_reval_path(struct path *path, struct nameidata *nd)
+static inline int handle_reval_path(struct nameidata *nd)
 {
+       struct dentry *dentry = nd->path.dentry;
        int status;
-       struct dentry *dentry = path->dentry;
 
-       /*
-        * only check on filesystems where it's possible for the dentry to
-        * become stale.
-        */
-       if (!need_reval_dot(dentry))
+       if (likely(!(nd->flags & LOOKUP_JUMPED)))
+               return 0;
+
+       if (likely(!(dentry->d_flags & DCACHE_OP_REVALIDATE)))
                return 0;
 
+       if (likely(!(dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)))
+               return 0;
+
+       /* Note: we do not d_invalidate() */
        status = d_revalidate(dentry, nd);
        if (status > 0)
                return 0;
 
-       if (!status) {
-               /* Don't d_invalidate in rcu-walk mode */
-               if (nameidata_drop_rcu(nd))
-                       return -ECHILD;
-               d_invalidate(dentry);
+       if (!status)
                status = -ESTALE;
-       }
+
        return status;
 }
 
@@ -738,6 +707,7 @@ static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *l
                path_put(&nd->path);
                nd->path = nd->root;
                path_get(&nd->root);
+               nd->flags |= LOOKUP_JUMPED;
        }
        nd->inode = nd->path.dentry->d_inode;
 
@@ -767,18 +737,43 @@ static inline void path_to_nameidata(const struct path *path,
        nd->path.dentry = path->dentry;
 }
 
+static inline void put_link(struct nameidata *nd, struct path *link, void *cookie)
+{
+       struct inode *inode = link->dentry->d_inode;
+       if (!IS_ERR(cookie) && inode->i_op->put_link)
+               inode->i_op->put_link(link->dentry, nd, cookie);
+       path_put(link);
+}
+
 static __always_inline int
-__do_follow_link(const struct path *link, struct nameidata *nd, void **p)
+follow_link(struct path *link, struct nameidata *nd, void **p)
 {
        int error;
        struct dentry *dentry = link->dentry;
 
-       touch_atime(link->mnt, dentry);
-       nd_set_link(nd, NULL);
+       BUG_ON(nd->flags & LOOKUP_RCU);
 
        if (link->mnt == nd->path.mnt)
                mntget(link->mnt);
 
+       if (unlikely(current->total_link_count >= 40)) {
+               *p = ERR_PTR(-ELOOP); /* no ->put_link(), please */
+               path_put(&nd->path);
+               return -ELOOP;
+       }
+       cond_resched();
+       current->total_link_count++;
+
+       touch_atime(link->mnt, dentry);
+       nd_set_link(nd, NULL);
+
+       error = security_inode_follow_link(link->dentry, nd);
+       if (error) {
+               *p = ERR_PTR(error); /* no ->put_link(), please */
+               path_put(&nd->path);
+               return error;
+       }
+
        nd->last_type = LAST_BIND;
        *p = dentry->d_inode->i_op->follow_link(dentry, nd);
        error = PTR_ERR(*p);
@@ -788,50 +783,18 @@ __do_follow_link(const struct path *link, struct nameidata *nd, void **p)
                if (s)
                        error = __vfs_follow_link(nd, s);
                else if (nd->last_type == LAST_BIND) {
-                       error = force_reval_path(&nd->path, nd);
-                       if (error)
+                       nd->flags |= LOOKUP_JUMPED;
+                       nd->inode = nd->path.dentry->d_inode;
+                       if (nd->inode->i_op->follow_link) {
+                               /* stepped on a _really_ weird one */
                                path_put(&nd->path);
+                               error = -ELOOP;
+                       }
                }
        }
        return error;
 }
 
-/*
- * This limits recursive symlink follows to 8, while
- * limiting consecutive symlinks to 40.
- *
- * Without that kind of total limit, nasty chains of consecutive
- * symlinks can cause almost arbitrarily long lookups. 
- */
-static inline int do_follow_link(struct path *path, struct nameidata *nd)
-{
-       void *cookie;
-       int err = -ELOOP;
-       if (current->link_count >= MAX_NESTED_LINKS)
-               goto loop;
-       if (current->total_link_count >= 40)
-               goto loop;
-       BUG_ON(nd->depth >= MAX_NESTED_LINKS);
-       cond_resched();
-       err = security_inode_follow_link(path->dentry, nd);
-       if (err)
-               goto loop;
-       current->link_count++;
-       current->total_link_count++;
-       nd->depth++;
-       err = __do_follow_link(path, nd, &cookie);
-       if (!IS_ERR(cookie) && path->dentry->d_inode->i_op->put_link)
-               path->dentry->d_inode->i_op->put_link(path->dentry, nd, cookie);
-       path_put(path);
-       current->link_count--;
-       nd->depth--;
-       return err;
-loop:
-       path_put_conditional(path, nd);
-       path_put(&nd->path);
-       return err;
-}
-
 static int follow_up_rcu(struct path *path)
 {
        struct vfsmount *parent;
@@ -1070,7 +1033,7 @@ static int follow_dotdot_rcu(struct nameidata *nd)
 
                        seq = read_seqcount_begin(&parent->d_seq);
                        if (read_seqcount_retry(&old->d_seq, nd->seq))
-                               return -ECHILD;
+                               goto failed;
                        inode = parent->d_inode;
                        nd->path.dentry = parent;
                        nd->seq = seq;
@@ -1083,8 +1046,15 @@ static int follow_dotdot_rcu(struct nameidata *nd)
        }
        __follow_mount_rcu(nd, &nd->path, &inode, true);
        nd->inode = inode;
-
        return 0;
+
+failed:
+       nd->flags &= ~LOOKUP_RCU;
+       if (!(nd->flags & LOOKUP_ROOT))
+               nd->root.mnt = NULL;
+       rcu_read_unlock();
+       br_read_unlock(vfsmount_lock);
+       return -ECHILD;
 }
 
 /*
@@ -1218,19 +1188,10 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
 {
        struct vfsmount *mnt = nd->path.mnt;
        struct dentry *dentry, *parent = nd->path.dentry;
-       struct inode *dir;
+       int need_reval = 1;
+       int status = 1;
        int err;
 
-       /*
-        * See if the low-level filesystem might want
-        * to use its own hash..
-        */
-       if (unlikely(parent->d_flags & DCACHE_OP_HASH)) {
-               err = parent->d_op->d_hash(parent, nd->inode, name);
-               if (err < 0)
-                       return err;
-       }
-
        /*
         * Rename seqlock is not required here because in the off chance
         * of a false negative due to a concurrent rename, we're going to
@@ -1238,37 +1199,74 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
         */
        if (nd->flags & LOOKUP_RCU) {
                unsigned seq;
-
                *inode = nd->inode;
                dentry = __d_lookup_rcu(parent, name, &seq, inode);
-               if (!dentry) {
-                       if (nameidata_drop_rcu(nd))
-                               return -ECHILD;
-                       goto need_lookup;
-               }
+               if (!dentry)
+                       goto unlazy;
+
                /* Memory barrier in read_seqcount_begin of child is enough */
                if (__read_seqcount_retry(&parent->d_seq, nd->seq))
                        return -ECHILD;
-
                nd->seq = seq;
-               if (dentry->d_flags & DCACHE_OP_REVALIDATE)
-                       goto need_revalidate;
-done2:
+
+               if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) {
+                       status = d_revalidate(dentry, nd);
+                       if (unlikely(status <= 0)) {
+                               if (status != -ECHILD)
+                                       need_reval = 0;
+                               goto unlazy;
+                       }
+               }
                path->mnt = mnt;
                path->dentry = dentry;
                if (likely(__follow_mount_rcu(nd, path, inode, false)))
                        return 0;
-               if (nameidata_drop_rcu(nd))
-                       return -ECHILD;
-               /* fallthru */
+unlazy:
+               if (dentry) {
+                       if (nameidata_dentry_drop_rcu(nd, dentry))
+                               return -ECHILD;
+               } else {
+                       if (nameidata_drop_rcu(nd))
+                               return -ECHILD;
+               }
+       } else {
+               dentry = __d_lookup(parent, name);
        }
-       dentry = __d_lookup(parent, name);
-       if (!dentry)
-               goto need_lookup;
-found:
-       if (dentry->d_flags & DCACHE_OP_REVALIDATE)
-               goto need_revalidate;
-done:
+
+retry:
+       if (unlikely(!dentry)) {
+               struct inode *dir = parent->d_inode;
+               BUG_ON(nd->inode != dir);
+
+               mutex_lock(&dir->i_mutex);
+               dentry = d_lookup(parent, name);
+               if (likely(!dentry)) {
+                       dentry = d_alloc_and_lookup(parent, name, nd);
+                       if (IS_ERR(dentry)) {
+                               mutex_unlock(&dir->i_mutex);
+                               return PTR_ERR(dentry);
+                       }
+                       /* known good */
+                       need_reval = 0;
+                       status = 1;
+               }
+               mutex_unlock(&dir->i_mutex);
+       }
+       if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE) && need_reval)
+               status = d_revalidate(dentry, nd);
+       if (unlikely(status <= 0)) {
+               if (status < 0) {
+                       dput(dentry);
+                       return status;
+               }
+               if (!d_invalidate(dentry)) {
+                       dput(dentry);
+                       dentry = NULL;
+                       need_reval = 1;
+                       goto retry;
+               }
+       }
+
        path->mnt = mnt;
        path->dentry = dentry;
        err = follow_managed(path, nd->flags);
@@ -1278,49 +1276,113 @@ done:
        }
        *inode = path->dentry->d_inode;
        return 0;
+}
+
+static inline int may_lookup(struct nameidata *nd)
+{
+       if (nd->flags & LOOKUP_RCU) {
+               int err = exec_permission(nd->inode, IPERM_FLAG_RCU);
+               if (err != -ECHILD)
+                       return err;
+               if (nameidata_drop_rcu(nd))
+                       return -ECHILD;
+       }
+       return exec_permission(nd->inode, 0);
+}
+
+static inline int handle_dots(struct nameidata *nd, int type)
+{
+       if (type == LAST_DOTDOT) {
+               if (nd->flags & LOOKUP_RCU) {
+                       if (follow_dotdot_rcu(nd))
+                               return -ECHILD;
+               } else
+                       follow_dotdot(nd);
+       }
+       return 0;
+}
 
-need_lookup:
-       dir = parent->d_inode;
-       BUG_ON(nd->inode != dir);
+static void terminate_walk(struct nameidata *nd)
+{
+       if (!(nd->flags & LOOKUP_RCU)) {
+               path_put(&nd->path);
+       } else {
+               nd->flags &= ~LOOKUP_RCU;
+               if (!(nd->flags & LOOKUP_ROOT))
+                       nd->root.mnt = NULL;
+               rcu_read_unlock();
+               br_read_unlock(vfsmount_lock);
+       }
+}
 
-       mutex_lock(&dir->i_mutex);
+static inline int walk_component(struct nameidata *nd, struct path *path,
+               struct qstr *name, int type, int follow)
+{
+       struct inode *inode;
+       int err;
        /*
-        * First re-do the cached lookup just in case it was created
-        * while we waited for the directory semaphore, or the first
-        * lookup failed due to an unrelated rename.
-        *
-        * This could use version numbering or similar to avoid unnecessary
-        * cache lookups, but then we'd have to do the first lookup in the
-        * non-racy way. However in the common case here, everything should
-        * be hot in cache, so would it be a big win?
+        * "." and ".." are special - ".." especially so because it has
+        * to be able to know about the current root directory and
+        * parent relationships.
         */
-       dentry = d_lookup(parent, name);
-       if (likely(!dentry)) {
-               dentry = d_alloc_and_lookup(parent, name, nd);
-               mutex_unlock(&dir->i_mutex);
-               if (IS_ERR(dentry))
-                       goto fail;
-               goto done;
+       if (unlikely(type != LAST_NORM))
+               return handle_dots(nd, type);
+       err = do_lookup(nd, name, path, &inode);
+       if (unlikely(err)) {
+               terminate_walk(nd);
+               return err;
        }
-       /*
-        * Uhhuh! Nasty case: the cache was re-populated while
-        * we waited on the semaphore. Need to revalidate.
-        */
-       mutex_unlock(&dir->i_mutex);
-       goto found;
+       if (!inode) {
+               path_to_nameidata(path, nd);
+               terminate_walk(nd);
+               return -ENOENT;
+       }
+       if (unlikely(inode->i_op->follow_link) && follow) {
+               if (nameidata_dentry_drop_rcu_maybe(nd, path->dentry))
+                       return -ECHILD;
+               BUG_ON(inode != path->dentry->d_inode);
+               return 1;
+       }
+       path_to_nameidata(path, nd);
+       nd->inode = inode;
+       return 0;
+}
 
-need_revalidate:
-       dentry = do_revalidate(dentry, nd);
-       if (!dentry)
-               goto need_lookup;
-       if (IS_ERR(dentry))
-               goto fail;
-       if (nd->flags & LOOKUP_RCU)
-               goto done2;
-       goto done;
+/*
+ * This limits recursive symlink follows to 8, while
+ * limiting consecutive symlinks to 40.
+ *
+ * Without that kind of total limit, nasty chains of consecutive
+ * symlinks can cause almost arbitrarily long lookups.
+ */
+static inline int nested_symlink(struct path *path, struct nameidata *nd)
+{
+       int res;
 
-fail:
-       return PTR_ERR(dentry);
+       BUG_ON(nd->depth >= MAX_NESTED_LINKS);
+       if (unlikely(current->link_count >= MAX_NESTED_LINKS)) {
+               path_put_conditional(path, nd);
+               path_put(&nd->path);
+               return -ELOOP;
+       }
+
+       nd->depth++;
+       current->link_count++;
+
+       do {
+               struct path link = *path;
+               void *cookie;
+
+               res = follow_link(&link, nd, &cookie);
+               if (!res)
+                       res = walk_component(nd, path, &nd->last,
+                                            nd->last_type, LOOKUP_FOLLOW);
+               put_link(nd, &link, cookie);
+       } while (res > 0);
+
+       current->link_count--;
+       nd->depth--;
+       return res;
 }
 
 /*
@@ -1340,30 +1402,18 @@ static int link_path_walk(const char *name, struct nameidata *nd)
        while (*name=='/')
                name++;
        if (!*name)
-               goto return_reval;
-
-       if (nd->depth)
-               lookup_flags = LOOKUP_FOLLOW | (nd->flags & LOOKUP_CONTINUE);
+               return 0;
 
        /* At this point we know we have a real path component. */
        for(;;) {
-               struct inode *inode;
                unsigned long hash;
                struct qstr this;
                unsigned int c;
+               int type;
 
                nd->flags |= LOOKUP_CONTINUE;
-               if (nd->flags & LOOKUP_RCU) {
-                       err = exec_permission(nd->inode, IPERM_FLAG_RCU);
-                       if (err == -ECHILD) {
-                               if (nameidata_drop_rcu(nd))
-                                       return -ECHILD;
-                               goto exec_again;
-                       }
-               } else {
-exec_again:
-                       err = exec_permission(nd->inode, 0);
-               }
+
+               err = may_lookup(nd);
                if (err)
                        break;
 
@@ -1379,56 +1429,43 @@ exec_again:
                this.len = name - (const char *) this.name;
                this.hash = end_name_hash(hash);
 
+               type = LAST_NORM;
+               if (this.name[0] == '.') switch (this.len) {
+                       case 2:
+                               if (this.name[1] == '.') {
+                                       type = LAST_DOTDOT;
+                                       nd->flags |= LOOKUP_JUMPED;
+                               }
+                               break;
+                       case 1:
+                               type = LAST_DOT;
+               }
+               if (likely(type == LAST_NORM)) {
+                       struct dentry *parent = nd->path.dentry;
+                       nd->flags &= ~LOOKUP_JUMPED;
+                       if (unlikely(parent->d_flags & DCACHE_OP_HASH)) {
+                               err = parent->d_op->d_hash(parent, nd->inode,
+                                                          &this);
+                               if (err < 0)
+                                       break;
+                       }
+               }
+
                /* remove trailing slashes? */
                if (!c)
                        goto last_component;
                while (*++name == '/');
                if (!*name)
-                       goto last_with_slashes;
+                       goto last_component;
 
-               /*
-                * "." and ".." are special - ".." especially so because it has
-                * to be able to know about the current root directory and
-                * parent relationships.
-                */
-               if (this.name[0] == '.') switch (this.len) {
-                       default:
-                               break;
-                       case 2:
-                               if (this.name[1] != '.')
-                                       break;
-                               if (nd->flags & LOOKUP_RCU) {
-                                       if (follow_dotdot_rcu(nd))
-                                               return -ECHILD;
-                               } else
-                                       follow_dotdot(nd);
-                               /* fallthrough */
-                       case 1:
-                               continue;
-               }
-               /* This does the actual lookups.. */
-               err = do_lookup(nd, &this, &next, &inode);
-               if (err)
-                       break;
-               err = -ENOENT;
-               if (!inode)
-                       goto out_dput;
+               err = walk_component(nd, &next, &this, type, LOOKUP_FOLLOW);
+               if (err < 0)
+                       return err;
 
-               if (inode->i_op->follow_link) {
-                       /* We commonly drop rcu-walk here */
-                       if (nameidata_dentry_drop_rcu_maybe(nd, next.dentry))
-                               return -ECHILD;
-                       BUG_ON(inode != next.dentry->d_inode);
-                       err = do_follow_link(&next, nd);
+               if (err) {
+                       err = nested_symlink(&next, nd);
                        if (err)
-                               goto return_err;
-                       nd->inode = nd->path.dentry->d_inode;
-                       err = -ENOENT;
-                       if (!nd->inode)
-                               break;
-               } else {
-                       path_to_nameidata(&next, nd);
-                       nd->inode = inode;
+                               return err;
                }
                err = -ENOTDIR; 
                if (!nd->inode->i_op->lookup)
@@ -1436,209 +1473,109 @@ exec_again:
                continue;
                /* here ends the main loop */
 
-last_with_slashes:
-               lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
 last_component:
                /* Clear LOOKUP_CONTINUE iff it was previously unset */
                nd->flags &= lookup_flags | ~LOOKUP_CONTINUE;
-               if (lookup_flags & LOOKUP_PARENT)
-                       goto lookup_parent;
-               if (this.name[0] == '.') switch (this.len) {
-                       default:
-                               break;
-                       case 2:
-                               if (this.name[1] != '.')
-                                       break;
-                               if (nd->flags & LOOKUP_RCU) {
-                                       if (follow_dotdot_rcu(nd))
-                                               return -ECHILD;
-                               } else
-                                       follow_dotdot(nd);
-                               /* fallthrough */
-                       case 1:
-                               goto return_reval;
-               }
-               err = do_lookup(nd, &this, &next, &inode);
-               if (err)
-                       break;
-               if (inode && unlikely(inode->i_op->follow_link) &&
-                   (lookup_flags & LOOKUP_FOLLOW)) {
-                       if (nameidata_dentry_drop_rcu_maybe(nd, next.dentry))
-                               return -ECHILD;
-                       BUG_ON(inode != next.dentry->d_inode);
-                       err = do_follow_link(&next, nd);
-                       if (err)
-                               goto return_err;
-                       nd->inode = nd->path.dentry->d_inode;
-               } else {
-                       path_to_nameidata(&next, nd);
-                       nd->inode = inode;
-               }
-               err = -ENOENT;
-               if (!nd->inode)
-                       break;
-               if (lookup_flags & LOOKUP_DIRECTORY) {
-                       err = -ENOTDIR; 
-                       if (!nd->inode->i_op->lookup)
-                               break;
-               }
-               goto return_base;
-lookup_parent:
                nd->last = this;
-               nd->last_type = LAST_NORM;
-               if (this.name[0] != '.')
-                       goto return_base;
-               if (this.len == 1)
-                       nd->last_type = LAST_DOT;
-               else if (this.len == 2 && this.name[1] == '.')
-                       nd->last_type = LAST_DOTDOT;
-               else
-                       goto return_base;
-return_reval:
-               /*
-                * We bypassed the ordinary revalidation routines.
-                * We may need to check the cached dentry for staleness.
-                */
-               if (need_reval_dot(nd->path.dentry)) {
-                       /* Note: we do not d_invalidate() */
-                       err = d_revalidate(nd->path.dentry, nd);
-                       if (!err)
-                               err = -ESTALE;
-                       if (err < 0)
-                               break;
-               }
-return_base:
-               if (nameidata_drop_rcu_last_maybe(nd))
-                       return -ECHILD;
+               nd->last_type = type;
                return 0;
-out_dput:
-               if (!(nd->flags & LOOKUP_RCU))
-                       path_put_conditional(&next, nd);
-               break;
        }
-       if (!(nd->flags & LOOKUP_RCU))
-               path_put(&nd->path);
-return_err:
+       terminate_walk(nd);
        return err;
 }
 
-static inline int path_walk_rcu(const char *name, struct nameidata *nd)
-{
-       current->total_link_count = 0;
-
-       return link_path_walk(name, nd);
-}
-
-static inline int path_walk_simple(const char *name, struct nameidata *nd)
-{
-       current->total_link_count = 0;
-
-       return link_path_walk(name, nd);
-}
-
-static int path_walk(const char *name, struct nameidata *nd)
-{
-       struct path save = nd->path;
-       int result;
-
-       current->total_link_count = 0;
-
-       /* make sure the stuff we saved doesn't go away */
-       path_get(&save);
-
-       result = link_path_walk(name, nd);
-       if (result == -ESTALE) {
-               /* nd->path had been dropped */
-               current->total_link_count = 0;
-               nd->path = save;
-               path_get(&nd->path);
-               nd->flags |= LOOKUP_REVAL;
-               result = link_path_walk(name, nd);
-       }
-
-       path_put(&save);
-
-       return result;
-}
-
-static void path_finish_rcu(struct nameidata *nd)
-{
-       if (nd->flags & LOOKUP_RCU) {
-               /* RCU dangling. Cancel it. */
-               nd->flags &= ~LOOKUP_RCU;
-               nd->root.mnt = NULL;
-               rcu_read_unlock();
-               br_read_unlock(vfsmount_lock);
-       }
-       if (nd->file)
-               fput(nd->file);
-}
-
-static int path_init_rcu(int dfd, const char *name, unsigned int flags, struct nameidata *nd)
+static int path_init(int dfd, const char *name, unsigned int flags,
+                    struct nameidata *nd, struct file **fp)
 {
        int retval = 0;
        int fput_needed;
        struct file *file;
 
        nd->last_type = LAST_ROOT; /* if there are only slashes... */
-       nd->flags = flags | LOOKUP_RCU;
+       nd->flags = flags | LOOKUP_JUMPED;
        nd->depth = 0;
+       if (flags & LOOKUP_ROOT) {
+               struct inode *inode = nd->root.dentry->d_inode;
+               if (*name) {
+                       if (!inode->i_op->lookup)
+                               return -ENOTDIR;
+                       retval = inode_permission(inode, MAY_EXEC);
+                       if (retval)
+                               return retval;
+               }
+               nd->path = nd->root;
+               nd->inode = inode;
+               if (flags & LOOKUP_RCU) {
+                       br_read_lock(vfsmount_lock);
+                       rcu_read_lock();
+                       nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
+               } else {
+                       path_get(&nd->path);
+               }
+               return 0;
+       }
+
        nd->root.mnt = NULL;
-       nd->file = NULL;
 
        if (*name=='/') {
-               struct fs_struct *fs = current->fs;
-               unsigned seq;
-
-               br_read_lock(vfsmount_lock);
-               rcu_read_lock();
-
-               do {
-                       seq = read_seqcount_begin(&fs->seq);
-                       nd->root = fs->root;
-                       nd->path = nd->root;
-                       nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
-               } while (read_seqcount_retry(&fs->seq, seq));
-
+               if (flags & LOOKUP_RCU) {
+                       br_read_lock(vfsmount_lock);
+                       rcu_read_lock();
+                       set_root_rcu(nd);
+               } else {
+                       set_root(nd);
+                       path_get(&nd->root);
+               }
+               nd->path = nd->root;
        } else if (dfd == AT_FDCWD) {
-               struct fs_struct *fs = current->fs;
-               unsigned seq;
-
-               br_read_lock(vfsmount_lock);
-               rcu_read_lock();
+               if (flags & LOOKUP_RCU) {
+                       struct fs_struct *fs = current->fs;
+                       unsigned seq;
 
-               do {
-                       seq = read_seqcount_begin(&fs->seq);
-                       nd->path = fs->pwd;
-                       nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
-               } while (read_seqcount_retry(&fs->seq, seq));
+                       br_read_lock(vfsmount_lock);
+                       rcu_read_lock();
 
+                       do {
+                               seq = read_seqcount_begin(&fs->seq);
+                               nd->path = fs->pwd;
+                               nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
+                       } while (read_seqcount_retry(&fs->seq, seq));
+               } else {
+                       get_fs_pwd(current->fs, &nd->path);
+               }
        } else {
                struct dentry *dentry;
 
-               file = fget_light(dfd, &fput_needed);
+               file = fget_raw_light(dfd, &fput_needed);
                retval = -EBADF;
                if (!file)
                        goto out_fail;
 
                dentry = file->f_path.dentry;
 
-               retval = -ENOTDIR;
-               if (!S_ISDIR(dentry->d_inode->i_mode))
-                       goto fput_fail;
+               if (*name) {
+                       retval = -ENOTDIR;
+                       if (!S_ISDIR(dentry->d_inode->i_mode))
+                               goto fput_fail;
 
-               retval = file_permission(file, MAY_EXEC);
-               if (retval)
-                       goto fput_fail;
+                       retval = file_permission(file, MAY_EXEC);
+                       if (retval)
+                               goto fput_fail;
+               }
 
                nd->path = file->f_path;
-               if (fput_needed)
-                       nd->file = file;
-
-               nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
-               br_read_lock(vfsmount_lock);
-               rcu_read_lock();
+               if (flags & LOOKUP_RCU) {
+                       if (fput_needed)
+                               *fp = file;
+                       nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
+                       br_read_lock(vfsmount_lock);
+                       rcu_read_lock();
+               } else {
+                       path_get(&file->f_path);
+                       fput_light(file, fput_needed);
+               }
        }
+
        nd->inode = nd->path.dentry->d_inode;
        return 0;
 
@@ -1648,60 +1585,23 @@ out_fail:
        return retval;
 }
 
-static int path_init(int dfd, const char *name, unsigned int flags, struct nameidata *nd)
+static inline int lookup_last(struct nameidata *nd, struct path *path)
 {
-       int retval = 0;
-       int fput_needed;
-       struct file *file;
-
-       nd->last_type = LAST_ROOT; /* if there are only slashes... */
-       nd->flags = flags;
-       nd->depth = 0;
-       nd->root.mnt = NULL;
-
-       if (*name=='/') {
-               set_root(nd);
-               nd->path = nd->root;
-               path_get(&nd->root);
-       } else if (dfd == AT_FDCWD) {
-               get_fs_pwd(current->fs, &nd->path);
-       } else {
-               struct dentry *dentry;
-
-               file = fget_light(dfd, &fput_needed);
-               retval = -EBADF;
-               if (!file)
-                       goto out_fail;
-
-               dentry = file->f_path.dentry;
+       if (nd->last_type == LAST_NORM && nd->last.name[nd->last.len])
+               nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
 
-               retval = -ENOTDIR;
-               if (!S_ISDIR(dentry->d_inode->i_mode))
-                       goto fput_fail;
-
-               retval = file_permission(file, MAY_EXEC);
-               if (retval)
-                       goto fput_fail;
-
-               nd->path = file->f_path;
-               path_get(&file->f_path);
-
-               fput_light(file, fput_needed);
-       }
-       nd->inode = nd->path.dentry->d_inode;
-       return 0;
-
-fput_fail:
-       fput_light(file, fput_needed);
-out_fail:
-       return retval;
+       nd->flags &= ~LOOKUP_PARENT;
+       return walk_component(nd, path, &nd->last, nd->last_type,
+                                       nd->flags & LOOKUP_FOLLOW);
 }
 
 /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */
-static int do_path_lookup(int dfd, const char *name,
+static int path_lookupat(int dfd, const char *name,
                                unsigned int flags, struct nameidata *nd)
 {
-       int retval;
+       struct file *base = NULL;
+       struct path path;
+       int err;
 
        /*
         * Path walking is largely split up into 2 different synchronisation
@@ -1717,44 +1617,75 @@ static int do_path_lookup(int dfd, const char *name,
         * be handled by restarting a traditional ref-walk (which will always
         * be able to complete).
         */
-       retval = path_init_rcu(dfd, name, flags, nd);
-       if (unlikely(retval))
-               return retval;
-       retval = path_walk_rcu(name, nd);
-       path_finish_rcu(nd);
-       if (nd->root.mnt) {
-               path_put(&nd->root);
-               nd->root.mnt = NULL;
+       err = path_init(dfd, name, flags | LOOKUP_PARENT, nd, &base);
+
+       if (unlikely(err))
+               return err;
+
+       current->total_link_count = 0;
+       err = link_path_walk(name, nd);
+
+       if (!err && !(flags & LOOKUP_PARENT)) {
+               err = lookup_last(nd, &path);
+               while (err > 0) {
+                       void *cookie;
+                       struct path link = path;
+                       nd->flags |= LOOKUP_PARENT;
+                       err = follow_link(&link, nd, &cookie);
+                       if (!err)
+                               err = lookup_last(nd, &path);
+                       put_link(nd, &link, cookie);
+               }
        }
 
-       if (unlikely(retval == -ECHILD || retval == -ESTALE)) {
-               /* slower, locked walk */
-               if (retval == -ESTALE)
-                       flags |= LOOKUP_REVAL;
-               retval = path_init(dfd, name, flags, nd);
-               if (unlikely(retval))
-                       return retval;
-               retval = path_walk(name, nd);
-               if (nd->root.mnt) {
-                       path_put(&nd->root);
-                       nd->root.mnt = NULL;
+       if (nd->flags & LOOKUP_RCU) {
+               /* went all way through without dropping RCU */
+               BUG_ON(err);
+               if (nameidata_drop_rcu_last(nd))
+                       err = -ECHILD;
+       }
+
+       if (!err)
+               err = handle_reval_path(nd);
+
+       if (!err && nd->flags & LOOKUP_DIRECTORY) {
+               if (!nd->inode->i_op->lookup) {
+                       path_put(&nd->path);
+                       return -ENOTDIR;
                }
        }
 
+       if (base)
+               fput(base);
+
+       if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) {
+               path_put(&nd->root);
+               nd->root.mnt = NULL;
+       }
+       return err;
+}
+
+static int do_path_lookup(int dfd, const char *name,
+                               unsigned int flags, struct nameidata *nd)
+{
+       int retval = path_lookupat(dfd, name, flags | LOOKUP_RCU, nd);
+       if (unlikely(retval == -ECHILD))
+               retval = path_lookupat(dfd, name, flags, nd);
+       if (unlikely(retval == -ESTALE))
+               retval = path_lookupat(dfd, name, flags | LOOKUP_REVAL, nd);
+
        if (likely(!retval)) {
                if (unlikely(!audit_dummy_context())) {
                        if (nd->path.dentry && nd->inode)
                                audit_inode(name, nd->path.dentry);
                }
        }
-
        return retval;
 }
 
-int path_lookup(const char *name, unsigned int flags,
-                       struct nameidata *nd)
+int kern_path_parent(const char *name, struct nameidata *nd)
 {
-       return do_path_lookup(AT_FDCWD, name, flags, nd);
+       return do_path_lookup(AT_FDCWD, name, LOOKUP_PARENT, nd);
 }
 
 int kern_path(const char *name, unsigned int flags, struct path *path)
@@ -1778,29 +1709,10 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
                    const char *name, unsigned int flags,
                    struct nameidata *nd)
 {
-       int retval;
-
-       /* same as do_path_lookup */
-       nd->last_type = LAST_ROOT;
-       nd->flags = flags;
-       nd->depth = 0;
-
-       nd->path.dentry = dentry;
-       nd->path.mnt = mnt;
-       path_get(&nd->path);
-       nd->root = nd->path;
-       path_get(&nd->root);
-       nd->inode = nd->path.dentry->d_inode;
-
-       retval = path_walk(name, nd);
-       if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry &&
-                               nd->inode))
-               audit_inode(name, nd->path.dentry);
-
-       path_put(&nd->root);
-       nd->root.mnt = NULL;
-
-       return retval;
+       nd->root.dentry = dentry;
+       nd->root.mnt = mnt;
+       /* the first argument of do_path_lookup() is ignored with LOOKUP_ROOT */
+       return do_path_lookup(AT_FDCWD, name, flags | LOOKUP_ROOT, nd);
 }
 
 static struct dentry *__lookup_hash(struct qstr *name,
@@ -1814,17 +1726,6 @@ static struct dentry *__lookup_hash(struct qstr *name,
        if (err)
                return ERR_PTR(err);
 
-       /*
-        * See if the low-level filesystem might want
-        * to use its own hash..
-        */
-       if (base->d_flags & DCACHE_OP_HASH) {
-               err = base->d_op->d_hash(base, inode, name);
-               dentry = ERR_PTR(err);
-               if (err < 0)
-                       goto out;
-       }
-
        /*
         * Don't bother with __d_lookup: callers are for creat as
         * well as unlink, so a lot of the time it would cost
@@ -1837,7 +1738,7 @@ static struct dentry *__lookup_hash(struct qstr *name,
 
        if (!dentry)
                dentry = d_alloc_and_lookup(base, name, nd);
-out:
+
        return dentry;
 }
 
@@ -1851,28 +1752,6 @@ static struct dentry *lookup_hash(struct nameidata *nd)
        return __lookup_hash(&nd->last, nd->path.dentry, nd);
 }
 
-static int __lookup_one_len(const char *name, struct qstr *this,
-               struct dentry *base, int len)
-{
-       unsigned long hash;
-       unsigned int c;
-
-       this->name = name;
-       this->len = len;
-       if (!len)
-               return -EACCES;
-
-       hash = init_name_hash();
-       while (len--) {
-               c = *(const unsigned char *)name++;
-               if (c == '/' || c == '\0')
-                       return -EACCES;
-               hash = partial_name_hash(c, hash);
-       }
-       this->hash = end_name_hash(hash);
-       return 0;
-}
-
 /**
  * lookup_one_len - filesystem helper to lookup single pathname component
  * @name:      pathname component to lookup
@@ -1886,14 +1765,34 @@ static int __lookup_one_len(const char *name, struct qstr *this,
  */
 struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
 {
-       int err;
        struct qstr this;
+       unsigned long hash;
+       unsigned int c;
 
        WARN_ON_ONCE(!mutex_is_locked(&base->d_inode->i_mutex));
 
-       err = __lookup_one_len(name, &this, base, len);
-       if (err)
-               return ERR_PTR(err);
+       this.name = name;
+       this.len = len;
+       if (!len)
+               return ERR_PTR(-EACCES);
+
+       hash = init_name_hash();
+       while (len--) {
+               c = *(const unsigned char *)name++;
+               if (c == '/' || c == '\0')
+                       return ERR_PTR(-EACCES);
+               hash = partial_name_hash(c, hash);
+       }
+       this.hash = end_name_hash(hash);
+       /*
+        * See if the low-level filesystem might want
+        * to use its own hash..
+        */
+       if (base->d_flags & DCACHE_OP_HASH) {
+               int err = base->d_op->d_hash(base, base->d_inode, &this);
+               if (err < 0)
+                       return ERR_PTR(err);
+       }
 
        return __lookup_hash(&this, base, NULL);
 }
@@ -1902,7 +1801,7 @@ int user_path_at(int dfd, const char __user *name, unsigned flags,
                 struct path *path)
 {
        struct nameidata nd;
-       char *tmp = getname(name);
+       char *tmp = getname_flags(name, flags);
        int err = PTR_ERR(tmp);
        if (!IS_ERR(tmp)) {
 
@@ -2082,12 +1981,16 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode,
        return error;
 }
 
-int may_open(struct path *path, int acc_mode, int flag)
+static int may_open(struct path *path, int acc_mode, int flag)
 {
        struct dentry *dentry = path->dentry;
        struct inode *inode = dentry->d_inode;
        int error;
 
+       /* O_PATH? */
+       if (!acc_mode)
+               return 0;
+
        if (!inode)
                return -ENOENT;
 
@@ -2155,34 +2058,6 @@ static int handle_truncate(struct file *filp)
        return error;
 }
 
-/*
- * Be careful about ever adding any more callers of this
- * function.  Its flags must be in the namei format, not
- * what get passed to sys_open().
- */
-static int __open_namei_create(struct nameidata *nd, struct path *path,
-                               int open_flag, int mode)
-{
-       int error;
-       struct dentry *dir = nd->path.dentry;
-
-       if (!IS_POSIXACL(dir->d_inode))
-               mode &= ~current_umask();
-       error = security_path_mknod(&nd->path, path->dentry, mode, 0);
-       if (error)
-               goto out_unlock;
-       error = vfs_create(dir->d_inode, path->dentry, mode, nd);
-out_unlock:
-       mutex_unlock(&dir->d_inode->i_mutex);
-       dput(nd->path.dentry);
-       nd->path.dentry = path->dentry;
-
-       if (error)
-               return error;
-       /* Don't check for write permission, don't truncate */
-       return may_open(&nd->path, 0, open_flag & ~O_TRUNC);
-}
-
 /*
  * Note that while the flag value (low two bits) for sys_open means:
  *     00 - read-only
@@ -2207,128 +2082,115 @@ static inline int open_to_namei_flags(int flag)
        return flag;
 }
 
-static int open_will_truncate(int flag, struct inode *inode)
-{
-       /*
-        * We'll never write to the fs underlying
-        * a device file.
-        */
-       if (special_file(inode->i_mode))
-               return 0;
-       return (flag & O_TRUNC);
-}
-
-static struct file *finish_open(struct nameidata *nd,
-                               int open_flag, int acc_mode)
-{
-       struct file *filp;
-       int will_truncate;
-       int error;
-
-       will_truncate = open_will_truncate(open_flag, nd->path.dentry->d_inode);
-       if (will_truncate) {
-               error = mnt_want_write(nd->path.mnt);
-               if (error)
-                       goto exit;
-       }
-       error = may_open(&nd->path, acc_mode, open_flag);
-       if (error) {
-               if (will_truncate)
-                       mnt_drop_write(nd->path.mnt);
-               goto exit;
-       }
-       filp = nameidata_to_filp(nd);
-       if (!IS_ERR(filp)) {
-               error = ima_file_check(filp, acc_mode);
-               if (error) {
-                       fput(filp);
-                       filp = ERR_PTR(error);
-               }
-       }
-       if (!IS_ERR(filp)) {
-               if (will_truncate) {
-                       error = handle_truncate(filp);
-                       if (error) {
-                               fput(filp);
-                               filp = ERR_PTR(error);
-                       }
-               }
-       }
-       /*
-        * It is now safe to drop the mnt write
-        * because the filp has had a write taken
-        * on its behalf.
-        */
-       if (will_truncate)
-               mnt_drop_write(nd->path.mnt);
-       path_put(&nd->path);
-       return filp;
-
-exit:
-       if (!IS_ERR(nd->intent.open.file))
-               release_open_intent(nd);
-       path_put(&nd->path);
-       return ERR_PTR(error);
-}
-
 /*
- * Handle O_CREAT case for do_filp_open
+ * Handle the last step of open()
  */
 static struct file *do_last(struct nameidata *nd, struct path *path,
-                           int open_flag, int acc_mode,
-                           int mode, const char *pathname)
+                           const struct open_flags *op, const char *pathname)
 {
        struct dentry *dir = nd->path.dentry;
+       struct dentry *dentry;
+       int open_flag = op->open_flag;
+       int will_truncate = open_flag & O_TRUNC;
+       int want_write = 0;
+       int acc_mode = op->acc_mode;
        struct file *filp;
-       int error = -EISDIR;
+       int error;
+
+       nd->flags &= ~LOOKUP_PARENT;
+       nd->flags |= op->intent;
 
        switch (nd->last_type) {
        case LAST_DOTDOT:
-               follow_dotdot(nd);
-               dir = nd->path.dentry;
        case LAST_DOT:
-               if (need_reval_dot(dir)) {
-                       int status = d_revalidate(nd->path.dentry, nd);
-                       if (!status)
-                               status = -ESTALE;
-                       if (status < 0) {
-                               error = status;
-                               goto exit;
-                       }
-               }
+               error = handle_dots(nd, nd->last_type);
+               if (error)
+                       return ERR_PTR(error);
                /* fallthrough */
        case LAST_ROOT:
-               goto exit;
+               if (nd->flags & LOOKUP_RCU) {
+                       if (nameidata_drop_rcu_last(nd))
+                               return ERR_PTR(-ECHILD);
+               }
+               error = handle_reval_path(nd);
+               if (error)
+                       goto exit;
+               audit_inode(pathname, nd->path.dentry);
+               if (open_flag & O_CREAT) {
+                       error = -EISDIR;
+                       goto exit;
+               }
+               goto ok;
        case LAST_BIND:
+               /* can't be RCU mode here */
+               error = handle_reval_path(nd);
+               if (error)
+                       goto exit;
                audit_inode(pathname, dir);
                goto ok;
        }
 
+       if (!(open_flag & O_CREAT)) {
+               int symlink_ok = 0;
+               if (nd->last.name[nd->last.len])
+                       nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
+               if (open_flag & O_PATH && !(nd->flags & LOOKUP_FOLLOW))
+                       symlink_ok = 1;
+               /* we _can_ be in RCU mode here */
+               error = walk_component(nd, path, &nd->last, LAST_NORM,
+                                       !symlink_ok);
+               if (error < 0)
+                       return ERR_PTR(error);
+               if (error) /* symlink */
+                       return NULL;
+               /* sayonara */
+               if (nd->flags & LOOKUP_RCU) {
+                       if (nameidata_drop_rcu_last(nd))
+                               return ERR_PTR(-ECHILD);
+               }
+
+               error = -ENOTDIR;
+               if (nd->flags & LOOKUP_DIRECTORY) {
+                       if (!nd->inode->i_op->lookup)
+                               goto exit;
+               }
+               audit_inode(pathname, nd->path.dentry);
+               goto ok;
+       }
+
+       /* create side of things */
+
+       if (nd->flags & LOOKUP_RCU) {
+               if (nameidata_drop_rcu_last(nd))
+                       return ERR_PTR(-ECHILD);
+       }
+
+       audit_inode(pathname, dir);
+       error = -EISDIR;
        /* trailing slashes? */
        if (nd->last.name[nd->last.len])
                goto exit;
 
        mutex_lock(&dir->d_inode->i_mutex);
 
-       path->dentry = lookup_hash(nd);
-       path->mnt = nd->path.mnt;
-
-       error = PTR_ERR(path->dentry);
-       if (IS_ERR(path->dentry)) {
+       dentry = lookup_hash(nd);
+       error = PTR_ERR(dentry);
+       if (IS_ERR(dentry)) {
                mutex_unlock(&dir->d_inode->i_mutex);
                goto exit;
        }
 
-       if (IS_ERR(nd->intent.open.file)) {
-               error = PTR_ERR(nd->intent.open.file);
-               goto exit_mutex_unlock;
-       }
+       path->dentry = dentry;
+       path->mnt = nd->path.mnt;
 
        /* Negative dentry, just create the file */
-       if (!path->dentry->d_inode) {
+       if (!dentry->d_inode) {
+               int mode = op->mode;
+               if (!IS_POSIXACL(dir->d_inode))
+                       mode &= ~current_umask();
                /*
                 * This write is needed to ensure that a
-                * ro->rw transition does not occur between
+                * rw->ro transition does not occur between
                 * the time when the file is created and when
                 * a permanent write count is taken through
                 * the 'struct file' in nameidata_to_filp().
@@ -2336,22 +2198,21 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
                error = mnt_want_write(nd->path.mnt);
                if (error)
                        goto exit_mutex_unlock;
-               error = __open_namei_create(nd, path, open_flag, mode);
-               if (error) {
-                       mnt_drop_write(nd->path.mnt);
-                       goto exit;
-               }
-               filp = nameidata_to_filp(nd);
-               mnt_drop_write(nd->path.mnt);
-               path_put(&nd->path);
-               if (!IS_ERR(filp)) {
-                       error = ima_file_check(filp, acc_mode);
-                       if (error) {
-                               fput(filp);
-                               filp = ERR_PTR(error);
-                       }
-               }
-               return filp;
+               want_write = 1;
+               /* Don't check for write permission, don't truncate */
+               open_flag &= ~O_TRUNC;
+               will_truncate = 0;
+               acc_mode = MAY_OPEN;
+               error = security_path_mknod(&nd->path, dentry, mode, 0);
+               if (error)
+                       goto exit_mutex_unlock;
+               error = vfs_create(dir->d_inode, dentry, mode, nd);
+               if (error)
+                       goto exit_mutex_unlock;
+               mutex_unlock(&dir->d_inode->i_mutex);
+               dput(nd->path.dentry);
+               nd->path.dentry = dentry;
+               goto common;
        }
 
        /*
@@ -2381,7 +2242,40 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
        if (S_ISDIR(nd->inode->i_mode))
                goto exit;
 ok:
-       filp = finish_open(nd, open_flag, acc_mode);
+       if (!S_ISREG(nd->inode->i_mode))
+               will_truncate = 0;
+
+       if (will_truncate) {
+               error = mnt_want_write(nd->path.mnt);
+               if (error)
+                       goto exit;
+               want_write = 1;
+       }
+common:
+       error = may_open(&nd->path, acc_mode, open_flag);
+       if (error)
+               goto exit;
+       filp = nameidata_to_filp(nd);
+       if (!IS_ERR(filp)) {
+               error = ima_file_check(filp, op->acc_mode);
+               if (error) {
+                       fput(filp);
+                       filp = ERR_PTR(error);
+               }
+       }
+       if (!IS_ERR(filp)) {
+               if (will_truncate) {
+                       error = handle_truncate(filp);
+                       if (error) {
+                               fput(filp);
+                               filp = ERR_PTR(error);
+                       }
+               }
+       }
+out:
+       if (want_write)
+               mnt_drop_write(nd->path.mnt);
+       path_put(&nd->path);
        return filp;
 
 exit_mutex_unlock:
@@ -2389,199 +2283,103 @@ exit_mutex_unlock:
 exit_dput:
        path_put_conditional(path, nd);
 exit:
-       if (!IS_ERR(nd->intent.open.file))
-               release_open_intent(nd);
-       path_put(&nd->path);
-       return ERR_PTR(error);
+       filp = ERR_PTR(error);
+       goto out;
 }
 
-/*
- * Note that the low bits of the passed in "open_flag"
- * are not the same as in the local variable "flag". See
- * open_to_namei_flags() for more details.
- */
-struct file *do_filp_open(int dfd, const char *pathname,
-               int open_flag, int mode, int acc_mode)
+static struct file *path_openat(int dfd, const char *pathname,
+               struct nameidata *nd, const struct open_flags *op, int flags)
 {
+       struct file *base = NULL;
        struct file *filp;
-       struct nameidata nd;
-       int error;
        struct path path;
-       int count = 0;
-       int flag = open_to_namei_flags(open_flag);
-       int flags;
-
-       if (!(open_flag & O_CREAT))
-               mode = 0;
-
-       /* Must never be set by userspace */
-       open_flag &= ~FMODE_NONOTIFY;
-
-       /*
-        * O_SYNC is implemented as __O_SYNC|O_DSYNC.  As many places only
-        * check for O_DSYNC if the need any syncing at all we enforce it's
-        * always set instead of having to deal with possibly weird behaviour
-        * for malicious applications setting only __O_SYNC.
-        */
-       if (open_flag & __O_SYNC)
-               open_flag |= O_DSYNC;
-
-       if (!acc_mode)
-               acc_mode = MAY_OPEN | ACC_MODE(open_flag);
-
-       /* O_TRUNC implies we need access checks for write permissions */
-       if (open_flag & O_TRUNC)
-               acc_mode |= MAY_WRITE;
-
-       /* Allow the LSM permission hook to distinguish append 
-          access from general write access. */
-       if (open_flag & O_APPEND)
-               acc_mode |= MAY_APPEND;
-
-       flags = LOOKUP_OPEN;
-       if (open_flag & O_CREAT) {
-               flags |= LOOKUP_CREATE;
-               if (open_flag & O_EXCL)
-                       flags |= LOOKUP_EXCL;
-       }
-       if (open_flag & O_DIRECTORY)
-               flags |= LOOKUP_DIRECTORY;
-       if (!(open_flag & O_NOFOLLOW))
-               flags |= LOOKUP_FOLLOW;
+       int error;
 
        filp = get_empty_filp();
        if (!filp)
                return ERR_PTR(-ENFILE);
 
-       filp->f_flags = open_flag;
-       nd.intent.open.file = filp;
-       nd.intent.open.flags = flag;
-       nd.intent.open.create_mode = mode;
+       filp->f_flags = op->open_flag;
+       nd->intent.open.file = filp;
+       nd->intent.open.flags = open_to_namei_flags(op->open_flag);
+       nd->intent.open.create_mode = op->mode;
 
-       if (open_flag & O_CREAT)
-               goto creat;
-
-       /* !O_CREAT, simple open */
-       error = do_path_lookup(dfd, pathname, flags, &nd);
+       error = path_init(dfd, pathname, flags | LOOKUP_PARENT, nd, &base);
        if (unlikely(error))
                goto out_filp;
-       error = -ELOOP;
-       if (!(nd.flags & LOOKUP_FOLLOW)) {
-               if (nd.inode->i_op->follow_link)
-                       goto out_path;
-       }
-       error = -ENOTDIR;
-       if (nd.flags & LOOKUP_DIRECTORY) {
-               if (!nd.inode->i_op->lookup)
-                       goto out_path;
-       }
-       audit_inode(pathname, nd.path.dentry);
-       filp = finish_open(&nd, open_flag, acc_mode);
-       return filp;
 
-creat:
-       /* OK, have to create the file. Find the parent. */
-       error = path_init_rcu(dfd, pathname,
-                       LOOKUP_PARENT | (flags & LOOKUP_REVAL), &nd);
-       if (error)
-               goto out_filp;
-       error = path_walk_rcu(pathname, &nd);
-       path_finish_rcu(&nd);
-       if (unlikely(error == -ECHILD || error == -ESTALE)) {
-               /* slower, locked walk */
-               if (error == -ESTALE) {
-reval:
-                       flags |= LOOKUP_REVAL;
-               }
-               error = path_init(dfd, pathname,
-                               LOOKUP_PARENT | (flags & LOOKUP_REVAL), &nd);
-               if (error)
-                       goto out_filp;
-
-               error = path_walk_simple(pathname, &nd);
-       }
+       current->total_link_count = 0;
+       error = link_path_walk(pathname, nd);
        if (unlikely(error))
                goto out_filp;
-       if (unlikely(!audit_dummy_context()))
-               audit_inode(pathname, nd.path.dentry);
 
-       /*
-        * We have the parent and last component.
-        */
-       nd.flags = flags;
-       filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);
+       filp = do_last(nd, &path, op, pathname);
        while (unlikely(!filp)) { /* trailing symlink */
                struct path link = path;
-               struct inode *linki = link.dentry->d_inode;
                void *cookie;
-               error = -ELOOP;
-               if (!(nd.flags & LOOKUP_FOLLOW))
-                       goto exit_dput;
-               if (count++ == 32)
-                       goto exit_dput;
-               /*
-                * This is subtle. Instead of calling do_follow_link() we do
-                * the thing by hands. The reason is that this way we have zero
-                * link_count and path_walk() (called from ->follow_link)
-                * honoring LOOKUP_PARENT.  After that we have the parent and
-                * last component, i.e. we are in the same situation as after
-                * the first path_walk().  Well, almost - if the last component
-                * is normal we get its copy stored in nd->last.name and we will
-                * have to putname() it when we are done. Procfs-like symlinks
-                * just set LAST_BIND.
-                */
-               nd.flags |= LOOKUP_PARENT;
-               error = security_inode_follow_link(link.dentry, &nd);
-               if (error)
-                       goto exit_dput;
-               error = __do_follow_link(&link, &nd, &cookie);
-               if (unlikely(error)) {
-                       if (!IS_ERR(cookie) && linki->i_op->put_link)
-                               linki->i_op->put_link(link.dentry, &nd, cookie);
-                       /* nd.path had been dropped */
-                       nd.path = link;
-                       goto out_path;
+               if (!(nd->flags & LOOKUP_FOLLOW)) {
+                       path_put_conditional(&path, nd);
+                       path_put(&nd->path);
+                       filp = ERR_PTR(-ELOOP);
+                       break;
                }
-               nd.flags &= ~LOOKUP_PARENT;
-               filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);
-               if (linki->i_op->put_link)
-                       linki->i_op->put_link(link.dentry, &nd, cookie);
-               path_put(&link);
+               nd->flags |= LOOKUP_PARENT;
+               nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL);
+               error = follow_link(&link, nd, &cookie);
+               if (unlikely(error))
+                       filp = ERR_PTR(error);
+               else
+                       filp = do_last(nd, &path, op, pathname);
+               put_link(nd, &link, cookie);
        }
 out:
-       if (nd.root.mnt)
-               path_put(&nd.root);
-       if (filp == ERR_PTR(-ESTALE) && !(flags & LOOKUP_REVAL))
-               goto reval;
+       if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT))
+               path_put(&nd->root);
+       if (base)
+               fput(base);
+       release_open_intent(nd);
        return filp;
 
-exit_dput:
-       path_put_conditional(&path, &nd);
-out_path:
-       path_put(&nd.path);
 out_filp:
-       if (!IS_ERR(nd.intent.open.file))
-               release_open_intent(&nd);
        filp = ERR_PTR(error);
        goto out;
 }
 
-/**
- * filp_open - open file and return file pointer
- *
- * @filename:  path to open
- * @flags:     open flags as per the open(2) second argument
- * @mode:      mode for the new file if O_CREAT is set, else ignored
- *
- * This is the helper to open a file from kernelspace if you really
- * have to.  But in generally you should not do this, so please move
- * along, nothing to see here..
- */
-struct file *filp_open(const char *filename, int flags, int mode)
+struct file *do_filp_open(int dfd, const char *pathname,
+               const struct open_flags *op, int flags)
+{
+       struct nameidata nd;
+       struct file *filp;
+
+       filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_RCU);
+       if (unlikely(filp == ERR_PTR(-ECHILD)))
+               filp = path_openat(dfd, pathname, &nd, op, flags);
+       if (unlikely(filp == ERR_PTR(-ESTALE)))
+               filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_REVAL);
+       return filp;
+}
+
+struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
+               const char *name, const struct open_flags *op, int flags)
 {
-       return do_filp_open(AT_FDCWD, filename, flags, mode, 0);
+       struct nameidata nd;
+       struct file *file;
+
+       nd.root.mnt = mnt;
+       nd.root.dentry = dentry;
+
+       flags |= LOOKUP_ROOT;
+
+       if (dentry->d_inode->i_op->follow_link && op->intent & LOOKUP_OPEN)
+               return ERR_PTR(-ELOOP);
+
+       file = path_openat(-1, name, &nd, op, flags | LOOKUP_RCU);
+       if (unlikely(file == ERR_PTR(-ECHILD)))
+               file = path_openat(-1, name, &nd, op, flags);
+       if (unlikely(file == ERR_PTR(-ESTALE)))
+               file = path_openat(-1, name, &nd, op, flags | LOOKUP_REVAL);
+       return file;
 }
-EXPORT_SYMBOL(filp_open);
 
 /**
  * lookup_create - lookup a dentry, creating it if it doesn't exist
@@ -3120,7 +2918,11 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
                return error;
 
        mutex_lock(&inode->i_mutex);
-       error = dir->i_op->link(old_dentry, dir, new_dentry);
+       /* Make sure we don't allow creating hardlink to an unlinked file */
+       if (inode->i_nlink == 0)
+               error =  -ENOENT;
+       else
+               error = dir->i_op->link(old_dentry, dir, new_dentry);
        mutex_unlock(&inode->i_mutex);
        if (!error)
                fsnotify_link(dir, inode, new_dentry);
@@ -3142,15 +2944,27 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
        struct dentry *new_dentry;
        struct nameidata nd;
        struct path old_path;
+       int how = 0;
        int error;
        char *to;
 
-       if ((flags & ~AT_SYMLINK_FOLLOW) != 0)
+       if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
                return -EINVAL;
+       /*
+        * To use null names we require CAP_DAC_READ_SEARCH
+        * This ensures that not everyone will be able to create
+        * handlink using the passed filedescriptor.
+        */
+       if (flags & AT_EMPTY_PATH) {
+               if (!capable(CAP_DAC_READ_SEARCH))
+                       return -ENOENT;
+               how = LOOKUP_EMPTY;
+       }
+
+       if (flags & AT_SYMLINK_FOLLOW)
+               how |= LOOKUP_FOLLOW;
 
-       error = user_path_at(olddfd, oldname,
-                            flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0,
-                            &old_path);
+       error = user_path_at(olddfd, oldname, how, &old_path);
        if (error)
                return error;
 
@@ -3587,7 +3401,7 @@ EXPORT_SYMBOL(page_readlink);
 EXPORT_SYMBOL(__page_symlink);
 EXPORT_SYMBOL(page_symlink);
 EXPORT_SYMBOL(page_symlink_inode_operations);
-EXPORT_SYMBOL(path_lookup);
+EXPORT_SYMBOL(kern_path_parent);
 EXPORT_SYMBOL(kern_path);
 EXPORT_SYMBOL(vfs_path_lookup);
 EXPORT_SYMBOL(inode_permission);
index 7b0b953..dffe6f4 100644 (file)
@@ -1002,6 +1002,18 @@ const struct seq_operations mounts_op = {
        .show   = show_vfsmnt
 };
 
+static int uuid_is_nil(u8 *uuid)
+{
+       int i;
+       u8  *cp = (u8 *)uuid;
+
+       for (i = 0; i < 16; i++) {
+               if (*cp++)
+                       return 0;
+       }
+       return 1;
+}
+
 static int show_mountinfo(struct seq_file *m, void *v)
 {
        struct proc_mounts *p = m->private;
@@ -1040,6 +1052,10 @@ static int show_mountinfo(struct seq_file *m, void *v)
        if (IS_MNT_UNBINDABLE(mnt))
                seq_puts(m, " unbindable");
 
+       if (!uuid_is_nil(mnt->mnt_sb->s_uuid))
+               /* print the uuid */
+               seq_printf(m, " uuid:%pU", mnt->mnt_sb->s_uuid);
+
        /* Filesystem specific data */
        seq_puts(m, " - ");
        show_type(m, sb);
@@ -1244,7 +1260,7 @@ static int do_umount(struct vfsmount *mnt, int flags)
                 */
                br_write_lock(vfsmount_lock);
                if (mnt_get_count(mnt) != 2) {
-                       br_write_lock(vfsmount_lock);
+                       br_write_unlock(vfsmount_lock);
                        return -EBUSY;
                }
                br_write_unlock(vfsmount_lock);
index 1990165..e3d2942 100644 (file)
@@ -134,33 +134,6 @@ out_err:
 }
 
 #if defined(CONFIG_NFS_V4_1)
-/*
- *  * CB_SEQUENCE operations will fail until the callback sessionid is set.
- *   */
-int nfs4_set_callback_sessionid(struct nfs_client *clp)
-{
-       struct svc_serv *serv = clp->cl_rpcclient->cl_xprt->bc_serv;
-       struct nfs4_sessionid *bc_sid;
-
-       if (!serv->sv_bc_xprt)
-               return -EINVAL;
-
-       /* on success freed in xprt_free */
-       bc_sid = kmalloc(sizeof(struct nfs4_sessionid), GFP_KERNEL);
-       if (!bc_sid)
-               return -ENOMEM;
-       memcpy(bc_sid->data, &clp->cl_session->sess_id.data,
-               NFS4_MAX_SESSIONID_LEN);
-       spin_lock_bh(&serv->sv_cb_lock);
-       serv->sv_bc_xprt->xpt_bc_sid = bc_sid;
-       spin_unlock_bh(&serv->sv_cb_lock);
-       dprintk("%s set xpt_bc_sid=%u:%u:%u:%u for sv_bc_xprt %p\n", __func__,
-               ((u32 *)bc_sid->data)[0], ((u32 *)bc_sid->data)[1],
-               ((u32 *)bc_sid->data)[2], ((u32 *)bc_sid->data)[3],
-               serv->sv_bc_xprt);
-       return 0;
-}
-
 /*
  * The callback service for NFSv4.1 callbacks
  */
@@ -266,10 +239,6 @@ static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
                struct nfs_callback_data *cb_info)
 {
 }
-int nfs4_set_callback_sessionid(struct nfs_client *clp)
-{
-       return 0;
-}
 #endif /* CONFIG_NFS_V4_1 */
 
 /*
@@ -359,78 +328,58 @@ void nfs_callback_down(int minorversion)
        mutex_unlock(&nfs_callback_mutex);
 }
 
-static int check_gss_callback_principal(struct nfs_client *clp,
-                                       struct svc_rqst *rqstp)
+/* Boolean check of RPC_AUTH_GSS principal */
+int
+check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp)
 {
        struct rpc_clnt *r = clp->cl_rpcclient;
        char *p = svc_gss_principal(rqstp);
 
+       if (rqstp->rq_authop->flavour != RPC_AUTH_GSS)
+               return 1;
+
        /* No RPC_AUTH_GSS on NFSv4.1 back channel yet */
        if (clp->cl_minorversion != 0)
-               return SVC_DROP;
+               return 0;
        /*
         * It might just be a normal user principal, in which case
         * userspace won't bother to tell us the name at all.
         */
        if (p == NULL)
-               return SVC_DENIED;
+               return 0;
 
        /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */
 
        if (memcmp(p, "nfs@", 4) != 0)
-               return SVC_DENIED;
+               return 0;
        p += 4;
        if (strcmp(p, r->cl_server) != 0)
-               return SVC_DENIED;
-       return SVC_OK;
+               return 0;
+       return 1;
 }
 
-/* pg_authenticate method helper */
-static struct nfs_client *nfs_cb_find_client(struct svc_rqst *rqstp)
-{
-       struct nfs4_sessionid *sessionid = bc_xprt_sid(rqstp);
-       int is_cb_compound = rqstp->rq_proc == CB_COMPOUND ? 1 : 0;
-
-       dprintk("--> %s rq_proc %d\n", __func__, rqstp->rq_proc);
-       if (svc_is_backchannel(rqstp))
-               /* Sessionid (usually) set after CB_NULL ping */
-               return nfs4_find_client_sessionid(svc_addr(rqstp), sessionid,
-                                                 is_cb_compound);
-       else
-               /* No callback identifier in pg_authenticate */
-               return nfs4_find_client_no_ident(svc_addr(rqstp));
-}
-
-/* pg_authenticate method for nfsv4 callback threads. */
+/*
+ * pg_authenticate method for nfsv4 callback threads.
+ *
+ * The authflavor has been negotiated, so an incorrect flavor is a server
+ * bug. Drop packets with incorrect authflavor.
+ *
+ * All other checking done after NFS decoding where the nfs_client can be
+ * found in nfs4_callback_compound
+ */
 static int nfs_callback_authenticate(struct svc_rqst *rqstp)
 {
-       struct nfs_client *clp;
-       RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
-       int ret = SVC_OK;
-
-       /* Don't talk to strangers */
-       clp = nfs_cb_find_client(rqstp);
-       if (clp == NULL)
-               return SVC_DROP;
-
-       dprintk("%s: %s NFSv4 callback!\n", __func__,
-                       svc_print_addr(rqstp, buf, sizeof(buf)));
-
        switch (rqstp->rq_authop->flavour) {
-               case RPC_AUTH_NULL:
-                       if (rqstp->rq_proc != CB_NULL)
-                               ret = SVC_DENIED;
-                       break;
-               case RPC_AUTH_UNIX:
-                       break;
-               case RPC_AUTH_GSS:
-                       ret = check_gss_callback_principal(clp, rqstp);
-                       break;
-               default:
-                       ret = SVC_DENIED;
+       case RPC_AUTH_NULL:
+               if (rqstp->rq_proc != CB_NULL)
+                       return SVC_DROP;
+               break;
+       case RPC_AUTH_GSS:
+               /* No RPC_AUTH_GSS support yet in NFSv4.1 */
+                if (svc_is_backchannel(rqstp))
+                       return SVC_DROP;
        }
-       nfs_put_client(clp);
-       return ret;
+       return SVC_OK;
 }
 
 /*
index d3b44f9..46d93ce 100644 (file)
@@ -7,6 +7,7 @@
  */
 #ifndef __LINUX_FS_NFS_CALLBACK_H
 #define __LINUX_FS_NFS_CALLBACK_H
+#include <linux/sunrpc/svc.h>
 
 #define NFS4_CALLBACK 0x40000000
 #define NFS4_CALLBACK_XDRSIZE 2048
@@ -37,7 +38,6 @@ enum nfs4_callback_opnum {
 struct cb_process_state {
        __be32                  drc_status;
        struct nfs_client       *clp;
-       struct nfs4_sessionid   *svc_sid; /* v4.1 callback service sessionid */
 };
 
 struct cb_compound_hdr_arg {
@@ -168,7 +168,7 @@ extern unsigned nfs4_callback_layoutrecall(
 extern void nfs4_check_drain_bc_complete(struct nfs4_session *ses);
 extern void nfs4_cb_take_slot(struct nfs_client *clp);
 #endif /* CONFIG_NFS_V4_1 */
-
+extern int check_gss_callback_principal(struct nfs_client *, struct svc_rqst *);
 extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args,
                                    struct cb_getattrres *res,
                                    struct cb_process_state *cps);
index 4bb91cb..8958757 100644 (file)
@@ -373,17 +373,11 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
 {
        struct nfs_client *clp;
        int i;
-       __be32 status;
+       __be32 status = htonl(NFS4ERR_BADSESSION);
 
        cps->clp = NULL;
 
-       status = htonl(NFS4ERR_BADSESSION);
-       /* Incoming session must match the callback session */
-       if (memcmp(&args->csa_sessionid, cps->svc_sid, NFS4_MAX_SESSIONID_LEN))
-               goto out;
-
-       clp = nfs4_find_client_sessionid(args->csa_addr,
-                                        &args->csa_sessionid, 1);
+       clp = nfs4_find_client_sessionid(args->csa_addr, &args->csa_sessionid);
        if (clp == NULL)
                goto out;
 
@@ -414,9 +408,9 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
        res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
        res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
        nfs4_cb_take_slot(clp);
-       cps->clp = clp; /* put in nfs4_callback_compound */
 
 out:
+       cps->clp = clp; /* put in nfs4_callback_compound */
        for (i = 0; i < args->csa_nrclists; i++)
                kfree(args->csa_rclists[i].rcl_refcalls);
        kfree(args->csa_rclists);
index 23112c2..14e0f93 100644 (file)
@@ -794,10 +794,9 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
 
        if (hdr_arg.minorversion == 0) {
                cps.clp = nfs4_find_client_ident(hdr_arg.cb_ident);
-               if (!cps.clp)
+               if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp))
                        return rpc_drop_reply;
-       } else
-               cps.svc_sid = bc_xprt_sid(rqstp);
+       }
 
        hdr_res.taglen = hdr_arg.taglen;
        hdr_res.tag = hdr_arg.tag;
index 192f2f8..bd3ca32 100644 (file)
@@ -1206,16 +1206,11 @@ nfs4_find_client_ident(int cb_ident)
  * For CB_COMPOUND calls, find a client by IP address, protocol version,
  * minorversion, and sessionID
  *
- * CREATE_SESSION triggers a CB_NULL ping from servers. The callback service
- * sessionid can only be set after the CREATE_SESSION return, so a CB_NULL
- * can arrive before the callback sessionid is set. For CB_NULL calls,
- * find a client by IP address protocol version, and minorversion.
- *
  * Returns NULL if no such client
  */
 struct nfs_client *
 nfs4_find_client_sessionid(const struct sockaddr *addr,
-                          struct nfs4_sessionid *sid, int is_cb_compound)
+                          struct nfs4_sessionid *sid)
 {
        struct nfs_client *clp;
 
@@ -1227,9 +1222,9 @@ nfs4_find_client_sessionid(const struct sockaddr *addr,
                if (!nfs4_has_session(clp))
                        continue;
 
-               /* Match sessionid unless cb_null call*/
-               if (is_cb_compound && (memcmp(clp->cl_session->sess_id.data,
-                   sid->data, NFS4_MAX_SESSIONID_LEN) != 0))
+               /* Match sessionid*/
+               if (memcmp(clp->cl_session->sess_id.data,
+                   sid->data, NFS4_MAX_SESSIONID_LEN) != 0)
                        continue;
 
                atomic_inc(&clp->cl_count);
@@ -1244,7 +1239,7 @@ nfs4_find_client_sessionid(const struct sockaddr *addr,
 
 struct nfs_client *
 nfs4_find_client_sessionid(const struct sockaddr *addr,
-                          struct nfs4_sessionid *sid, int is_cb_compound)
+                          struct nfs4_sessionid *sid)
 {
        return NULL;
 }
index 364e432..bbbc6bf 100644 (file)
@@ -23,8 +23,6 @@
 
 static void nfs_do_free_delegation(struct nfs_delegation *delegation)
 {
-       if (delegation->cred)
-               put_rpccred(delegation->cred);
        kfree(delegation);
 }
 
@@ -37,6 +35,10 @@ static void nfs_free_delegation_callback(struct rcu_head *head)
 
 static void nfs_free_delegation(struct nfs_delegation *delegation)
 {
+       if (delegation->cred) {
+               put_rpccred(delegation->cred);
+               delegation->cred = NULL;
+       }
        call_rcu(&delegation->rcu, nfs_free_delegation_callback);
 }
 
index e6ace0d..9943a75 100644 (file)
@@ -407,15 +407,18 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
                pos += vec->iov_len;
        }
 
+       /*
+        * If no bytes were started, return the error, and let the
+        * generic layer handle the completion.
+        */
+       if (requested_bytes == 0) {
+               nfs_direct_req_release(dreq);
+               return result < 0 ? result : -EIO;
+       }
+
        if (put_dreq(dreq))
                nfs_direct_complete(dreq);
-
-       if (requested_bytes != 0)
-               return 0;
-
-       if (result < 0)
-               return result;
-       return -EIO;
+       return 0;
 }
 
 static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov,
@@ -841,15 +844,18 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
                pos += vec->iov_len;
        }
 
+       /*
+        * If no bytes were started, return the error, and let the
+        * generic layer handle the completion.
+        */
+       if (requested_bytes == 0) {
+               nfs_direct_req_release(dreq);
+               return result < 0 ? result : -EIO;
+       }
+
        if (put_dreq(dreq))
                nfs_direct_write_complete(dreq, dreq->inode);
-
-       if (requested_bytes != 0)
-               return 0;
-
-       if (result < 0)
-               return result;
-       return -EIO;
+       return 0;
 }
 
 static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov,
index d851242..01768e5 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/inet.h>
 #include <linux/nfs_xdr.h>
 #include <linux/slab.h>
+#include <linux/compat.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -89,7 +90,11 @@ int nfs_wait_bit_killable(void *word)
  */
 u64 nfs_compat_user_ino64(u64 fileid)
 {
-       int ino;
+#ifdef CONFIG_COMPAT
+       compat_ulong_t ino;
+#else  
+       unsigned long ino;
+#endif
 
        if (enable_ino64)
                return fileid;
@@ -881,9 +886,10 @@ out:
        return ret;
 }
 
-static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
+static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
+       unsigned long ret = 0;
 
        if ((fattr->valid & NFS_ATTR_FATTR_PRECHANGE)
                        && (fattr->valid & NFS_ATTR_FATTR_CHANGE)
@@ -891,25 +897,32 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                nfsi->change_attr = fattr->change_attr;
                if (S_ISDIR(inode->i_mode))
                        nfsi->cache_validity |= NFS_INO_INVALID_DATA;
+               ret |= NFS_INO_INVALID_ATTR;
        }
        /* If we have atomic WCC data, we may update some attributes */
        if ((fattr->valid & NFS_ATTR_FATTR_PRECTIME)
                        && (fattr->valid & NFS_ATTR_FATTR_CTIME)
-                       && timespec_equal(&inode->i_ctime, &fattr->pre_ctime))
-                       memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
+                       && timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) {
+               memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
+               ret |= NFS_INO_INVALID_ATTR;
+       }
 
        if ((fattr->valid & NFS_ATTR_FATTR_PREMTIME)
                        && (fattr->valid & NFS_ATTR_FATTR_MTIME)
                        && timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) {
-                       memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
-                       if (S_ISDIR(inode->i_mode))
-                               nfsi->cache_validity |= NFS_INO_INVALID_DATA;
+               memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
+               if (S_ISDIR(inode->i_mode))
+                       nfsi->cache_validity |= NFS_INO_INVALID_DATA;
+               ret |= NFS_INO_INVALID_ATTR;
        }
        if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE)
                        && (fattr->valid & NFS_ATTR_FATTR_SIZE)
                        && i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size)
-                       && nfsi->npages == 0)
-                       i_size_write(inode, nfs_size_to_loff_t(fattr->size));
+                       && nfsi->npages == 0) {
+               i_size_write(inode, nfs_size_to_loff_t(fattr->size));
+               ret |= NFS_INO_INVALID_ATTR;
+       }
+       return ret;
 }
 
 /**
@@ -1223,7 +1236,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        | NFS_INO_REVAL_PAGECACHE);
 
        /* Do atomic weak cache consistency updates */
-       nfs_wcc_update_inode(inode, fattr);
+       invalid |= nfs_wcc_update_inode(inode, fattr);
 
        /* More cache consistency checks */
        if (fattr->valid & NFS_ATTR_FATTR_CHANGE) {
@@ -1505,7 +1518,7 @@ static int nfsiod_start(void)
 {
        struct workqueue_struct *wq;
        dprintk("RPC:       creating workqueue nfsiod\n");
-       wq = alloc_workqueue("nfsiod", WQ_RESCUER, 0);
+       wq = alloc_workqueue("nfsiod", WQ_MEM_RECLAIM, 0);
        if (wq == NULL)
                return -ENOMEM;
        nfsiod_workqueue = wq;
index 4644f04..cf9fdbd 100644 (file)
@@ -133,8 +133,7 @@ extern void nfs_put_client(struct nfs_client *);
 extern struct nfs_client *nfs4_find_client_no_ident(const struct sockaddr *);
 extern struct nfs_client *nfs4_find_client_ident(int);
 extern struct nfs_client *
-nfs4_find_client_sessionid(const struct sockaddr *, struct nfs4_sessionid *,
-                          int);
+nfs4_find_client_sessionid(const struct sockaddr *, struct nfs4_sessionid *);
 extern struct nfs_server *nfs_create_server(
                                        const struct nfs_parsed_mount_data *,
                                        struct nfs_fh *);
index 9f88c5f..2743427 100644 (file)
@@ -311,8 +311,8 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
        if (!nfs_server_capable(inode, NFS_CAP_ACLS))
                goto out;
 
-       /* We are doing this here, because XDR marshalling can only
-          return -ENOMEM. */
+       /* We are doing this here because XDR marshalling does not
+        * return any results, it BUGs. */
        status = -ENOSPC;
        if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES)
                goto out;
index 01c5e8b..183c6b1 100644 (file)
@@ -1328,10 +1328,13 @@ static void nfs3_xdr_enc_setacl3args(struct rpc_rqst *req,
 
        encode_nfs_fh3(xdr, NFS_FH(args->inode));
        encode_uint32(xdr, args->mask);
+
+       base = req->rq_slen;
        if (args->npages != 0)
                xdr_write_pages(xdr, args->pages, 0, args->len);
+       else
+               xdr_reserve_space(xdr, NFS_ACL_INLINE_BUFSIZE);
 
-       base = req->rq_slen;
        error = nfsacl_encode(xdr->buf, base, args->inode,
                            (args->mask & NFS_ACL) ?
                            args->acl_access : NULL, 1, 0);
index 7a74740..1be36cf 100644 (file)
@@ -298,6 +298,11 @@ struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp);
 #if defined(CONFIG_NFS_V4_1)
 struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp);
 struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp);
+extern void nfs4_schedule_session_recovery(struct nfs4_session *);
+#else
+static inline void nfs4_schedule_session_recovery(struct nfs4_session *session)
+{
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *);
@@ -307,10 +312,9 @@ extern void nfs4_put_open_state(struct nfs4_state *);
 extern void nfs4_close_state(struct path *, struct nfs4_state *, fmode_t);
 extern void nfs4_close_sync(struct path *, struct nfs4_state *, fmode_t);
 extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t);
-extern void nfs4_schedule_state_recovery(struct nfs_client *);
+extern void nfs4_schedule_lease_recovery(struct nfs_client *);
 extern void nfs4_schedule_state_manager(struct nfs_client *);
-extern int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state);
-extern int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state);
+extern void nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs4_state *);
 extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags);
 extern void nfs41_handle_recall_slot(struct nfs_client *clp);
 extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
index 51fe64a..b73c343 100644 (file)
@@ -214,17 +214,26 @@ decode_and_add_ds(__be32 **pp, struct inode *inode)
 
        /* ipv6 length plus port is legal */
        if (rlen > INET6_ADDRSTRLEN + 8) {
-               dprintk("%s Invalid address, length %d\n", __func__,
+               dprintk("%s: Invalid address, length %d\n", __func__,
                        rlen);
                goto out_err;
        }
        buf = kmalloc(rlen + 1, GFP_KERNEL);
+       if (!buf) {
+               dprintk("%s: Not enough memory\n", __func__);
+               goto out_err;
+       }
        buf[rlen] = '\0';
        memcpy(buf, r_addr, rlen);
 
        /* replace the port dots with dashes for the in4_pton() delimiter*/
        for (i = 0; i < 2; i++) {
                char *res = strrchr(buf, '.');
+               if (!res) {
+                       dprintk("%s: Failed finding expected dots in port\n",
+                               __func__);
+                       goto out_free;
+               }
                *res = '-';
        }
 
@@ -240,7 +249,7 @@ decode_and_add_ds(__be32 **pp, struct inode *inode)
        port = htons((tmp[0] << 8) | (tmp[1]));
 
        ds = nfs4_pnfs_ds_add(inode, ip_addr, port);
-       dprintk("%s Decoded address and port %s\n", __func__, buf);
+       dprintk("%s: Decoded address and port %s\n", __func__, buf);
 out_free:
        kfree(buf);
 out_err:
index 9d992b0..0a07e35 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/module.h>
 #include <linux/sunrpc/bc_xprt.h>
 #include <linux/xattr.h>
+#include <linux/utsname.h>
 
 #include "nfs4_fs.h"
 #include "delegation.h"
@@ -255,12 +256,13 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode,
                case -NFS4ERR_OPENMODE:
                        if (state == NULL)
                                break;
-                       nfs4_state_mark_reclaim_nograce(clp, state);
-                       goto do_state_recovery;
+                       nfs4_schedule_stateid_recovery(server, state);
+                       goto wait_on_recovery;
                case -NFS4ERR_STALE_STATEID:
                case -NFS4ERR_STALE_CLIENTID:
                case -NFS4ERR_EXPIRED:
-                       goto do_state_recovery;
+                       nfs4_schedule_lease_recovery(clp);
+                       goto wait_on_recovery;
 #if defined(CONFIG_NFS_V4_1)
                case -NFS4ERR_BADSESSION:
                case -NFS4ERR_BADSLOT:
@@ -271,7 +273,7 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode,
                case -NFS4ERR_SEQ_MISORDERED:
                        dprintk("%s ERROR: %d Reset session\n", __func__,
                                errorcode);
-                       nfs4_schedule_state_recovery(clp);
+                       nfs4_schedule_session_recovery(clp->cl_session);
                        exception->retry = 1;
                        break;
 #endif /* defined(CONFIG_NFS_V4_1) */
@@ -294,8 +296,7 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode,
        }
        /* We failed to handle the error */
        return nfs4_map_errors(ret);
-do_state_recovery:
-       nfs4_schedule_state_recovery(clp);
+wait_on_recovery:
        ret = nfs4_wait_clnt_recover(clp);
        if (ret == 0)
                exception->retry = 1;
@@ -434,8 +435,8 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *
                clp = res->sr_session->clp;
                do_renew_lease(clp, timestamp);
                /* Check sequence flags */
-               if (atomic_read(&clp->cl_count) > 1)
-                       nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags);
+               if (res->sr_status_flags != 0)
+                       nfs4_schedule_lease_recovery(clp);
                break;
        case -NFS4ERR_DELAY:
                /* The server detected a resend of the RPC call and
@@ -1254,14 +1255,13 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
                        case -NFS4ERR_BAD_HIGH_SLOT:
                        case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
                        case -NFS4ERR_DEADSESSION:
-                               nfs4_schedule_state_recovery(
-                                       server->nfs_client);
+                               nfs4_schedule_session_recovery(server->nfs_client->cl_session);
                                goto out;
                        case -NFS4ERR_STALE_CLIENTID:
                        case -NFS4ERR_STALE_STATEID:
                        case -NFS4ERR_EXPIRED:
                                /* Don't recall a delegation if it was lost */
-                               nfs4_schedule_state_recovery(server->nfs_client);
+                               nfs4_schedule_lease_recovery(server->nfs_client);
                                goto out;
                        case -ERESTARTSYS:
                                /*
@@ -1270,7 +1270,7 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
                                 */
                        case -NFS4ERR_ADMIN_REVOKED:
                        case -NFS4ERR_BAD_STATEID:
-                               nfs4_state_mark_reclaim_nograce(server->nfs_client, state);
+                               nfs4_schedule_stateid_recovery(server, state);
                        case -EKEYEXPIRED:
                                /*
                                 * User RPCSEC_GSS context has expired.
@@ -1586,7 +1586,7 @@ static int nfs4_recover_expired_lease(struct nfs_server *server)
                if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) &&
                    !test_bit(NFS4CLNT_CHECK_LEASE,&clp->cl_state))
                        break;
-               nfs4_schedule_state_recovery(clp);
+               nfs4_schedule_state_manager(clp);
                ret = -EIO;
        }
        return ret;
@@ -3177,7 +3177,7 @@ static void nfs4_renew_done(struct rpc_task *task, void *calldata)
        if (task->tk_status < 0) {
                /* Unless we're shutting down, schedule state recovery! */
                if (test_bit(NFS_CS_RENEWD, &clp->cl_res_state) != 0)
-                       nfs4_schedule_state_recovery(clp);
+                       nfs4_schedule_lease_recovery(clp);
                return;
        }
        do_renew_lease(clp, timestamp);
@@ -3251,6 +3251,35 @@ static void buf_to_pages(const void *buf, size_t buflen,
        }
 }
 
+static int buf_to_pages_noslab(const void *buf, size_t buflen,
+               struct page **pages, unsigned int *pgbase)
+{
+       struct page *newpage, **spages;
+       int rc = 0;
+       size_t len;
+       spages = pages;
+
+       do {
+               len = min_t(size_t, PAGE_CACHE_SIZE, buflen);
+               newpage = alloc_page(GFP_KERNEL);
+
+               if (newpage == NULL)
+                       goto unwind;
+               memcpy(page_address(newpage), buf, len);
+                buf += len;
+                buflen -= len;
+               *pages++ = newpage;
+               rc++;
+       } while (buflen != 0);
+
+       return rc;
+
+unwind:
+       for(; rc > 0; rc--)
+               __free_page(spages[rc-1]);
+       return -ENOMEM;
+}
+
 struct nfs4_cached_acl {
        int cached;
        size_t len;
@@ -3419,13 +3448,23 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
                .rpc_argp       = &arg,
                .rpc_resp       = &res,
        };
-       int ret;
+       int ret, i;
 
        if (!nfs4_server_supports_acls(server))
                return -EOPNOTSUPP;
+       i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
+       if (i < 0)
+               return i;
        nfs_inode_return_delegation(inode);
-       buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
        ret = nfs4_call_sync(server, &msg, &arg, &res, 1);
+
+       /*
+        * Free each page after tx, so the only ref left is
+        * held by the network stack
+        */
+       for (; i > 0; i--)
+               put_page(pages[i-1]);
+
        /*
         * Acl update can result in inode attribute update.
         * so mark the attribute cache invalid.
@@ -3463,12 +3502,13 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
                case -NFS4ERR_OPENMODE:
                        if (state == NULL)
                                break;
-                       nfs4_state_mark_reclaim_nograce(clp, state);
-                       goto do_state_recovery;
+                       nfs4_schedule_stateid_recovery(server, state);
+                       goto wait_on_recovery;
                case -NFS4ERR_STALE_STATEID:
                case -NFS4ERR_STALE_CLIENTID:
                case -NFS4ERR_EXPIRED:
-                       goto do_state_recovery;
+                       nfs4_schedule_lease_recovery(clp);
+                       goto wait_on_recovery;
 #if defined(CONFIG_NFS_V4_1)
                case -NFS4ERR_BADSESSION:
                case -NFS4ERR_BADSLOT:
@@ -3479,7 +3519,7 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
                case -NFS4ERR_SEQ_MISORDERED:
                        dprintk("%s ERROR %d, Reset session\n", __func__,
                                task->tk_status);
-                       nfs4_schedule_state_recovery(clp);
+                       nfs4_schedule_session_recovery(clp->cl_session);
                        task->tk_status = 0;
                        return -EAGAIN;
 #endif /* CONFIG_NFS_V4_1 */
@@ -3496,9 +3536,8 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
        }
        task->tk_status = nfs4_map_errors(task->tk_status);
        return 0;
-do_state_recovery:
+wait_on_recovery:
        rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL);
-       nfs4_schedule_state_recovery(clp);
        if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0)
                rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task);
        task->tk_status = 0;
@@ -4109,7 +4148,7 @@ static void nfs4_lock_release(void *calldata)
                task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp,
                                data->arg.lock_seqid);
                if (!IS_ERR(task))
-                       rpc_put_task(task);
+                       rpc_put_task_async(task);
                dprintk("%s: cancelling lock!\n", __func__);
        } else
                nfs_free_seqid(data->arg.lock_seqid);
@@ -4133,23 +4172,18 @@ static const struct rpc_call_ops nfs4_recover_lock_ops = {
 
 static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_state *lsp, int new_lock_owner, int error)
 {
-       struct nfs_client *clp = server->nfs_client;
-       struct nfs4_state *state = lsp->ls_state;
-
        switch (error) {
        case -NFS4ERR_ADMIN_REVOKED:
        case -NFS4ERR_BAD_STATEID:
-       case -NFS4ERR_EXPIRED:
+               lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
                if (new_lock_owner != 0 ||
                   (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0)
-                       nfs4_state_mark_reclaim_nograce(clp, state);
-               lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
+                       nfs4_schedule_stateid_recovery(server, lsp->ls_state);
                break;
        case -NFS4ERR_STALE_STATEID:
-               if (new_lock_owner != 0 ||
-                   (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0)
-                       nfs4_state_mark_reclaim_reboot(clp, state);
                lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
+       case -NFS4ERR_EXPIRED:
+               nfs4_schedule_lease_recovery(server->nfs_client);
        };
 }
 
@@ -4365,12 +4399,14 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
                        case -NFS4ERR_EXPIRED:
                        case -NFS4ERR_STALE_CLIENTID:
                        case -NFS4ERR_STALE_STATEID:
+                               nfs4_schedule_lease_recovery(server->nfs_client);
+                               goto out;
                        case -NFS4ERR_BADSESSION:
                        case -NFS4ERR_BADSLOT:
                        case -NFS4ERR_BAD_HIGH_SLOT:
                        case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
                        case -NFS4ERR_DEADSESSION:
-                               nfs4_schedule_state_recovery(server->nfs_client);
+                               nfs4_schedule_session_recovery(server->nfs_client->cl_session);
                                goto out;
                        case -ERESTARTSYS:
                                /*
@@ -4380,7 +4416,7 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
                        case -NFS4ERR_ADMIN_REVOKED:
                        case -NFS4ERR_BAD_STATEID:
                        case -NFS4ERR_OPENMODE:
-                               nfs4_state_mark_reclaim_nograce(server->nfs_client, state);
+                               nfs4_schedule_stateid_recovery(server, state);
                                err = 0;
                                goto out;
                        case -EKEYEXPIRED:
@@ -4572,27 +4608,16 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
        *p = htonl((u32)clp->cl_boot_time.tv_nsec);
        args.verifier = &verifier;
 
-       while (1) {
-               args.id_len = scnprintf(args.id, sizeof(args.id),
-                                       "%s/%s %u",
-                                       clp->cl_ipaddr,
-                                       rpc_peeraddr2str(clp->cl_rpcclient,
-                                                        RPC_DISPLAY_ADDR),
-                                       clp->cl_id_uniquifier);
-
-               status = rpc_call_sync(clp->cl_rpcclient, &msg, 0);
-
-               if (status != -NFS4ERR_CLID_INUSE)
-                       break;
-
-               if (signalled())
-                       break;
-
-               if (++clp->cl_id_uniquifier == 0)
-                       break;
-       }
+       args.id_len = scnprintf(args.id, sizeof(args.id),
+                               "%s/%s.%s/%u",
+                               clp->cl_ipaddr,
+                               init_utsname()->nodename,
+                               init_utsname()->domainname,
+                               clp->cl_rpcclient->cl_auth->au_flavor);
 
-       status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags);
+       status = rpc_call_sync(clp->cl_rpcclient, &msg, 0);
+       if (!status)
+               status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags);
        dprintk("<-- %s status= %d\n", __func__, status);
        return status;
 }
@@ -4998,10 +5023,20 @@ int nfs4_proc_create_session(struct nfs_client *clp)
        int status;
        unsigned *ptr;
        struct nfs4_session *session = clp->cl_session;
+       long timeout = 0;
+       int err;
 
        dprintk("--> %s clp=%p session=%p\n", __func__, clp, session);
 
-       status = _nfs4_proc_create_session(clp);
+       do {
+               status = _nfs4_proc_create_session(clp);
+               if (status == -NFS4ERR_DELAY) {
+                       err = nfs4_delay(clp->cl_rpcclient, &timeout);
+                       if (err)
+                               status = err;
+               }
+       } while (status == -NFS4ERR_DELAY);
+
        if (status)
                goto out;
 
@@ -5110,7 +5145,7 @@ static int nfs41_sequence_handle_errors(struct rpc_task *task, struct nfs_client
                rpc_delay(task, NFS4_POLL_RETRY_MAX);
                return -EAGAIN;
        default:
-               nfs4_schedule_state_recovery(clp);
+               nfs4_schedule_lease_recovery(clp);
        }
        return 0;
 }
@@ -5197,7 +5232,7 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cr
        if (IS_ERR(task))
                ret = PTR_ERR(task);
        else
-               rpc_put_task(task);
+               rpc_put_task_async(task);
        dprintk("<-- %s status=%d\n", __func__, ret);
        return ret;
 }
@@ -5213,8 +5248,13 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
                goto out;
        }
        ret = rpc_wait_for_completion_task(task);
-       if (!ret)
+       if (!ret) {
+               struct nfs4_sequence_res *res = task->tk_msg.rpc_resp;
+
+               if (task->tk_status == 0)
+                       nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags);
                ret = task->tk_status;
+       }
        rpc_put_task(task);
 out:
        dprintk("<-- %s status=%d\n", __func__, ret);
@@ -5251,7 +5291,7 @@ static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nf
                rpc_delay(task, NFS4_POLL_RETRY_MAX);
                return -EAGAIN;
        default:
-               nfs4_schedule_state_recovery(clp);
+               nfs4_schedule_lease_recovery(clp);
        }
        return 0;
 }
@@ -5319,6 +5359,9 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp)
                status = PTR_ERR(task);
                goto out;
        }
+       status = nfs4_wait_for_completion_rpc_task(task);
+       if (status == 0)
+               status = task->tk_status;
        rpc_put_task(task);
        return 0;
 out:
index 2336d53..0592288 100644 (file)
@@ -232,12 +232,6 @@ int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
        status = nfs4_proc_create_session(clp);
        if (status != 0)
                goto out;
-       status = nfs4_set_callback_sessionid(clp);
-       if (status != 0) {
-               printk(KERN_WARNING "Sessionid not set. No callback service\n");
-               nfs_callback_down(1);
-               status = 0;
-       }
        nfs41_setup_state_renewal(clp);
        nfs_mark_client_ready(clp, NFS_CS_READY);
 out:
@@ -1013,9 +1007,9 @@ void nfs4_schedule_state_manager(struct nfs_client *clp)
 }
 
 /*
- * Schedule a state recovery attempt
+ * Schedule a lease recovery attempt
  */
-void nfs4_schedule_state_recovery(struct nfs_client *clp)
+void nfs4_schedule_lease_recovery(struct nfs_client *clp)
 {
        if (!clp)
                return;
@@ -1024,7 +1018,7 @@ void nfs4_schedule_state_recovery(struct nfs_client *clp)
        nfs4_schedule_state_manager(clp);
 }
 
-int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state)
+static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state)
 {
 
        set_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
@@ -1038,7 +1032,7 @@ int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *st
        return 1;
 }
 
-int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state)
+static int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state)
 {
        set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags);
        clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
@@ -1047,6 +1041,14 @@ int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *s
        return 1;
 }
 
+void nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4_state *state)
+{
+       struct nfs_client *clp = server->nfs_client;
+
+       nfs4_state_mark_reclaim_nograce(clp, state);
+       nfs4_schedule_state_manager(clp);
+}
+
 static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops)
 {
        struct inode *inode = state->inode;
@@ -1442,10 +1444,15 @@ static int nfs4_reclaim_lease(struct nfs_client *clp)
 }
 
 #ifdef CONFIG_NFS_V4_1
+void nfs4_schedule_session_recovery(struct nfs4_session *session)
+{
+       nfs4_schedule_lease_recovery(session->clp);
+}
+
 void nfs41_handle_recall_slot(struct nfs_client *clp)
 {
        set_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state);
-       nfs4_schedule_state_recovery(clp);
+       nfs4_schedule_state_manager(clp);
 }
 
 static void nfs4_reset_all_state(struct nfs_client *clp)
@@ -1453,7 +1460,7 @@ static void nfs4_reset_all_state(struct nfs_client *clp)
        if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) {
                clp->cl_boot_time = CURRENT_TIME;
                nfs4_state_start_reclaim_nograce(clp);
-               nfs4_schedule_state_recovery(clp);
+               nfs4_schedule_state_manager(clp);
        }
 }
 
@@ -1461,7 +1468,7 @@ static void nfs41_handle_server_reboot(struct nfs_client *clp)
 {
        if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) {
                nfs4_state_start_reclaim_reboot(clp);
-               nfs4_schedule_state_recovery(clp);
+               nfs4_schedule_state_manager(clp);
        }
 }
 
@@ -1481,7 +1488,7 @@ static void nfs41_handle_cb_path_down(struct nfs_client *clp)
 {
        nfs_expire_all_delegations(clp);
        if (test_and_set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) == 0)
-               nfs4_schedule_state_recovery(clp);
+               nfs4_schedule_state_manager(clp);
 }
 
 void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags)
index 2ab8e5c..94d50e8 100644 (file)
@@ -1660,7 +1660,7 @@ static void encode_create_session(struct xdr_stream *xdr,
 
        p = reserve_space(xdr, 20 + 2*28 + 20 + len + 12);
        *p++ = cpu_to_be32(OP_CREATE_SESSION);
-       p = xdr_encode_hyper(p, clp->cl_ex_clid);
+       p = xdr_encode_hyper(p, clp->cl_clientid);
        *p++ = cpu_to_be32(clp->cl_seqid);                      /*Sequence id */
        *p++ = cpu_to_be32(args->flags);                        /*flags */
 
@@ -4694,7 +4694,7 @@ static int decode_exchange_id(struct xdr_stream *xdr,
        p = xdr_inline_decode(xdr, 8);
        if (unlikely(!p))
                goto out_overflow;
-       xdr_decode_hyper(p, &clp->cl_ex_clid);
+       xdr_decode_hyper(p, &clp->cl_clientid);
        p = xdr_inline_decode(xdr, 12);
        if (unlikely(!p))
                goto out_overflow;
@@ -6086,11 +6086,11 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
        __be32 *p = xdr_inline_decode(xdr, 4);
        if (unlikely(!p))
                goto out_overflow;
-       if (!ntohl(*p++)) {
+       if (*p == xdr_zero) {
                p = xdr_inline_decode(xdr, 4);
                if (unlikely(!p))
                        goto out_overflow;
-               if (!ntohl(*p++))
+               if (*p == xdr_zero)
                        return -EAGAIN;
                entry->eof = 1;
                return -EBADCOOKIE;
@@ -6101,7 +6101,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
                goto out_overflow;
        entry->prev_cookie = entry->cookie;
        p = xdr_decode_hyper(p, &entry->cookie);
-       entry->len = ntohl(*p++);
+       entry->len = be32_to_cpup(p);
 
        p = xdr_inline_decode(xdr, entry->len);
        if (unlikely(!p))
@@ -6132,9 +6132,6 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
        if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE)
                entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
 
-       if (verify_attr_len(xdr, p, len) < 0)
-               goto out_overflow;
-
        return 0;
 
 out_overflow:
index 903908a..c541093 100644 (file)
 /* Default path we try to mount. "%s" gets replaced by our IP address */
 #define NFS_ROOT               "/tftpboot/%s"
 
+/* Default NFSROOT mount options. */
+#define NFS_DEF_OPTIONS                "udp"
+
 /* Parameters passed from the kernel command line */
 static char nfs_root_parms[256] __initdata = "";
 
 /* Text-based mount options passed to super.c */
-static char nfs_root_options[256] __initdata = "";
+static char nfs_root_options[256] __initdata = NFS_DEF_OPTIONS;
 
 /* Address of NFS server */
 static __be32 servaddr __initdata = htonl(INADDR_NONE);
@@ -160,8 +163,14 @@ static int __init root_nfs_copy(char *dest, const char *src,
 }
 
 static int __init root_nfs_cat(char *dest, const char *src,
-                                 const size_t destlen)
+                              const size_t destlen)
 {
+       size_t len = strlen(dest);
+
+       if (len && dest[len - 1] != ',')
+               if (strlcat(dest, ",", destlen) > destlen)
+                       return -1;
+
        if (strlcat(dest, src, destlen) > destlen)
                return -1;
        return 0;
@@ -194,16 +203,6 @@ static int __init root_nfs_parse_options(char *incoming, char *exppath,
                if (root_nfs_cat(nfs_root_options, incoming,
                                                sizeof(nfs_root_options)))
                        return -1;
-
-       /*
-        * Possibly prepare for more options to be appended
-        */
-       if (nfs_root_options[0] != '\0' &&
-           nfs_root_options[strlen(nfs_root_options)] != ',')
-               if (root_nfs_cat(nfs_root_options, ",",
-                                               sizeof(nfs_root_options)))
-                       return -1;
-
        return 0;
 }
 
@@ -217,7 +216,7 @@ static int __init root_nfs_parse_options(char *incoming, char *exppath,
  */
 static int __init root_nfs_data(char *cmdline)
 {
-       char addr_option[sizeof("nolock,addr=") + INET_ADDRSTRLEN + 1];
+       char mand_options[sizeof("nolock,addr=") + INET_ADDRSTRLEN + 1];
        int len, retval = -1;
        char *tmp = NULL;
        const size_t tmplen = sizeof(nfs_export_path);
@@ -244,9 +243,9 @@ static int __init root_nfs_data(char *cmdline)
         * Append mandatory options for nfsroot so they override
         * what has come before
         */
-       snprintf(addr_option, sizeof(addr_option), "nolock,addr=%pI4",
+       snprintf(mand_options, sizeof(mand_options), "nolock,addr=%pI4",
                        &servaddr);
-       if (root_nfs_cat(nfs_root_options, addr_option,
+       if (root_nfs_cat(nfs_root_options, mand_options,
                                                sizeof(nfs_root_options)))
                goto out_optionstoolong;
 
index bc40897..1b1bc1a 100644 (file)
@@ -951,7 +951,7 @@ pnfs_put_deviceid_cache(struct nfs_client *clp)
 {
        struct pnfs_deviceid_cache *local = clp->cl_devid_cache;
 
-       dprintk("--> %s cl_devid_cache %p\n", __func__, clp->cl_devid_cache);
+       dprintk("--> %s ({%d})\n", __func__, atomic_read(&local->dc_ref));
        if (atomic_dec_and_lock(&local->dc_ref, &clp->cl_lock)) {
                int i;
                /* Verify cache is empty */
index e313a51..6481d53 100644 (file)
@@ -180,7 +180,7 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n
        task_setup_data.rpc_client = NFS_CLIENT(dir);
        task = rpc_run_task(&task_setup_data);
        if (!IS_ERR(task))
-               rpc_put_task(task);
+               rpc_put_task_async(task);
        return 1;
 }
 
index 10d648e..42b92d7 100644 (file)
@@ -932,7 +932,7 @@ out_bad:
        while (!list_empty(&list)) {
                data = list_entry(list.next, struct nfs_write_data, pages);
                list_del(&data->pages);
-               nfs_writedata_release(data);
+               nfs_writedata_free(data);
        }
        nfs_redirty_request(req);
        return -ENOMEM;
@@ -1292,6 +1292,8 @@ static int nfs_commit_rpcsetup(struct list_head *head,
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
+       if (how & FLUSH_SYNC)
+               rpc_wait_for_completion_task(task);
        rpc_put_task(task);
        return 0;
 }
index fc1c525..84c27d6 100644 (file)
@@ -42,6 +42,11 @@ struct nfsacl_encode_desc {
        gid_t gid;
 };
 
+struct nfsacl_simple_acl {
+       struct posix_acl acl;
+       struct posix_acl_entry ace[4];
+};
+
 static int
 xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem)
 {
@@ -72,9 +77,20 @@ xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem)
        return 0;
 }
 
-unsigned int
-nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
-             struct posix_acl *acl, int encode_entries, int typeflag)
+/**
+ * nfsacl_encode - Encode an NFSv3 ACL
+ *
+ * @buf: destination xdr_buf to contain XDR encoded ACL
+ * @base: byte offset in xdr_buf where XDR'd ACL begins
+ * @inode: inode of file whose ACL this is
+ * @acl: posix_acl to encode
+ * @encode_entries: whether to encode ACEs as well
+ * @typeflag: ACL type: NFS_ACL_DEFAULT or zero
+ *
+ * Returns size of encoded ACL in bytes or a negative errno value.
+ */
+int nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
+                 struct posix_acl *acl, int encode_entries, int typeflag)
 {
        int entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0;
        struct nfsacl_encode_desc nfsacl_desc = {
@@ -88,17 +104,22 @@ nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
                .uid = inode->i_uid,
                .gid = inode->i_gid,
        };
+       struct nfsacl_simple_acl aclbuf;
        int err;
-       struct posix_acl *acl2 = NULL;
 
        if (entries > NFS_ACL_MAX_ENTRIES ||
            xdr_encode_word(buf, base, entries))
                return -EINVAL;
        if (encode_entries && acl && acl->a_count == 3) {
-               /* Fake up an ACL_MASK entry. */
-               acl2 = posix_acl_alloc(4, GFP_KERNEL);
-               if (!acl2)
-                       return -ENOMEM;
+               struct posix_acl *acl2 = &aclbuf.acl;
+
+               /* Avoid the use of posix_acl_alloc().  nfsacl_encode() is
+                * invoked in contexts where a memory allocation failure is
+                * fatal.  Fortunately this fake ACL is small enough to
+                * construct on the stack. */
+               memset(acl2, 0, sizeof(acl2));
+               posix_acl_init(acl2, 4);
+
                /* Insert entries in canonical order: other orders seem
                 to confuse Solaris VxFS. */
                acl2->a_entries[0] = acl->a_entries[0];  /* ACL_USER_OBJ */
@@ -109,8 +130,6 @@ nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
                nfsacl_desc.acl = acl2;
        }
        err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc);
-       if (acl2)
-               posix_acl_release(acl2);
        if (!err)
                err = 8 + nfsacl_desc.desc.elem_size *
                          nfsacl_desc.desc.array_len;
@@ -224,9 +243,18 @@ posix_acl_from_nfsacl(struct posix_acl *acl)
        return 0;
 }
 
-unsigned int
-nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt,
-             struct posix_acl **pacl)
+/**
+ * nfsacl_decode - Decode an NFSv3 ACL
+ *
+ * @buf: xdr_buf containing XDR'd ACL data to decode
+ * @base: byte offset in xdr_buf where XDR'd ACL begins
+ * @aclcnt: count of ACEs in decoded posix_acl
+ * @pacl: buffer in which to place decoded posix_acl
+ *
+ * Returns the length of the decoded ACL in bytes, or a negative errno value.
+ */
+int nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt,
+                 struct posix_acl **pacl)
 {
        struct nfsacl_decode_desc nfsacl_desc = {
                .desc = {
index bf9cbd2..124e8fc 100644 (file)
 
 static struct file *do_open(char *name, int flags)
 {
-       struct nameidata nd;
        struct vfsmount *mnt;
-       int error;
+       struct file *file;
 
        mnt = do_kern_mount("nfsd", 0, "nfsd", NULL);
        if (IS_ERR(mnt))
                return (struct file *)mnt;
 
-       error = vfs_path_lookup(mnt->mnt_root, mnt, name, 0, &nd);
-       mntput(mnt);    /* drop do_kern_mount reference */
-       if (error)
-               return ERR_PTR(error);
-
-       if (flags == O_RDWR)
-               error = may_open(&nd.path, MAY_READ|MAY_WRITE, flags);
-       else
-               error = may_open(&nd.path, MAY_WRITE, flags);
+       file = file_open_root(mnt->mnt_root, mnt, name, flags);
 
-       if (!error)
-               return dentry_open(nd.path.dentry, nd.path.mnt, flags,
-                                  current_cred());
-
-       path_put(&nd.path);
-       return ERR_PTR(error);
+       mntput(mnt);    /* drop do_kern_mount reference */
+       return file;
 }
 
 static struct {
index 3be975e..02eb4ed 100644 (file)
@@ -432,7 +432,7 @@ static int decode_cb_sequence4resok(struct xdr_stream *xdr,
         * If the server returns different values for sessionID, slotID or
         * sequence number, the server is looney tunes.
         */
-       p = xdr_inline_decode(xdr, NFS4_MAX_SESSIONID_LEN + 4 + 4);
+       p = xdr_inline_decode(xdr, NFS4_MAX_SESSIONID_LEN + 4 + 4 + 4 + 4);
        if (unlikely(p == NULL))
                goto out_overflow;
        memcpy(id.data, p, NFS4_MAX_SESSIONID_LEN);
@@ -484,7 +484,7 @@ static int decode_cb_sequence4res(struct xdr_stream *xdr,
 out:
        return status;
 out_default:
-       return nfs_cb_stat_to_errno(status);
+       return nfs_cb_stat_to_errno(nfserr);
 }
 
 /*
@@ -564,11 +564,9 @@ static int nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp,
        if (unlikely(status))
                goto out;
        if (unlikely(nfserr != NFS4_OK))
-               goto out_default;
+               status = nfs_cb_stat_to_errno(nfserr);
 out:
        return status;
-out_default:
-       return nfs_cb_stat_to_errno(status);
 }
 
 /*
index d98d021..7b566ec 100644 (file)
@@ -230,9 +230,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
        dp->dl_client = clp;
        get_nfs4_file(fp);
        dp->dl_file = fp;
-       dp->dl_vfs_file = find_readable_file(fp);
-       get_file(dp->dl_vfs_file);
-       dp->dl_flock = NULL;
        dp->dl_type = type;
        dp->dl_stateid.si_boot = boot_time;
        dp->dl_stateid.si_stateownerid = current_delegid++;
@@ -241,8 +238,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
        fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle);
        dp->dl_time = 0;
        atomic_set(&dp->dl_count, 1);
-       list_add(&dp->dl_perfile, &fp->fi_delegations);
-       list_add(&dp->dl_perclnt, &clp->cl_delegations);
        INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc);
        return dp;
 }
@@ -253,36 +248,30 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
        if (atomic_dec_and_test(&dp->dl_count)) {
                dprintk("NFSD: freeing dp %p\n",dp);
                put_nfs4_file(dp->dl_file);
-               fput(dp->dl_vfs_file);
                kmem_cache_free(deleg_slab, dp);
                num_delegations--;
        }
 }
 
-/* Remove the associated file_lock first, then remove the delegation.
- * lease_modify() is called to remove the FS_LEASE file_lock from
- * the i_flock list, eventually calling nfsd's lock_manager
- * fl_release_callback.
- */
-static void
-nfs4_close_delegation(struct nfs4_delegation *dp)
+static void nfs4_put_deleg_lease(struct nfs4_file *fp)
 {
-       dprintk("NFSD: close_delegation dp %p\n",dp);
-       /* XXX: do we even need this check?: */
-       if (dp->dl_flock)
-               vfs_setlease(dp->dl_vfs_file, F_UNLCK, &dp->dl_flock);
+       if (atomic_dec_and_test(&fp->fi_delegees)) {
+               vfs_setlease(fp->fi_deleg_file, F_UNLCK, &fp->fi_lease);
+               fp->fi_lease = NULL;
+               fp->fi_deleg_file = NULL;
+       }
 }
 
 /* Called under the state lock. */
 static void
 unhash_delegation(struct nfs4_delegation *dp)
 {
-       list_del_init(&dp->dl_perfile);
        list_del_init(&dp->dl_perclnt);
        spin_lock(&recall_lock);
+       list_del_init(&dp->dl_perfile);
        list_del_init(&dp->dl_recall_lru);
        spin_unlock(&recall_lock);
-       nfs4_close_delegation(dp);
+       nfs4_put_deleg_lease(dp->dl_file);
        nfs4_put_delegation(dp);
 }
 
@@ -958,8 +947,6 @@ expire_client(struct nfs4_client *clp)
        spin_lock(&recall_lock);
        while (!list_empty(&clp->cl_delegations)) {
                dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt);
-               dprintk("NFSD: expire client. dp %p, fp %p\n", dp,
-                               dp->dl_flock);
                list_del_init(&dp->dl_perclnt);
                list_move(&dp->dl_recall_lru, &reaplist);
        }
@@ -2078,6 +2065,7 @@ alloc_init_file(struct inode *ino)
                fp->fi_inode = igrab(ino);
                fp->fi_id = current_fileid++;
                fp->fi_had_conflict = false;
+               fp->fi_lease = NULL;
                memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
                memset(fp->fi_access, 0, sizeof(fp->fi_access));
                spin_lock(&recall_lock);
@@ -2329,23 +2317,8 @@ nfs4_file_downgrade(struct nfs4_file *fp, unsigned int share_access)
                nfs4_file_put_access(fp, O_RDONLY);
 }
 
-/*
- * Spawn a thread to perform a recall on the delegation represented
- * by the lease (file_lock)
- *
- * Called from break_lease() with lock_flocks() held.
- * Note: we assume break_lease will only call this *once* for any given
- * lease.
- */
-static
-void nfsd_break_deleg_cb(struct file_lock *fl)
+static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
 {
-       struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner;
-
-       dprintk("NFSD nfsd_break_deleg_cb: dp %p fl %p\n",dp,fl);
-       if (!dp)
-               return;
-
        /* We're assuming the state code never drops its reference
         * without first removing the lease.  Since we're in this lease
         * callback (and since the lease code is serialized by the kernel
@@ -2353,22 +2326,35 @@ void nfsd_break_deleg_cb(struct file_lock *fl)
         * it's safe to take a reference: */
        atomic_inc(&dp->dl_count);
 
-       spin_lock(&recall_lock);
        list_add_tail(&dp->dl_recall_lru, &del_recall_lru);
-       spin_unlock(&recall_lock);
 
        /* only place dl_time is set. protected by lock_flocks*/
        dp->dl_time = get_seconds();
 
+       nfsd4_cb_recall(dp);
+}
+
+/* Called from break_lease() with lock_flocks() held. */
+static void nfsd_break_deleg_cb(struct file_lock *fl)
+{
+       struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner;
+       struct nfs4_delegation *dp;
+
+       BUG_ON(!fp);
+       /* We assume break_lease is only called once per lease: */
+       BUG_ON(fp->fi_had_conflict);
        /*
         * We don't want the locks code to timeout the lease for us;
-        * we'll remove it ourself if the delegation isn't returned
-        * in time.
+        * we'll remove it ourself if a delegation isn't returned
+        * in time:
         */
        fl->fl_break_time = 0;
 
-       dp->dl_file->fi_had_conflict = true;
-       nfsd4_cb_recall(dp);
+       spin_lock(&recall_lock);
+       fp->fi_had_conflict = true;
+       list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
+               nfsd_break_one_deleg(dp);
+       spin_unlock(&recall_lock);
 }
 
 static
@@ -2461,10 +2447,13 @@ find_delegation_file(struct nfs4_file *fp, stateid_t *stid)
 {
        struct nfs4_delegation *dp;
 
-       list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) {
-               if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid)
+       spin_lock(&recall_lock);
+       list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
+               if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid) {
+                       spin_unlock(&recall_lock);
                        return dp;
-       }
+               }
+       spin_unlock(&recall_lock);
        return NULL;
 }
 
@@ -2641,6 +2630,66 @@ static bool nfsd4_cb_channel_good(struct nfs4_client *clp)
        return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN;
 }
 
+static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, int flag)
+{
+       struct file_lock *fl;
+
+       fl = locks_alloc_lock();
+       if (!fl)
+               return NULL;
+       locks_init_lock(fl);
+       fl->fl_lmops = &nfsd_lease_mng_ops;
+       fl->fl_flags = FL_LEASE;
+       fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
+       fl->fl_end = OFFSET_MAX;
+       fl->fl_owner = (fl_owner_t)(dp->dl_file);
+       fl->fl_pid = current->tgid;
+       return fl;
+}
+
+static int nfs4_setlease(struct nfs4_delegation *dp, int flag)
+{
+       struct nfs4_file *fp = dp->dl_file;
+       struct file_lock *fl;
+       int status;
+
+       fl = nfs4_alloc_init_lease(dp, flag);
+       if (!fl)
+               return -ENOMEM;
+       fl->fl_file = find_readable_file(fp);
+       list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations);
+       status = vfs_setlease(fl->fl_file, fl->fl_type, &fl);
+       if (status) {
+               list_del_init(&dp->dl_perclnt);
+               locks_free_lock(fl);
+               return -ENOMEM;
+       }
+       fp->fi_lease = fl;
+       fp->fi_deleg_file = fl->fl_file;
+       get_file(fp->fi_deleg_file);
+       atomic_set(&fp->fi_delegees, 1);
+       list_add(&dp->dl_perfile, &fp->fi_delegations);
+       return 0;
+}
+
+static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag)
+{
+       struct nfs4_file *fp = dp->dl_file;
+
+       if (!fp->fi_lease)
+               return nfs4_setlease(dp, flag);
+       spin_lock(&recall_lock);
+       if (fp->fi_had_conflict) {
+               spin_unlock(&recall_lock);
+               return -EAGAIN;
+       }
+       atomic_inc(&fp->fi_delegees);
+       list_add(&dp->dl_perfile, &fp->fi_delegations);
+       spin_unlock(&recall_lock);
+       list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations);
+       return 0;
+}
+
 /*
  * Attempt to hand out a delegation.
  */
@@ -2650,7 +2699,6 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
        struct nfs4_delegation *dp;
        struct nfs4_stateowner *sop = stp->st_stateowner;
        int cb_up;
-       struct file_lock *fl;
        int status, flag = 0;
 
        cb_up = nfsd4_cb_channel_good(sop->so_client);
@@ -2681,36 +2729,11 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
        }
 
        dp = alloc_init_deleg(sop->so_client, stp, fh, flag);
-       if (dp == NULL) {
-               flag = NFS4_OPEN_DELEGATE_NONE;
-               goto out;
-       }
-       status = -ENOMEM;
-       fl = locks_alloc_lock();
-       if (!fl)
-               goto out;
-       locks_init_lock(fl);
-       fl->fl_lmops = &nfsd_lease_mng_ops;
-       fl->fl_flags = FL_LEASE;
-       fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
-       fl->fl_end = OFFSET_MAX;
-       fl->fl_owner =  (fl_owner_t)dp;
-       fl->fl_file = find_readable_file(stp->st_file);
-       BUG_ON(!fl->fl_file);
-       fl->fl_pid = current->tgid;
-       dp->dl_flock = fl;
-
-       /* vfs_setlease checks to see if delegation should be handed out.
-        * the lock_manager callback fl_change is used
-        */
-       if ((status = vfs_setlease(fl->fl_file, fl->fl_type, &fl))) {
-               dprintk("NFSD: setlease failed [%d], no delegation\n", status);
-               dp->dl_flock = NULL;
-               locks_free_lock(fl);
-               unhash_delegation(dp);
-               flag = NFS4_OPEN_DELEGATE_NONE;
-               goto out;
-       }
+       if (dp == NULL)
+               goto out_no_deleg;
+       status = nfs4_set_delegation(dp, flag);
+       if (status)
+               goto out_free;
 
        memcpy(&open->op_delegate_stateid, &dp->dl_stateid, sizeof(dp->dl_stateid));
 
@@ -2722,6 +2745,12 @@ out:
                        && open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)
                dprintk("NFSD: WARNING: refusing delegation reclaim\n");
        open->op_delegate_type = flag;
+       return;
+out_free:
+       nfs4_put_delegation(dp);
+out_no_deleg:
+       flag = NFS4_OPEN_DELEGATE_NONE;
+       goto out;
 }
 
 /*
@@ -2916,8 +2945,6 @@ nfs4_laundromat(void)
                                test_val = u;
                        break;
                }
-               dprintk("NFSD: purging unused delegation dp %p, fp %p\n",
-                                   dp, dp->dl_flock);
                list_move(&dp->dl_recall_lru, &reaplist);
        }
        spin_unlock(&recall_lock);
@@ -3128,7 +3155,7 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
                        goto out;
                renew_client(dp->dl_client);
                if (filpp) {
-                       *filpp = find_readable_file(dp->dl_file);
+                       *filpp = dp->dl_file->fi_deleg_file;
                        BUG_ON(!*filpp);
                }
        } else { /* open or lock stateid */
index 956629b..615f0a9 100644 (file)
@@ -317,8 +317,8 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
                READ_BUF(dummy32);
                len += (XDR_QUADLEN(dummy32) << 2);
                READMEM(buf, dummy32);
-               if ((host_err = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid)))
-                       goto out_nfserr;
+               if ((status = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid)))
+                       return status;
                iattr->ia_valid |= ATTR_UID;
        }
        if (bmval[1] & FATTR4_WORD1_OWNER_GROUP) {
@@ -328,8 +328,8 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
                READ_BUF(dummy32);
                len += (XDR_QUADLEN(dummy32) << 2);
                READMEM(buf, dummy32);
-               if ((host_err = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid)))
-                       goto out_nfserr;
+               if ((status = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid)))
+                       return status;
                iattr->ia_valid |= ATTR_GID;
        }
        if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) {
@@ -1142,7 +1142,7 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp,
 
        u32 dummy;
        char *machine_name;
-       int i;
+       int i, j;
        int nr_secflavs;
 
        READ_BUF(16);
@@ -1215,7 +1215,7 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp,
                        READ_BUF(4);
                        READ32(dummy);
                        READ_BUF(dummy * 4);
-                       for (i = 0; i < dummy; ++i)
+                       for (j = 0; j < dummy; ++j)
                                READ32(dummy);
                        break;
                case RPC_AUTH_GSS:
index 3074656..2d31224 100644 (file)
@@ -83,8 +83,6 @@ struct nfs4_delegation {
        atomic_t                dl_count;       /* ref count */
        struct nfs4_client      *dl_client;
        struct nfs4_file        *dl_file;
-       struct file             *dl_vfs_file;
-       struct file_lock        *dl_flock;
        u32                     dl_type;
        time_t                  dl_time;
 /* For recall: */
@@ -379,6 +377,9 @@ struct nfs4_file {
         */
        atomic_t                fi_readers;
        atomic_t                fi_writers;
+       struct file             *fi_deleg_file;
+       struct file_lock        *fi_lease;
+       atomic_t                fi_delegees;
        struct inode            *fi_inode;
        u32                     fi_id;      /* used with stateowner->so_id 
                                             * for stateid_hashtbl hash */
index 641117f..da1d970 100644 (file)
@@ -808,7 +808,7 @@ nfsd_get_raparms(dev_t dev, ino_t ino)
                if (ra->p_count == 0)
                        frap = rap;
        }
-       depth = nfsdstats.ra_size*11/10;
+       depth = nfsdstats.ra_size;
        if (!frap) {    
                spin_unlock(&rab->pb_lock);
                return NULL;
@@ -1742,6 +1742,13 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
                goto out_dput_new;
 
        host_err = nfsd_break_lease(odentry->d_inode);
+       if (host_err)
+               goto out_drop_write;
+       if (ndentry->d_inode) {
+               host_err = nfsd_break_lease(ndentry->d_inode);
+               if (host_err)
+                       goto out_drop_write;
+       }
        if (host_err)
                goto out_drop_write;
        host_err = vfs_rename(fdir, odentry, tdir, ndentry);
@@ -1812,22 +1819,22 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
 
        host_err = mnt_want_write(fhp->fh_export->ex_path.mnt);
        if (host_err)
-               goto out_nfserr;
+               goto out_put;
 
        host_err = nfsd_break_lease(rdentry->d_inode);
        if (host_err)
-               goto out_put;
+               goto out_drop_write;
        if (type != S_IFDIR)
                host_err = vfs_unlink(dirp, rdentry);
        else
                host_err = vfs_rmdir(dirp, rdentry);
-out_put:
-       dput(rdentry);
-
        if (!host_err)
                host_err = commit_metadata(fhp);
-
+out_drop_write:
        mnt_drop_write(fhp->fh_export->ex_path.mnt);
+out_put:
+       dput(rdentry);
+
 out_nfserr:
        err = nfserrno(host_err);
 out:
index 388e9e8..85f7baa 100644 (file)
 #include "btnode.h"
 
 
-void nilfs_btnode_cache_init_once(struct address_space *btnc)
-{
-       nilfs_mapping_init_once(btnc);
-}
-
 static const struct address_space_operations def_btnode_aops = {
        .sync_page              = block_sync_page,
 };
index 7903749..1b8ebd8 100644 (file)
@@ -37,7 +37,6 @@ struct nilfs_btnode_chkey_ctxt {
        struct buffer_head *newbh;
 };
 
-void nilfs_btnode_cache_init_once(struct address_space *);
 void nilfs_btnode_cache_init(struct address_space *, struct backing_dev_info *);
 void nilfs_btnode_cache_clear(struct address_space *);
 struct buffer_head *nilfs_btnode_create_block(struct address_space *btnc,
index 6a0e2a1..a0babd2 100644 (file)
@@ -454,9 +454,9 @@ int nilfs_mdt_setup_shadow_map(struct inode *inode,
        struct backing_dev_info *bdi = inode->i_sb->s_bdi;
 
        INIT_LIST_HEAD(&shadow->frozen_buffers);
-       nilfs_mapping_init_once(&shadow->frozen_data);
+       address_space_init_once(&shadow->frozen_data);
        nilfs_mapping_init(&shadow->frozen_data, bdi, &shadow_map_aops);
-       nilfs_mapping_init_once(&shadow->frozen_btnodes);
+       address_space_init_once(&shadow->frozen_btnodes);
        nilfs_mapping_init(&shadow->frozen_btnodes, bdi, &shadow_map_aops);
        mi->mi_shadow = shadow;
        return 0;
index 9803427..161791d 100644 (file)
@@ -397,7 +397,6 @@ static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                new_de = nilfs_find_entry(new_dir, &new_dentry->d_name, &new_page);
                if (!new_de)
                        goto out_dir;
-               inc_nlink(old_inode);
                nilfs_set_link(new_dir, new_de, new_page, old_inode);
                nilfs_mark_inode_dirty(new_dir);
                new_inode->i_ctime = CURRENT_TIME;
@@ -411,13 +410,9 @@ static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        if (new_dir->i_nlink >= NILFS_LINK_MAX)
                                goto out_dir;
                }
-               inc_nlink(old_inode);
                err = nilfs_add_link(new_dentry, old_inode);
-               if (err) {
-                       drop_nlink(old_inode);
-                       nilfs_mark_inode_dirty(old_inode);
+               if (err)
                        goto out_dir;
-               }
                if (dir_de) {
                        inc_nlink(new_dir);
                        nilfs_mark_inode_dirty(new_dir);
@@ -431,7 +426,6 @@ static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        old_inode->i_ctime = CURRENT_TIME;
 
        nilfs_delete_entry(old_de, old_page);
-       drop_nlink(old_inode);
 
        if (dir_de) {
                nilfs_set_link(old_inode, dir_de, dir_page, new_dir);
index 0c43241..a585b35 100644 (file)
@@ -492,19 +492,6 @@ unsigned nilfs_page_count_clean_buffers(struct page *page,
        return nc;
 }
 
-void nilfs_mapping_init_once(struct address_space *mapping)
-{
-       memset(mapping, 0, sizeof(*mapping));
-       INIT_RADIX_TREE(&mapping->page_tree, GFP_ATOMIC);
-       spin_lock_init(&mapping->tree_lock);
-       INIT_LIST_HEAD(&mapping->private_list);
-       spin_lock_init(&mapping->private_lock);
-
-       spin_lock_init(&mapping->i_mmap_lock);
-       INIT_RAW_PRIO_TREE_ROOT(&mapping->i_mmap);
-       INIT_LIST_HEAD(&mapping->i_mmap_nonlinear);
-}
-
 void nilfs_mapping_init(struct address_space *mapping,
                        struct backing_dev_info *bdi,
                        const struct address_space_operations *aops)
index 622df27..2a00953 100644 (file)
@@ -61,7 +61,6 @@ void nilfs_free_private_page(struct page *);
 int nilfs_copy_dirty_pages(struct address_space *, struct address_space *);
 void nilfs_copy_back_pages(struct address_space *, struct address_space *);
 void nilfs_clear_dirty_pages(struct address_space *);
-void nilfs_mapping_init_once(struct address_space *mapping);
 void nilfs_mapping_init(struct address_space *mapping,
                        struct backing_dev_info *bdi,
                        const struct address_space_operations *aops);
index 55ebae5..2de9f63 100644 (file)
@@ -430,7 +430,8 @@ static void nilfs_segctor_begin_finfo(struct nilfs_sc_info *sci,
        nilfs_segctor_map_segsum_entry(
                sci, &sci->sc_binfo_ptr, sizeof(struct nilfs_finfo));
 
-       if (inode->i_sb && !test_bit(NILFS_SC_HAVE_DELTA, &sci->sc_flags))
+       if (NILFS_I(inode)->i_root &&
+           !test_bit(NILFS_SC_HAVE_DELTA, &sci->sc_flags))
                set_bit(NILFS_SC_HAVE_DELTA, &sci->sc_flags);
        /* skip finfo */
 }
index 0994f6a..1673b3d 100644 (file)
@@ -704,7 +704,8 @@ skip_mount_setup:
        sbp[0]->s_state =
                cpu_to_le16(le16_to_cpu(sbp[0]->s_state) & ~NILFS_VALID_FS);
        /* synchronize sbp[1] with sbp[0] */
-       memcpy(sbp[1], sbp[0], nilfs->ns_sbsize);
+       if (sbp[1])
+               memcpy(sbp[1], sbp[0], nilfs->ns_sbsize);
        return nilfs_commit_super(sbi, NILFS_SB_COMMIT_ALL);
 }
 
@@ -1278,7 +1279,7 @@ static void nilfs_inode_init_once(void *obj)
 #ifdef CONFIG_NILFS_XATTR
        init_rwsem(&ii->xattr_sem);
 #endif
-       nilfs_btnode_cache_init_once(&ii->i_btnode_cache);
+       address_space_init_once(&ii->i_btnode_cache);
        ii->i_bmap = &ii->i_bmap_data;
        inode_init_once(&ii->vfs_inode);
 }
index b572b67..326e747 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * mft.c - NTFS kernel mft record operations. Part of the Linux-NTFS project.
  *
- * Copyright (c) 2001-2006 Anton Altaparmakov
+ * Copyright (c) 2001-2011 Anton Altaparmakov and Tuxera Inc.
  * Copyright (c) 2002 Richard Russon
  *
  * This program/include file is free software; you can redistribute it and/or
@@ -2576,6 +2576,8 @@ mft_rec_already_initialized:
        flush_dcache_page(page);
        SetPageUptodate(page);
        if (base_ni) {
+               MFT_RECORD *m_tmp;
+
                /*
                 * Setup the base mft record in the extent mft record.  This
                 * completes initialization of the allocated extent mft record
@@ -2588,11 +2590,11 @@ mft_rec_already_initialized:
                 * attach it to the base inode @base_ni and map, pin, and lock
                 * its, i.e. the allocated, mft record.
                 */
-               m = map_extent_mft_record(base_ni, bit, &ni);
-               if (IS_ERR(m)) {
+               m_tmp = map_extent_mft_record(base_ni, bit, &ni);
+               if (IS_ERR(m_tmp)) {
                        ntfs_error(vol->sb, "Failed to map allocated extent "
                                        "mft record 0x%llx.", (long long)bit);
-                       err = PTR_ERR(m);
+                       err = PTR_ERR(m_tmp);
                        /* Set the mft record itself not in use. */
                        m->flags &= cpu_to_le16(
                                        ~le16_to_cpu(MFT_RECORD_IN_USE));
@@ -2603,6 +2605,7 @@ mft_rec_already_initialized:
                        ntfs_unmap_page(page);
                        goto undo_mftbmp_alloc;
                }
+               BUG_ON(m != m_tmp);
                /*
                 * Make sure the allocated mft record is written out to disk.
                 * No need to set the inode dirty because the caller is going
index 6d80ecc..7eb9040 100644 (file)
@@ -56,7 +56,7 @@ static int ocfs2_dentry_revalidate(struct dentry *dentry,
        int ret = 0;    /* if all else fails, just return false */
        struct ocfs2_super *osb;
 
-       if (nd->flags & LOOKUP_RCU)
+       if (nd && nd->flags & LOOKUP_RCU)
                return -ECHILD;
 
        inode = dentry->d_inode;
index 5dbc306..254652a 100644 (file)
@@ -197,8 +197,12 @@ static int ocfs2_encode_fh(struct dentry *dentry, u32 *fh_in, int *max_len,
                   dentry->d_name.len, dentry->d_name.name,
                   fh, len, connectable);
 
-       if (len < 3 || (connectable && len < 6)) {
-               mlog(ML_ERROR, "fh buffer is too small for encoding\n");
+       if (connectable && (len < 6)) {
+               *max_len = 6;
+               type = 255;
+               goto bail;
+       } else if (len < 3) {
+               *max_len = 3;
                type = 255;
                goto bail;
        }
index 43e56b9..6180da1 100644 (file)
@@ -405,9 +405,9 @@ static inline int ocfs2_remove_extent_credits(struct super_block *sb)
               ocfs2_quota_trans_credits(sb);
 }
 
-/* data block for new dir/symlink, 2 for bitmap updates (bitmap fe +
- * bitmap block for the new bit) dx_root update for free list */
-#define OCFS2_DIR_LINK_ADDITIONAL_CREDITS (1 + 2 + 1)
+/* data block for new dir/symlink, allocation of directory block, dx_root
+ * update for free list */
+#define OCFS2_DIR_LINK_ADDITIONAL_CREDITS (1 + OCFS2_SUBALLOC_ALLOC + 1)
 
 static inline int ocfs2_add_dir_index_credits(struct super_block *sb)
 {
index 196fcb5..d5ab56c 100644 (file)
@@ -114,7 +114,4 @@ int ocfs2_local_write_dquot(struct dquot *dquot);
 extern const struct dquot_operations ocfs2_quota_operations;
 extern struct quota_format_type ocfs2_quota_format;
 
-int ocfs2_quota_setup(void);
-void ocfs2_quota_shutdown(void);
-
 #endif /* _OCFS2_QUOTA_H */
index 4607923..a73f641 100644 (file)
@@ -63,8 +63,6 @@
  *        write to gf
  */
 
-static struct workqueue_struct *ocfs2_quota_wq = NULL;
-
 static void qsync_work_fn(struct work_struct *work);
 
 static void ocfs2_global_disk2memdqb(struct dquot *dquot, void *dp)
@@ -400,8 +398,8 @@ int ocfs2_global_read_info(struct super_block *sb, int type)
                                                OCFS2_QBLK_RESERVED_SPACE;
        oinfo->dqi_gi.dqi_qtree_depth = qtree_depth(&oinfo->dqi_gi);
        INIT_DELAYED_WORK(&oinfo->dqi_sync_work, qsync_work_fn);
-       queue_delayed_work(ocfs2_quota_wq, &oinfo->dqi_sync_work,
-                          msecs_to_jiffies(oinfo->dqi_syncms));
+       schedule_delayed_work(&oinfo->dqi_sync_work,
+                             msecs_to_jiffies(oinfo->dqi_syncms));
 
 out_err:
        mlog_exit(status);
@@ -635,8 +633,8 @@ static void qsync_work_fn(struct work_struct *work)
        struct super_block *sb = oinfo->dqi_gqinode->i_sb;
 
        dquot_scan_active(sb, ocfs2_sync_dquot_helper, oinfo->dqi_type);
-       queue_delayed_work(ocfs2_quota_wq, &oinfo->dqi_sync_work,
-                          msecs_to_jiffies(oinfo->dqi_syncms));
+       schedule_delayed_work(&oinfo->dqi_sync_work,
+                             msecs_to_jiffies(oinfo->dqi_syncms));
 }
 
 /*
@@ -923,20 +921,3 @@ const struct dquot_operations ocfs2_quota_operations = {
        .alloc_dquot    = ocfs2_alloc_dquot,
        .destroy_dquot  = ocfs2_destroy_dquot,
 };
-
-int ocfs2_quota_setup(void)
-{
-       ocfs2_quota_wq = create_workqueue("o2quot");
-       if (!ocfs2_quota_wq)
-               return -ENOMEM;
-       return 0;
-}
-
-void ocfs2_quota_shutdown(void)
-{
-       if (ocfs2_quota_wq) {
-               flush_workqueue(ocfs2_quota_wq);
-               destroy_workqueue(ocfs2_quota_wq);
-               ocfs2_quota_wq = NULL;
-       }
-}
index b5f9160..29623da 100644 (file)
@@ -3228,7 +3228,7 @@ static int ocfs2_make_clusters_writable(struct super_block *sb,
                                        u32 num_clusters, unsigned int e_flags)
 {
        int ret, delete, index, credits =  0;
-       u32 new_bit, new_len;
+       u32 new_bit, new_len, orig_num_clusters;
        unsigned int set_len;
        struct ocfs2_super *osb = OCFS2_SB(sb);
        handle_t *handle;
@@ -3261,6 +3261,8 @@ static int ocfs2_make_clusters_writable(struct super_block *sb,
                goto out;
        }
 
+       orig_num_clusters = num_clusters;
+
        while (num_clusters) {
                ret = ocfs2_get_refcount_rec(ref_ci, context->ref_root_bh,
                                             p_cluster, num_clusters,
@@ -3348,7 +3350,8 @@ static int ocfs2_make_clusters_writable(struct super_block *sb,
         * in write-back mode.
         */
        if (context->get_clusters == ocfs2_di_get_clusters) {
-               ret = ocfs2_cow_sync_writeback(sb, context, cpos, num_clusters);
+               ret = ocfs2_cow_sync_writeback(sb, context, cpos,
+                                              orig_num_clusters);
                if (ret)
                        mlog_errno(ret);
        }
@@ -4376,7 +4379,7 @@ static int ocfs2_user_path_parent(const char __user *path,
        if (IS_ERR(s))
                return PTR_ERR(s);
 
-       error = path_lookup(s, LOOKUP_PARENT, nd);
+       error = kern_path_parent(s, nd);
        if (error)
                putname(s);
        else
index 38f986d..236ed1b 100644 (file)
@@ -1316,7 +1316,7 @@ static int ocfs2_parse_options(struct super_block *sb,
                               struct mount_options *mopt,
                               int is_remount)
 {
-       int status;
+       int status, user_stack = 0;
        char *p;
        u32 tmp;
 
@@ -1459,6 +1459,15 @@ static int ocfs2_parse_options(struct super_block *sb,
                        memcpy(mopt->cluster_stack, args[0].from,
                               OCFS2_STACK_LABEL_LEN);
                        mopt->cluster_stack[OCFS2_STACK_LABEL_LEN] = '\0';
+                       /*
+                        * Open code the memcmp here as we don't have
+                        * an osb to pass to
+                        * ocfs2_userspace_stack().
+                        */
+                       if (memcmp(mopt->cluster_stack,
+                                  OCFS2_CLASSIC_CLUSTER_STACK,
+                                  OCFS2_STACK_LABEL_LEN))
+                               user_stack = 1;
                        break;
                case Opt_inode64:
                        mopt->mount_opt |= OCFS2_MOUNT_INODE64;
@@ -1514,13 +1523,16 @@ static int ocfs2_parse_options(struct super_block *sb,
                }
        }
 
-       /* Ensure only one heartbeat mode */
-       tmp = mopt->mount_opt & (OCFS2_MOUNT_HB_LOCAL | OCFS2_MOUNT_HB_GLOBAL |
-                                OCFS2_MOUNT_HB_NONE);
-       if (hweight32(tmp) != 1) {
-               mlog(ML_ERROR, "Invalid heartbeat mount options\n");
-               status = 0;
-               goto bail;
+       if (user_stack == 0) {
+               /* Ensure only one heartbeat mode */
+               tmp = mopt->mount_opt & (OCFS2_MOUNT_HB_LOCAL |
+                                        OCFS2_MOUNT_HB_GLOBAL |
+                                        OCFS2_MOUNT_HB_NONE);
+               if (hweight32(tmp) != 1) {
+                       mlog(ML_ERROR, "Invalid heartbeat mount options\n");
+                       status = 0;
+                       goto bail;
+               }
        }
 
        status = 1;
@@ -1645,16 +1657,11 @@ static int __init ocfs2_init(void)
                mlog(ML_ERROR, "Unable to create ocfs2 debugfs root.\n");
        }
 
-       status = ocfs2_quota_setup();
-       if (status)
-               goto leave;
-
        ocfs2_set_locking_protocol();
 
        status = register_quota_format(&ocfs2_quota_format);
 leave:
        if (status < 0) {
-               ocfs2_quota_shutdown();
                ocfs2_free_mem_caches();
                exit_ocfs2_uptodate_cache();
        }
@@ -1671,8 +1678,6 @@ static void __exit ocfs2_exit(void)
 {
        mlog_entry_void();
 
-       ocfs2_quota_shutdown();
-
        if (ocfs2_wq) {
                flush_workqueue(ocfs2_wq);
                destroy_workqueue(ocfs2_wq);
index e52389e..3cac0bd 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -233,6 +233,14 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
 
        if (!(file->f_mode & FMODE_WRITE))
                return -EBADF;
+
+       /* It's not possible punch hole on append only file */
+       if (mode & FALLOC_FL_PUNCH_HOLE && IS_APPEND(inode))
+               return -EPERM;
+
+       if (IS_IMMUTABLE(inode))
+               return -EPERM;
+
        /*
         * Revalidate the write permissions, in case security policy has
         * changed since the files were opened.
@@ -565,13 +573,15 @@ SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user,
 {
        struct path path;
        int error = -EINVAL;
-       int follow;
+       int lookup_flags;
 
-       if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
+       if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
                goto out;
 
-       follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
-       error = user_path_at(dfd, filename, follow, &path);
+       lookup_flags = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
+       if (flag & AT_EMPTY_PATH)
+               lookup_flags |= LOOKUP_EMPTY;
+       error = user_path_at(dfd, filename, lookup_flags, &path);
        if (error)
                goto out;
        error = mnt_want_write(path.mnt);
@@ -661,11 +671,16 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
                                        int (*open)(struct inode *, struct file *),
                                        const struct cred *cred)
 {
+       static const struct file_operations empty_fops = {};
        struct inode *inode;
        int error;
 
        f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |
                                FMODE_PREAD | FMODE_PWRITE;
+
+       if (unlikely(f->f_flags & O_PATH))
+               f->f_mode = FMODE_PATH;
+
        inode = dentry->d_inode;
        if (f->f_mode & FMODE_WRITE) {
                error = __get_file_write_access(inode, mnt);
@@ -679,9 +694,15 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
        f->f_path.dentry = dentry;
        f->f_path.mnt = mnt;
        f->f_pos = 0;
-       f->f_op = fops_get(inode->i_fop);
        file_sb_list_add(f, inode->i_sb);
 
+       if (unlikely(f->f_mode & FMODE_PATH)) {
+               f->f_op = &empty_fops;
+               return f;
+       }
+
+       f->f_op = fops_get(inode->i_fop);
+
        error = security_dentry_open(f, cred);
        if (error)
                goto cleanup_all;
@@ -790,6 +811,8 @@ struct file *nameidata_to_filp(struct nameidata *nd)
 
        /* Pick up the filp from the open intent */
        filp = nd->intent.open.file;
+       nd->intent.open.file = NULL;
+
        /* Has the filesystem initialised the file for us? */
        if (filp->f_path.dentry == NULL) {
                path_get(&nd->path);
@@ -880,15 +903,110 @@ void fd_install(unsigned int fd, struct file *file)
 
 EXPORT_SYMBOL(fd_install);
 
+static inline int build_open_flags(int flags, int mode, struct open_flags *op)
+{
+       int lookup_flags = 0;
+       int acc_mode;
+
+       if (!(flags & O_CREAT))
+               mode = 0;
+       op->mode = mode;
+
+       /* Must never be set by userspace */
+       flags &= ~FMODE_NONOTIFY;
+
+       /*
+        * O_SYNC is implemented as __O_SYNC|O_DSYNC.  As many places only
+        * check for O_DSYNC if the need any syncing at all we enforce it's
+        * always set instead of having to deal with possibly weird behaviour
+        * for malicious applications setting only __O_SYNC.
+        */
+       if (flags & __O_SYNC)
+               flags |= O_DSYNC;
+
+       /*
+        * If we have O_PATH in the open flag. Then we
+        * cannot have anything other than the below set of flags
+        */
+       if (flags & O_PATH) {
+               flags &= O_DIRECTORY | O_NOFOLLOW | O_PATH;
+               acc_mode = 0;
+       } else {
+               acc_mode = MAY_OPEN | ACC_MODE(flags);
+       }
+
+       op->open_flag = flags;
+
+       /* O_TRUNC implies we need access checks for write permissions */
+       if (flags & O_TRUNC)
+               acc_mode |= MAY_WRITE;
+
+       /* Allow the LSM permission hook to distinguish append
+          access from general write access. */
+       if (flags & O_APPEND)
+               acc_mode |= MAY_APPEND;
+
+       op->acc_mode = acc_mode;
+
+       op->intent = flags & O_PATH ? 0 : LOOKUP_OPEN;
+
+       if (flags & O_CREAT) {
+               op->intent |= LOOKUP_CREATE;
+               if (flags & O_EXCL)
+                       op->intent |= LOOKUP_EXCL;
+       }
+
+       if (flags & O_DIRECTORY)
+               lookup_flags |= LOOKUP_DIRECTORY;
+       if (!(flags & O_NOFOLLOW))
+               lookup_flags |= LOOKUP_FOLLOW;
+       return lookup_flags;
+}
+
+/**
+ * filp_open - open file and return file pointer
+ *
+ * @filename:  path to open
+ * @flags:     open flags as per the open(2) second argument
+ * @mode:      mode for the new file if O_CREAT is set, else ignored
+ *
+ * This is the helper to open a file from kernelspace if you really
+ * have to.  But in generally you should not do this, so please move
+ * along, nothing to see here..
+ */
+struct file *filp_open(const char *filename, int flags, int mode)
+{
+       struct open_flags op;
+       int lookup = build_open_flags(flags, mode, &op);
+       return do_filp_open(AT_FDCWD, filename, &op, lookup);
+}
+EXPORT_SYMBOL(filp_open);
+
+struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
+                           const char *filename, int flags)
+{
+       struct open_flags op;
+       int lookup = build_open_flags(flags, 0, &op);
+       if (flags & O_CREAT)
+               return ERR_PTR(-EINVAL);
+       if (!filename && (flags & O_DIRECTORY))
+               if (!dentry->d_inode->i_op->lookup)
+                       return ERR_PTR(-ENOTDIR);
+       return do_file_open_root(dentry, mnt, filename, &op, lookup);
+}
+EXPORT_SYMBOL(file_open_root);
+
 long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
 {
+       struct open_flags op;
+       int lookup = build_open_flags(flags, mode, &op);
        char *tmp = getname(filename);
        int fd = PTR_ERR(tmp);
 
        if (!IS_ERR(tmp)) {
                fd = get_unused_fd_flags(flags);
                if (fd >= 0) {
-                       struct file *f = do_filp_open(dfd, tmp, flags, mode, 0);
+                       struct file *f = do_filp_open(dfd, tmp, &op, lookup);
                        if (IS_ERR(f)) {
                                put_unused_fd(fd);
                                fd = PTR_ERR(f);
@@ -958,8 +1076,10 @@ int filp_close(struct file *filp, fl_owner_t id)
        if (filp->f_op && filp->f_op->flush)
                retval = filp->f_op->flush(filp, id);
 
-       dnotify_flush(filp, id);
-       locks_remove_posix(filp, id);
+       if (likely(!(filp->f_mode & FMODE_PATH))) {
+               dnotify_flush(filp, id);
+               locks_remove_posix(filp, id);
+       }
        fput(filp);
        return retval;
 }
index 789c625..b10e354 100644 (file)
@@ -251,6 +251,11 @@ static bool ldm_parse_vmdb (const u8 *data, struct vmdb *vm)
        }
 
        vm->vblk_size     = get_unaligned_be32(data + 0x08);
+       if (vm->vblk_size == 0) {
+               ldm_error ("Illegal VBLK size");
+               return false;
+       }
+
        vm->vblk_offset   = get_unaligned_be32(data + 0x0C);
        vm->last_vblk_seq = get_unaligned_be32(data + 0x04);
 
index 68d6a21..11f688b 100644 (file)
@@ -29,10 +29,9 @@ static inline void mac_fix_string(char *stg, int len)
 
 int mac_partition(struct parsed_partitions *state)
 {
-       int slot = 1;
        Sector sect;
        unsigned char *data;
-       int blk, blocks_in_map;
+       int slot, blocks_in_map;
        unsigned secsize;
 #ifdef CONFIG_PPC_PMAC
        int found_root = 0;
@@ -59,10 +58,14 @@ int mac_partition(struct parsed_partitions *state)
                put_dev_sector(sect);
                return 0;               /* not a MacOS disk */
        }
-       strlcat(state->pp_buf, " [mac]", PAGE_SIZE);
        blocks_in_map = be32_to_cpu(part->map_count);
-       for (blk = 1; blk <= blocks_in_map; ++blk) {
-               int pos = blk * secsize;
+       if (blocks_in_map < 0 || blocks_in_map >= DISK_MAX_PARTS) {
+               put_dev_sector(sect);
+               return 0;
+       }
+       strlcat(state->pp_buf, " [mac]", PAGE_SIZE);
+       for (slot = 1; slot <= blocks_in_map; ++slot) {
+               int pos = slot * secsize;
                put_dev_sector(sect);
                data = read_part_sector(state, pos/512, &sect);
                if (!data)
@@ -113,13 +116,11 @@ int mac_partition(struct parsed_partitions *state)
                        }
 
                        if (goodness > found_root_goodness) {
-                               found_root = blk;
+                               found_root = slot;
                                found_root_goodness = goodness;
                        }
                }
 #endif /* CONFIG_PPC_PMAC */
-
-               ++slot;
        }
 #ifdef CONFIG_PPC_PMAC
        if (found_root_goodness)
index 48cec7c..764b86a 100644 (file)
 #include "check.h"
 #include "osf.h"
 
+#define MAX_OSF_PARTITIONS 18
+
 int osf_partition(struct parsed_partitions *state)
 {
        int i;
        int slot = 1;
+       unsigned int npartitions;
        Sector sect;
        unsigned char *data;
        struct disklabel {
@@ -45,7 +48,7 @@ int osf_partition(struct parsed_partitions *state)
                        u8  p_fstype;
                        u8  p_frag;
                        __le16 p_cpg;
-               } d_partitions[8];
+               } d_partitions[MAX_OSF_PARTITIONS];
        } * label;
        struct d_partition * partition;
 
@@ -63,7 +66,12 @@ int osf_partition(struct parsed_partitions *state)
                put_dev_sector(sect);
                return 0;
        }
-       for (i = 0 ; i < le16_to_cpu(label->d_npartitions); i++, partition++) {
+       npartitions = le16_to_cpu(label->d_npartitions);
+       if (npartitions > MAX_OSF_PARTITIONS) {
+               put_dev_sector(sect);
+               return 0;
+       }
+       for (i = 0 ; i < npartitions; i++, partition++) {
                if (slot == state->limit)
                        break;
                if (le32_to_cpu(partition->p_size))
index 39df95a..b1cf6bf 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/errno.h>
 
+EXPORT_SYMBOL(posix_acl_init);
 EXPORT_SYMBOL(posix_acl_alloc);
 EXPORT_SYMBOL(posix_acl_clone);
 EXPORT_SYMBOL(posix_acl_valid);
@@ -31,6 +32,16 @@ EXPORT_SYMBOL(posix_acl_create_masq);
 EXPORT_SYMBOL(posix_acl_chmod_masq);
 EXPORT_SYMBOL(posix_acl_permission);
 
+/*
+ * Init a fresh posix_acl
+ */
+void
+posix_acl_init(struct posix_acl *acl, int count)
+{
+       atomic_set(&acl->a_refcount, 1);
+       acl->a_count = count;
+}
+
 /*
  * Allocate a new ACL with the specified number of entries.
  */
@@ -40,10 +51,8 @@ posix_acl_alloc(int count, gfp_t flags)
        const size_t size = sizeof(struct posix_acl) +
                            count * sizeof(struct posix_acl_entry);
        struct posix_acl *acl = kmalloc(size, flags);
-       if (acl) {
-               atomic_set(&acl->a_refcount, 1);
-               acl->a_count = count;
-       }
+       if (acl)
+               posix_acl_init(acl, count);
        return acl;
 }
 
index df2b703..7c99c1c 100644 (file)
@@ -353,9 +353,6 @@ int proc_pid_status(struct seq_file *m, struct pid_namespace *ns,
        task_cap(m, task);
        task_cpus_allowed(m, task);
        cpuset_task_status_allowed(m, task);
-#if defined(CONFIG_S390)
-       task_show_regs(m, task);
-#endif
        task_context_switch_counts(m, task);
        return 0;
 }
index 9d096e8..d49c4b5 100644 (file)
@@ -2620,35 +2620,6 @@ static const struct pid_entry proc_base_stuff[] = {
                &proc_self_inode_operations, NULL, {}),
 };
 
-/*
- *     Exceptional case: normally we are not allowed to unhash a busy
- * directory. In this case, however, we can do it - no aliasing problems
- * due to the way we treat inodes.
- */
-static int proc_base_revalidate(struct dentry *dentry, struct nameidata *nd)
-{
-       struct inode *inode;
-       struct task_struct *task;
-
-       if (nd->flags & LOOKUP_RCU)
-               return -ECHILD;
-
-       inode = dentry->d_inode;
-       task = get_proc_task(inode);
-       if (task) {
-               put_task_struct(task);
-               return 1;
-       }
-       d_drop(dentry);
-       return 0;
-}
-
-static const struct dentry_operations proc_base_dentry_operations =
-{
-       .d_revalidate   = proc_base_revalidate,
-       .d_delete       = pid_delete_dentry,
-};
-
 static struct dentry *proc_base_instantiate(struct inode *dir,
        struct dentry *dentry, struct task_struct *task, const void *ptr)
 {
@@ -2685,7 +2656,6 @@ static struct dentry *proc_base_instantiate(struct inode *dir,
        if (p->fop)
                inode->i_fop = p->fop;
        ei->op = p->op;
-       d_set_d_op(dentry, &proc_base_dentry_operations);
        d_add(dentry, inode);
        error = NULL;
 out:
index eafc22a..b701eaa 100644 (file)
@@ -67,7 +67,7 @@ static void *c_start(struct seq_file *m, loff_t *pos)
        struct console *con;
        loff_t off = 0;
 
-       acquire_console_sem();
+       console_lock();
        for_each_console(con)
                if (off++ == *pos)
                        break;
@@ -84,7 +84,7 @@ static void *c_next(struct seq_file *m, void *v, loff_t *pos)
 
 static void c_stop(struct seq_file *m, void *v)
 {
-       release_console_sem();
+       console_unlock();
 }
 
 static const struct seq_operations consoles_op = {
index 176ce4c..d6a7ca1 100644 (file)
@@ -27,6 +27,7 @@
 static void proc_evict_inode(struct inode *inode)
 {
        struct proc_dir_entry *de;
+       struct ctl_table_header *head;
 
        truncate_inode_pages(&inode->i_data, 0);
        end_writeback(inode);
@@ -38,8 +39,11 @@ static void proc_evict_inode(struct inode *inode)
        de = PROC_I(inode)->pde;
        if (de)
                pde_put(de);
-       if (PROC_I(inode)->sysctl)
-               sysctl_head_put(PROC_I(inode)->sysctl);
+       head = PROC_I(inode)->sysctl;
+       if (head) {
+               rcu_assign_pointer(PROC_I(inode)->sysctl, NULL);
+               sysctl_head_put(head);
+       }
 }
 
 struct vfsmount *proc_mnt;
index d9396a4..927cbd1 100644 (file)
@@ -233,7 +233,7 @@ void __init proc_device_tree_init(void)
                return;
        root = of_find_node_by_path("/");
        if (root == NULL) {
-               printk(KERN_ERR "/proc/device-tree: can't find root\n");
+               pr_debug("/proc/device-tree: can't find root\n");
                return;
        }
        proc_device_tree_add_node(root, proc_device_tree);
index 09a1f92..8eb2522 100644 (file)
@@ -408,15 +408,18 @@ static int proc_sys_compare(const struct dentry *parent,
                const struct dentry *dentry, const struct inode *inode,
                unsigned int len, const char *str, const struct qstr *name)
 {
+       struct ctl_table_header *head;
        /* Although proc doesn't have negative dentries, rcu-walk means
         * that inode here can be NULL */
+       /* AV: can it, indeed? */
        if (!inode)
-               return 0;
+               return 1;
        if (name->len != len)
                return 1;
        if (memcmp(name->name, str, len))
                return 1;
-       return !sysctl_is_seen(PROC_I(inode)->sysctl);
+       head = rcu_dereference(PROC_I(inode)->sysctl);
+       return !head || !sysctl_is_seen(head);
 }
 
 static const struct dentry_operations proc_sys_dentry_operations = {
index 0bae036..1bba24b 100644 (file)
@@ -1593,8 +1593,13 @@ int reiserfs_encode_fh(struct dentry *dentry, __u32 * data, int *lenp,
        struct inode *inode = dentry->d_inode;
        int maxlen = *lenp;
 
-       if (maxlen < 3)
+       if (need_parent && (maxlen < 5)) {
+               *lenp = 5;
                return 255;
+       } else if (maxlen < 3) {
+               *lenp = 3;
+               return 255;
+       }
 
        data[0] = inode->i_ino;
        data[1] = le32_to_cpu(INODE_PKEY(inode)->k_dir_id);
index 3eea859..c77514b 100644 (file)
@@ -2876,7 +2876,7 @@ int journal_init(struct super_block *sb, const char *j_dev_name,
        reiserfs_mounted_fs_count++;
        if (reiserfs_mounted_fs_count <= 1) {
                reiserfs_write_unlock(sb);
-               commit_wq = create_workqueue("reiserfs");
+               commit_wq = alloc_workqueue("reiserfs", WQ_MEM_RECLAIM, 0);
                reiserfs_write_lock(sb);
        }
 
index ba5f51e..4b2eb56 100644 (file)
@@ -771,7 +771,7 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
                                        EMPTY_DIR_SIZE_V1 : EMPTY_DIR_SIZE,
                                        dentry, inode, &security);
        if (retval) {
-               dir->i_nlink--;
+               DEC_DIR_INODE_NLINK(dir)
                goto out_failed;
        }
 
@@ -1122,10 +1122,6 @@ static int reiserfs_link(struct dentry *old_dentry, struct inode *dir,
                reiserfs_write_unlock(dir->i_sb);
                return -EMLINK;
        }
-       if (inode->i_nlink == 0) {
-               reiserfs_write_unlock(dir->i_sb);
-               return -ENOENT;
-       }
 
        /* inc before scheduling so reiserfs_unlink knows we are here */
        inc_nlink(inode);
index 3cfb2e9..5c11ca8 100644 (file)
@@ -978,8 +978,6 @@ int reiserfs_permission(struct inode *inode, int mask, unsigned int flags)
 
 static int xattr_hide_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
-       if (nd->flags & LOOKUP_RCU)
-               return -ECHILD;
        return -EPERM;
 }
 
index 2fb2882..8ab48bc 100644 (file)
@@ -63,6 +63,14 @@ static struct buffer_head *get_block_length(struct super_block *sb,
                *length = (unsigned char) bh->b_data[*offset] |
                        (unsigned char) bh->b_data[*offset + 1] << 8;
                *offset += 2;
+
+               if (*offset == msblk->devblksize) {
+                       put_bh(bh);
+                       bh = sb_bread(sb, ++(*cur_index));
+                       if (bh == NULL)
+                               return NULL;
+                       *offset = 0;
+               }
        }
 
        return bh;
index 856756c..c4eb400 100644 (file)
@@ -95,12 +95,6 @@ static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void **buffer,
                        if (!buffer_uptodate(bh[k]))
                                goto release_mutex;
 
-                       if (avail == 0) {
-                               offset = 0;
-                               put_bh(bh[k++]);
-                               continue;
-                       }
-
                        stream->buf.in = bh[k]->b_data + offset;
                        stream->buf.in_size = avail;
                        stream->buf.in_pos = 0;
index 818a5e0..4661ae2 100644 (file)
@@ -82,12 +82,6 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
                        if (!buffer_uptodate(bh[k]))
                                goto release_mutex;
 
-                       if (avail == 0) {
-                               offset = 0;
-                               put_bh(bh[k++]);
-                               continue;
-                       }
-
                        stream->next_in = bh[k]->b_data + offset;
                        stream->avail_in = avail;
                        offset = 0;
index d5c61cf..9610391 100644 (file)
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -75,13 +75,16 @@ int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,
        int error = -EINVAL;
        int lookup_flags = 0;
 
-       if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT)) != 0)
+       if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
+                     AT_EMPTY_PATH)) != 0)
                goto out;
 
        if (!(flag & AT_SYMLINK_NOFOLLOW))
                lookup_flags |= LOOKUP_FOLLOW;
        if (flag & AT_NO_AUTOMOUNT)
                lookup_flags |= LOOKUP_NO_AUTOMOUNT;
+       if (flag & AT_EMPTY_PATH)
+               lookup_flags |= LOOKUP_EMPTY;
 
        error = user_path_at(dfd, filename, lookup_flags, &path);
        if (error)
@@ -297,7 +300,7 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname,
        if (bufsiz <= 0)
                return -EINVAL;
 
-       error = user_path_at(dfd, pathname, 0, &path);
+       error = user_path_at(dfd, pathname, LOOKUP_EMPTY, &path);
        if (!error) {
                struct inode *inode = path.dentry->d_inode;
 
index 30ea8c8..8244924 100644 (file)
@@ -73,149 +73,135 @@ int vfs_statfs(struct path *path, struct kstatfs *buf)
 }
 EXPORT_SYMBOL(vfs_statfs);
 
-static int do_statfs_native(struct path *path, struct statfs *buf)
+int user_statfs(const char __user *pathname, struct kstatfs *st)
 {
-       struct kstatfs st;
-       int retval;
+       struct path path;
+       int error = user_path(pathname, &path);
+       if (!error) {
+               error = vfs_statfs(&path, st);
+               path_put(&path);
+       }
+       return error;
+}
 
-       retval = vfs_statfs(path, &st);
-       if (retval)
-               return retval;
+int fd_statfs(int fd, struct kstatfs *st)
+{
+       struct file *file = fget(fd);
+       int error = -EBADF;
+       if (file) {
+               error = vfs_statfs(&file->f_path, st);
+               fput(file);
+       }
+       return error;
+}
 
-       if (sizeof(*buf) == sizeof(st))
-               memcpy(buf, &st, sizeof(st));
+static int do_statfs_native(struct kstatfs *st, struct statfs __user *p)
+{
+       struct statfs buf;
+
+       if (sizeof(buf) == sizeof(*st))
+               memcpy(&buf, st, sizeof(*st));
        else {
-               if (sizeof buf->f_blocks == 4) {
-                       if ((st.f_blocks | st.f_bfree | st.f_bavail |
-                            st.f_bsize | st.f_frsize) &
+               if (sizeof buf.f_blocks == 4) {
+                       if ((st->f_blocks | st->f_bfree | st->f_bavail |
+                            st->f_bsize | st->f_frsize) &
                            0xffffffff00000000ULL)
                                return -EOVERFLOW;
                        /*
                         * f_files and f_ffree may be -1; it's okay to stuff
                         * that into 32 bits
                         */
-                       if (st.f_files != -1 &&
-                           (st.f_files & 0xffffffff00000000ULL))
+                       if (st->f_files != -1 &&
+                           (st->f_files & 0xffffffff00000000ULL))
                                return -EOVERFLOW;
-                       if (st.f_ffree != -1 &&
-                           (st.f_ffree & 0xffffffff00000000ULL))
+                       if (st->f_ffree != -1 &&
+                           (st->f_ffree & 0xffffffff00000000ULL))
                                return -EOVERFLOW;
                }
 
-               buf->f_type = st.f_type;
-               buf->f_bsize = st.f_bsize;
-               buf->f_blocks = st.f_blocks;
-               buf->f_bfree = st.f_bfree;
-               buf->f_bavail = st.f_bavail;
-               buf->f_files = st.f_files;
-               buf->f_ffree = st.f_ffree;
-               buf->f_fsid = st.f_fsid;
-               buf->f_namelen = st.f_namelen;
-               buf->f_frsize = st.f_frsize;
-               buf->f_flags = st.f_flags;
-               memset(buf->f_spare, 0, sizeof(buf->f_spare));
+               buf.f_type = st->f_type;
+               buf.f_bsize = st->f_bsize;
+               buf.f_blocks = st->f_blocks;
+               buf.f_bfree = st->f_bfree;
+               buf.f_bavail = st->f_bavail;
+               buf.f_files = st->f_files;
+               buf.f_ffree = st->f_ffree;
+               buf.f_fsid = st->f_fsid;
+               buf.f_namelen = st->f_namelen;
+               buf.f_frsize = st->f_frsize;
+               buf.f_flags = st->f_flags;
+               memset(buf.f_spare, 0, sizeof(buf.f_spare));
        }
+       if (copy_to_user(p, &buf, sizeof(buf)))
+               return -EFAULT;
        return 0;
 }
 
-static int do_statfs64(struct path *path, struct statfs64 *buf)
+static int do_statfs64(struct kstatfs *st, struct statfs64 __user *p)
 {
-       struct kstatfs st;
-       int retval;
-
-       retval = vfs_statfs(path, &st);
-       if (retval)
-               return retval;
-
-       if (sizeof(*buf) == sizeof(st))
-               memcpy(buf, &st, sizeof(st));
+       struct statfs64 buf;
+       if (sizeof(buf) == sizeof(*st))
+               memcpy(&buf, st, sizeof(*st));
        else {
-               buf->f_type = st.f_type;
-               buf->f_bsize = st.f_bsize;
-               buf->f_blocks = st.f_blocks;
-               buf->f_bfree = st.f_bfree;
-               buf->f_bavail = st.f_bavail;
-               buf->f_files = st.f_files;
-               buf->f_ffree = st.f_ffree;
-               buf->f_fsid = st.f_fsid;
-               buf->f_namelen = st.f_namelen;
-               buf->f_frsize = st.f_frsize;
-               buf->f_flags = st.f_flags;
-               memset(buf->f_spare, 0, sizeof(buf->f_spare));
+               buf.f_type = st->f_type;
+               buf.f_bsize = st->f_bsize;
+               buf.f_blocks = st->f_blocks;
+               buf.f_bfree = st->f_bfree;
+               buf.f_bavail = st->f_bavail;
+               buf.f_files = st->f_files;
+               buf.f_ffree = st->f_ffree;
+               buf.f_fsid = st->f_fsid;
+               buf.f_namelen = st->f_namelen;
+               buf.f_frsize = st->f_frsize;
+               buf.f_flags = st->f_flags;
+               memset(buf.f_spare, 0, sizeof(buf.f_spare));
        }
+       if (copy_to_user(p, &buf, sizeof(buf)))
+               return -EFAULT;
        return 0;
 }
 
 SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
 {
-       struct path path;
-       int error;
-
-       error = user_path(pathname, &path);
-       if (!error) {
-               struct statfs tmp;
-               error = do_statfs_native(&path, &tmp);
-               if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
-                       error = -EFAULT;
-               path_put(&path);
-       }
+       struct kstatfs st;
+       int error = user_statfs(pathname, &st);
+       if (!error)
+               error = do_statfs_native(&st, buf);
        return error;
 }
 
 SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
 {
-       struct path path;
-       long error;
-
+       struct kstatfs st;
+       int error;
        if (sz != sizeof(*buf))
                return -EINVAL;
-       error = user_path(pathname, &path);
-       if (!error) {
-               struct statfs64 tmp;
-               error = do_statfs64(&path, &tmp);
-               if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
-                       error = -EFAULT;
-               path_put(&path);
-       }
+       error = user_statfs(pathname, &st);
+       if (!error)
+               error = do_statfs64(&st, buf);
        return error;
 }
 
 SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
 {
-       struct file *file;
-       struct statfs tmp;
-       int error;
-
-       error = -EBADF;
-       file = fget(fd);
-       if (!file)
-               goto out;
-       error = do_statfs_native(&file->f_path, &tmp);
-       if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
-               error = -EFAULT;
-       fput(file);
-out:
+       struct kstatfs st;
+       int error = fd_statfs(fd, &st);
+       if (!error)
+               error = do_statfs_native(&st, buf);
        return error;
 }
 
 SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
 {
-       struct file *file;
-       struct statfs64 tmp;
+       struct kstatfs st;
        int error;
 
        if (sz != sizeof(*buf))
                return -EINVAL;
 
-       error = -EBADF;
-       file = fget(fd);
-       if (!file)
-               goto out;
-       error = do_statfs64(&file->f_path, &tmp);
-       if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
-               error = -EFAULT;
-       fput(file);
-out:
+       error = fd_statfs(fd, &st);
+       if (!error)
+               error = do_statfs64(&st, buf);
        return error;
 }
 
index 74e149e..7e9dd4c 100644 (file)
@@ -177,6 +177,11 @@ void deactivate_locked_super(struct super_block *s)
        struct file_system_type *fs = s->s_type;
        if (atomic_dec_and_test(&s->s_active)) {
                fs->kill_sb(s);
+               /*
+                * We need to call rcu_barrier so all the delayed rcu free
+                * inodes are flushed before we release the fs module.
+                */
+               rcu_barrier();
                put_filesystem(fs);
                put_super(s);
        } else {
index b427b12..e474fbc 100644 (file)
@@ -245,7 +245,6 @@ static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
                new_de = sysv_find_entry(new_dentry, &new_page);
                if (!new_de)
                        goto out_dir;
-               inode_inc_link_count(old_inode);
                sysv_set_link(new_de, new_page, old_inode);
                new_inode->i_ctime = CURRENT_TIME_SEC;
                if (dir_de)
@@ -257,18 +256,15 @@ static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
                        if (new_dir->i_nlink >= SYSV_SB(new_dir->i_sb)->s_link_max)
                                goto out_dir;
                }
-               inode_inc_link_count(old_inode);
                err = sysv_add_link(new_dentry, old_inode);
-               if (err) {
-                       inode_dec_link_count(old_inode);
+               if (err)
                        goto out_dir;
-               }
                if (dir_de)
                        inode_inc_link_count(new_dir);
        }
 
        sysv_delete_entry(old_de, old_page);
-       inode_dec_link_count(old_inode);
+       mark_inode_dirty(old_inode);
 
        if (dir_de) {
                sysv_set_link(dir_de, dir_page, new_dir);
index 14f64b6..7217d67 100644 (file)
@@ -522,24 +522,6 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
        ubifs_assert(mutex_is_locked(&dir->i_mutex));
        ubifs_assert(mutex_is_locked(&inode->i_mutex));
 
-       /*
-        * Return -ENOENT if we've raced with unlink and i_nlink is 0.  Doing
-        * otherwise has the potential to corrupt the orphan inode list.
-        *
-        * Indeed, consider a scenario when 'vfs_link(dirA/fileA)' and
-        * 'vfs_unlink(dirA/fileA, dirB/fileB)' race. 'vfs_link()' does not
-        * lock 'dirA->i_mutex', so this is possible. Both of the functions
-        * lock 'fileA->i_mutex' though. Suppose 'vfs_unlink()' wins, and takes
-        * 'fileA->i_mutex' mutex first. Suppose 'fileA->i_nlink' is 1. In this
-        * case 'ubifs_unlink()' will drop the last reference, and put 'inodeA'
-        * to the list of orphans. After this, 'vfs_link()' will link
-        * 'dirB/fileB' to 'inodeA'. This is a problem because, for example,
-        * the subsequent 'vfs_unlink(dirB/fileB)' will add the same inode
-        * to the list of orphans.
-        */
-        if (inode->i_nlink == 0)
-                return -ENOENT;
-
        err = dbg_check_synced_i_size(inode);
        if (err)
                return err;
index 2be0f9e..f1dce84 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/crc-itu-t.h>
 #include <linux/exportfs.h>
 
+enum { UDF_MAX_LINKS = 0xffff };
+
 static inline int udf_match(int len1, const unsigned char *name1, int len2,
                            const unsigned char *name2)
 {
@@ -650,7 +652,7 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        struct udf_inode_info *iinfo;
 
        err = -EMLINK;
-       if (dir->i_nlink >= (256 << sizeof(dir->i_nlink)) - 1)
+       if (dir->i_nlink >= UDF_MAX_LINKS)
                goto out;
 
        err = -EIO;
@@ -1034,9 +1036,8 @@ static int udf_link(struct dentry *old_dentry, struct inode *dir,
        struct fileIdentDesc cfi, *fi;
        int err;
 
-       if (inode->i_nlink >= (256 << sizeof(inode->i_nlink)) - 1) {
+       if (inode->i_nlink >= UDF_MAX_LINKS)
                return -EMLINK;
-       }
 
        fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
        if (!fi) {
@@ -1131,9 +1132,7 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
                        goto end_rename;
 
                retval = -EMLINK;
-               if (!new_inode &&
-                       new_dir->i_nlink >=
-                               (256 << sizeof(new_dir->i_nlink)) - 1)
+               if (!new_inode && new_dir->i_nlink >= UDF_MAX_LINKS)
                        goto end_rename;
        }
        if (!nfi) {
@@ -1287,8 +1286,13 @@ static int udf_encode_fh(struct dentry *de, __u32 *fh, int *lenp,
        struct fid *fid = (struct fid *)fh;
        int type = FILEID_UDF_WITHOUT_PARENT;
 
-       if (len < 3 || (connectable && len < 5))
+       if (connectable && (len < 5)) {
+               *lenp = 5;
                return 255;
+       } else if (len < 3) {
+               *lenp = 3;
+               return 255;
+       }
 
        *lenp = 3;
        fid->udf.block = location.logicalBlockNum;
index 12f39b9..d6f6815 100644 (file)
@@ -306,7 +306,6 @@ static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
                new_de = ufs_find_entry(new_dir, &new_dentry->d_name, &new_page);
                if (!new_de)
                        goto out_dir;
-               inode_inc_link_count(old_inode);
                ufs_set_link(new_dir, new_de, new_page, old_inode);
                new_inode->i_ctime = CURRENT_TIME_SEC;
                if (dir_de)
@@ -318,12 +317,9 @@ static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        if (new_dir->i_nlink >= UFS_LINK_MAX)
                                goto out_dir;
                }
-               inode_inc_link_count(old_inode);
                err = ufs_add_link(new_dentry, old_inode);
-               if (err) {
-                       inode_dec_link_count(old_inode);
+               if (err)
                        goto out_dir;
-               }
                if (dir_de)
                        inode_inc_link_count(new_dir);
        }
@@ -331,12 +327,11 @@ static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
        /*
         * Like most other Unix systems, set the ctime for inodes on a
         * rename.
-        * inode_dec_link_count() will mark the inode dirty.
         */
        old_inode->i_ctime = CURRENT_TIME_SEC;
 
        ufs_delete_entry(old_dir, old_de, old_page);
-       inode_dec_link_count(old_inode);
+       mark_inode_dirty(old_inode);
 
        if (dir_de) {
                ufs_set_link(old_inode, dir_de, dir_page, new_dir);
index ac1c7e8..f83a4c8 100644 (file)
@@ -2022,11 +2022,12 @@ xfs_buf_init(void)
        if (!xfslogd_workqueue)
                goto out_free_buf_zone;
 
-       xfsdatad_workqueue = create_workqueue("xfsdatad");
+       xfsdatad_workqueue = alloc_workqueue("xfsdatad", WQ_MEM_RECLAIM, 1);
        if (!xfsdatad_workqueue)
                goto out_destroy_xfslogd_workqueue;
 
-       xfsconvertd_workqueue = create_workqueue("xfsconvertd");
+       xfsconvertd_workqueue = alloc_workqueue("xfsconvertd",
+                                               WQ_MEM_RECLAIM, 1);
        if (!xfsconvertd_workqueue)
                goto out_destroy_xfsdatad_workqueue;
 
index 05201ae..d61611c 100644 (file)
@@ -152,6 +152,8 @@ xfs_ioc_trim(
 
        if (!capable(CAP_SYS_ADMIN))
                return -XFS_ERROR(EPERM);
+       if (!blk_queue_discard(q))
+               return -XFS_ERROR(EOPNOTSUPP);
        if (copy_from_user(&range, urange, sizeof(range)))
                return -XFS_ERROR(EFAULT);
 
index fc0114d..f4f878f 100644 (file)
@@ -89,8 +89,10 @@ xfs_fs_encode_fh(
         * seven combinations work.  The real answer is "don't use v2".
         */
        len = xfs_fileid_length(fileid_type);
-       if (*max_len < len)
+       if (*max_len < len) {
+               *max_len = len;
                return 255;
+       }
        *max_len = len;
 
        switch (fileid_type) {
index b06ede1..0ca0e3c 100644 (file)
@@ -695,14 +695,19 @@ xfs_ioc_fsgeometry_v1(
        xfs_mount_t             *mp,
        void                    __user *arg)
 {
-       xfs_fsop_geom_v1_t      fsgeo;
+       xfs_fsop_geom_t         fsgeo;
        int                     error;
 
-       error = xfs_fs_geometry(mp, (xfs_fsop_geom_t *)&fsgeo, 3);
+       error = xfs_fs_geometry(mp, &fsgeo, 3);
        if (error)
                return -error;
 
-       if (copy_to_user(arg, &fsgeo, sizeof(fsgeo)))
+       /*
+        * Caller should have passed an argument of type
+        * xfs_fsop_geom_v1_t.  This is a proper subset of the
+        * xfs_fsop_geom_t that xfs_fs_geometry() fills in.
+        */
+       if (copy_to_user(arg, &fsgeo, sizeof(xfs_fsop_geom_v1_t)))
                return -XFS_ERROR(EFAULT);
        return 0;
 }
@@ -985,10 +990,22 @@ xfs_ioctl_setattr(
 
                /*
                 * Extent size must be a multiple of the appropriate block
-                * size, if set at all.
+                * size, if set at all. It must also be smaller than the
+                * maximum extent size supported by the filesystem.
+                *
+                * Also, for non-realtime files, limit the extent size hint to
+                * half the size of the AGs in the filesystem so alignment
+                * doesn't result in extents larger than an AG.
                 */
                if (fa->fsx_extsize != 0) {
-                       xfs_extlen_t    size;
+                       xfs_extlen_t    size;
+                       xfs_fsblock_t   extsize_fsb;
+
+                       extsize_fsb = XFS_B_TO_FSB(mp, fa->fsx_extsize);
+                       if (extsize_fsb > MAXEXTLEN) {
+                               code = XFS_ERROR(EINVAL);
+                               goto error_return;
+                       }
 
                        if (XFS_IS_REALTIME_INODE(ip) ||
                            ((mask & FSX_XFLAGS) &&
@@ -997,6 +1014,10 @@ xfs_ioctl_setattr(
                                       mp->m_sb.sb_blocklog;
                        } else {
                                size = mp->m_sb.sb_blocksize;
+                               if (extsize_fsb > mp->m_sb.sb_agblocks / 2) {
+                                       code = XFS_ERROR(EINVAL);
+                                       goto error_return;
+                               }
                        }
 
                        if (fa->fsx_extsize % size) {
index f8e854b..206a281 100644 (file)
@@ -1863,12 +1863,14 @@ xfs_qm_dqreclaim_one(void)
        xfs_dquot_t     *dqpout;
        xfs_dquot_t     *dqp;
        int             restarts;
+       int             startagain;
 
        restarts = 0;
        dqpout = NULL;
 
        /* lockorder: hashchainlock, freelistlock, mplistlock, dqlock, dqflock */
-startagain:
+again:
+       startagain = 0;
        mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
 
        list_for_each_entry(dqp, &xfs_Gqm->qm_dqfrlist, q_freelist) {
@@ -1885,13 +1887,10 @@ startagain:
                        ASSERT(! (dqp->dq_flags & XFS_DQ_INACTIVE));
 
                        trace_xfs_dqreclaim_want(dqp);
-
-                       xfs_dqunlock(dqp);
-                       mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
-                       if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
-                               return NULL;
                        XQM_STATS_INC(xqmstats.xs_qm_dqwants);
-                       goto startagain;
+                       restarts++;
+                       startagain = 1;
+                       goto dqunlock;
                }
 
                /*
@@ -1906,23 +1905,20 @@ startagain:
                        ASSERT(list_empty(&dqp->q_mplist));
                        list_del_init(&dqp->q_freelist);
                        xfs_Gqm->qm_dqfrlist_cnt--;
-                       xfs_dqunlock(dqp);
                        dqpout = dqp;
                        XQM_STATS_INC(xqmstats.xs_qm_dqinact_reclaims);
-                       break;
+                       goto dqunlock;
                }
 
                ASSERT(dqp->q_hash);
                ASSERT(!list_empty(&dqp->q_mplist));
 
                /*
-                * Try to grab the flush lock. If this dquot is in the process of
-                * getting flushed to disk, we don't want to reclaim it.
+                * Try to grab the flush lock. If this dquot is in the process
+                * of getting flushed to disk, we don't want to reclaim it.
                 */
-               if (!xfs_dqflock_nowait(dqp)) {
-                       xfs_dqunlock(dqp);
-                       continue;
-               }
+               if (!xfs_dqflock_nowait(dqp))
+                       goto dqunlock;
 
                /*
                 * We have the flush lock so we know that this is not in the
@@ -1944,8 +1940,7 @@ startagain:
                                xfs_fs_cmn_err(CE_WARN, mp,
                        "xfs_qm_dqreclaim: dquot %p flush failed", dqp);
                        }
-                       xfs_dqunlock(dqp); /* dqflush unlocks dqflock */
-                       continue;
+                       goto dqunlock;
                }
 
                /*
@@ -1967,13 +1962,8 @@ startagain:
                 */
                if (!mutex_trylock(&mp->m_quotainfo->qi_dqlist_lock)) {
                        restarts++;
-                       mutex_unlock(&dqp->q_hash->qh_lock);
-                       xfs_dqfunlock(dqp);
-                       xfs_dqunlock(dqp);
-                       mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
-                       if (restarts++ >= XFS_QM_RECLAIM_MAX_RESTARTS)
-                               return NULL;
-                       goto startagain;
+                       startagain = 1;
+                       goto qhunlock;
                }
 
                ASSERT(dqp->q_nrefs == 0);
@@ -1986,14 +1976,20 @@ startagain:
                xfs_Gqm->qm_dqfrlist_cnt--;
                dqpout = dqp;
                mutex_unlock(&mp->m_quotainfo->qi_dqlist_lock);
+qhunlock:
                mutex_unlock(&dqp->q_hash->qh_lock);
 dqfunlock:
                xfs_dqfunlock(dqp);
+dqunlock:
                xfs_dqunlock(dqp);
                if (dqpout)
                        break;
                if (restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
-                       return NULL;
+                       break;
+               if (startagain) {
+                       mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
+                       goto again;
+               }
        }
        mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
        return dqpout;
index 0ab56b3..d0b3bc7 100644 (file)
@@ -74,6 +74,22 @@ typedef unsigned int xfs_alloctype_t;
  */
 #define XFS_ALLOC_SET_ASIDE(mp)  (4 + ((mp)->m_sb.sb_agcount * 4))
 
+/*
+ * When deciding how much space to allocate out of an AG, we limit the
+ * allocation maximum size to the size the AG. However, we cannot use all the
+ * blocks in the AG - some are permanently used by metadata. These
+ * blocks are generally:
+ *     - the AG superblock, AGF, AGI and AGFL
+ *     - the AGF (bno and cnt) and AGI btree root blocks
+ *     - 4 blocks on the AGFL according to XFS_ALLOC_SET_ASIDE() limits
+ *
+ * The AG headers are sector sized, so the amount of space they take up is
+ * dependent on filesystem geometry. The others are all single blocks.
+ */
+#define XFS_ALLOC_AG_MAX_USABLE(mp)    \
+       ((mp)->m_sb.sb_agblocks - XFS_BB_TO_FSB(mp, XFS_FSS_TO_BB(mp, 4)) - 7)
+
+
 /*
  * Argument structure for xfs_alloc routines.
  * This is turned into a structure to avoid having 20 arguments passed
index 4111cd3..dc3afd7 100644 (file)
@@ -1038,17 +1038,34 @@ xfs_bmap_add_extent_delay_real(
                 * Filling in the middle part of a previous delayed allocation.
                 * Contiguity is impossible here.
                 * This case is avoided almost all the time.
+                *
+                * We start with a delayed allocation:
+                *
+                * +ddddddddddddddddddddddddddddddddddddddddddddddddddddddd+
+                *  PREV @ idx
+                *
+                * and we are allocating:
+                *                     +rrrrrrrrrrrrrrrrr+
+                *                            new
+                *
+                * and we set it up for insertion as:
+                * +ddddddddddddddddddd+rrrrrrrrrrrrrrrrr+ddddddddddddddddd+
+                *                            new
+                *  PREV @ idx          LEFT              RIGHT
+                *                      inserted at idx + 1
                 */
                temp = new->br_startoff - PREV.br_startoff;
-               trace_xfs_bmap_pre_update(ip, idx, 0, _THIS_IP_);
-               xfs_bmbt_set_blockcount(ep, temp);
-               r[0] = *new;
-               r[1].br_state = PREV.br_state;
-               r[1].br_startblock = 0;
-               r[1].br_startoff = new_endoff;
                temp2 = PREV.br_startoff + PREV.br_blockcount - new_endoff;
-               r[1].br_blockcount = temp2;
-               xfs_iext_insert(ip, idx + 1, 2, &r[0], state);
+               trace_xfs_bmap_pre_update(ip, idx, 0, _THIS_IP_);
+               xfs_bmbt_set_blockcount(ep, temp);      /* truncate PREV */
+               LEFT = *new;
+               RIGHT.br_state = PREV.br_state;
+               RIGHT.br_startblock = nullstartblock(
+                               (int)xfs_bmap_worst_indlen(ip, temp2));
+               RIGHT.br_startoff = new_endoff;
+               RIGHT.br_blockcount = temp2;
+               /* insert LEFT (r[0]) and RIGHT (r[1]) at the same time */
+               xfs_iext_insert(ip, idx + 1, 2, &LEFT, state);
                ip->i_df.if_lastex = idx + 1;
                ip->i_d.di_nextents++;
                if (cur == NULL)
@@ -2430,7 +2447,7 @@ xfs_bmap_btalloc_nullfb(
                startag = ag = 0;
 
        pag = xfs_perag_get(mp, ag);
-       while (*blen < ap->alen) {
+       while (*blen < args->maxlen) {
                if (!pag->pagf_init) {
                        error = xfs_alloc_pagf_init(mp, args->tp, ag,
                                                    XFS_ALLOC_FLAG_TRYLOCK);
@@ -2452,7 +2469,7 @@ xfs_bmap_btalloc_nullfb(
                        notinit = 1;
 
                if (xfs_inode_is_filestream(ap->ip)) {
-                       if (*blen >= ap->alen)
+                       if (*blen >= args->maxlen)
                                break;
 
                        if (ap->userdata) {
@@ -2498,14 +2515,14 @@ xfs_bmap_btalloc_nullfb(
         * If the best seen length is less than the request
         * length, use the best as the minimum.
         */
-       else if (*blen < ap->alen)
+       else if (*blen < args->maxlen)
                args->minlen = *blen;
        /*
-        * Otherwise we've seen an extent as big as alen,
+        * Otherwise we've seen an extent as big as maxlen,
         * use that as the minimum.
         */
        else
-               args->minlen = ap->alen;
+               args->minlen = args->maxlen;
 
        /*
         * set the failure fallback case to look in the selected
@@ -2573,7 +2590,9 @@ xfs_bmap_btalloc(
        args.tp = ap->tp;
        args.mp = mp;
        args.fsbno = ap->rval;
-       args.maxlen = MIN(ap->alen, mp->m_sb.sb_agblocks);
+
+       /* Trim the allocation back to the maximum an AG can fit. */
+       args.maxlen = MIN(ap->alen, XFS_ALLOC_AG_MAX_USABLE(mp));
        args.firstblock = ap->firstblock;
        blen = 0;
        if (nullfb) {
@@ -2621,7 +2640,7 @@ xfs_bmap_btalloc(
                        /*
                         * Adjust for alignment
                         */
-                       if (blen > args.alignment && blen <= ap->alen)
+                       if (blen > args.alignment && blen <= args.maxlen)
                                args.minlen = blen - args.alignment;
                        args.minalignslop = 0;
                } else {
@@ -2640,7 +2659,7 @@ xfs_bmap_btalloc(
                         * of minlen+alignment+slop doesn't go up
                         * between the calls.
                         */
-                       if (blen > mp->m_dalign && blen <= ap->alen)
+                       if (blen > mp->m_dalign && blen <= args.maxlen)
                                nextminlen = blen - mp->m_dalign;
                        else
                                nextminlen = args.minlen;
@@ -4485,6 +4504,16 @@ xfs_bmapi(
                                /* Figure out the extent size, adjust alen */
                                extsz = xfs_get_extsz_hint(ip);
                                if (extsz) {
+                                       /*
+                                        * make sure we don't exceed a single
+                                        * extent length when we align the
+                                        * extent by reducing length we are
+                                        * going to allocate by the maximum
+                                        * amount extent size aligment may
+                                        * require.
+                                        */
+                                       alen = XFS_FILBLKS_MIN(len,
+                                                  MAXEXTLEN - (2 * extsz - 1));
                                        error = xfs_bmap_extsize_align(mp,
                                                        &got, &prev, extsz,
                                                        rt, eof,
index 98c6f73..6f8c21c 100644 (file)
@@ -427,13 +427,15 @@ xfs_buf_item_unpin(
 
                if (remove) {
                        /*
-                        * We have to remove the log item from the transaction
-                        * as we are about to release our reference to the
-                        * buffer.  If we don't, the unlock that occurs later
-                        * in xfs_trans_uncommit() will ry to reference the
+                        * If we are in a transaction context, we have to
+                        * remove the log item from the transaction as we are
+                        * about to release our reference to the buffer.  If we
+                        * don't, the unlock that occurs later in
+                        * xfs_trans_uncommit() will try to reference the
                         * buffer which we no longer have a hold on.
                         */
-                       xfs_trans_del_item(lip);
+                       if (lip->li_desc)
+                               xfs_trans_del_item(lip);
 
                        /*
                         * Since the transaction no longer refers to the buffer,
index 75f2ef6..d22e626 100644 (file)
@@ -138,7 +138,8 @@ xfs_efi_item_unpin(
 
        if (remove) {
                ASSERT(!(lip->li_flags & XFS_LI_IN_AIL));
-               xfs_trans_del_item(lip);
+               if (lip->li_desc)
+                       xfs_trans_del_item(lip);
                xfs_efi_item_free(efip);
                return;
        }
index cec89dd..85668ef 100644 (file)
@@ -53,6 +53,9 @@ xfs_fs_geometry(
        xfs_fsop_geom_t         *geo,
        int                     new_version)
 {
+
+       memset(geo, 0, sizeof(*geo));
+
        geo->blocksize = mp->m_sb.sb_blocksize;
        geo->rtextsize = mp->m_sb.sb_rextsize;
        geo->agblocks = mp->m_sb.sb_agblocks;
index 55582bd..8a0f044 100644 (file)
@@ -337,7 +337,12 @@ xfs_iomap_prealloc_size(
                int shift = 0;
                int64_t freesp;
 
-               alloc_blocks = XFS_B_TO_FSB(mp, ip->i_size);
+               /*
+                * rounddown_pow_of_two() returns an undefined result
+                * if we pass in alloc_blocks = 0. Hence the "+ 1" to
+                * ensure we always pass in a non-zero value.
+                */
+               alloc_blocks = XFS_B_TO_FSB(mp, ip->i_size) + 1;
                alloc_blocks = XFS_FILEOFF_MIN(MAXEXTLEN,
                                        rounddown_pow_of_two(alloc_blocks));
 
index 916eb7d..3bd3291 100644 (file)
@@ -191,7 +191,7 @@ void          xfs_log_ticket_put(struct xlog_ticket *ticket);
 
 xlog_tid_t xfs_log_get_trans_ident(struct xfs_trans *tp);
 
-int    xfs_log_commit_cil(struct xfs_mount *mp, struct xfs_trans *tp,
+void   xfs_log_commit_cil(struct xfs_mount *mp, struct xfs_trans *tp,
                                struct xfs_log_vec *log_vector,
                                xfs_lsn_t *commit_lsn, int flags);
 bool   xfs_log_item_in_current_chkpt(struct xfs_log_item *lip);
index 9dc8125..9ca59be 100644 (file)
@@ -543,7 +543,7 @@ xlog_cil_push(
 
        error = xlog_write(log, &lvhdr, tic, &ctx->start_lsn, NULL, 0);
        if (error)
-               goto out_abort;
+               goto out_abort_free_ticket;
 
        /*
         * now that we've written the checkpoint into the log, strictly
@@ -569,8 +569,9 @@ restart:
        }
        spin_unlock(&cil->xc_cil_lock);
 
+       /* xfs_log_done always frees the ticket on error. */
        commit_lsn = xfs_log_done(log->l_mp, tic, &commit_iclog, 0);
-       if (error || commit_lsn == -1)
+       if (commit_lsn == -1)
                goto out_abort;
 
        /* attach all the transactions w/ busy extents to iclog */
@@ -600,6 +601,8 @@ out_free_ticket:
        kmem_free(new_ctx);
        return 0;
 
+out_abort_free_ticket:
+       xfs_log_ticket_put(tic);
 out_abort:
        xlog_cil_committed(ctx, XFS_LI_ABORTED);
        return XFS_ERROR(EIO);
@@ -622,7 +625,7 @@ out_abort:
  * background commit, returns without it held once background commits are
  * allowed again.
  */
-int
+void
 xfs_log_commit_cil(
        struct xfs_mount        *mp,
        struct xfs_trans        *tp,
@@ -637,11 +640,6 @@ xfs_log_commit_cil(
        if (flags & XFS_TRANS_RELEASE_LOG_RES)
                log_flags = XFS_LOG_REL_PERM_RESERV;
 
-       if (XLOG_FORCED_SHUTDOWN(log)) {
-               xlog_cil_free_logvec(log_vector);
-               return XFS_ERROR(EIO);
-       }
-
        /*
         * do all the hard work of formatting items (including memory
         * allocation) outside the CIL context lock. This prevents stalling CIL
@@ -701,7 +699,6 @@ xfs_log_commit_cil(
         */
        if (push)
                xlog_cil_push(log, 0);
-       return 0;
 }
 
 /*
index edfa178..4aff563 100644 (file)
@@ -309,7 +309,7 @@ xfs_mru_cache_init(void)
        if (!xfs_mru_elem_zone)
                goto out;
 
-       xfs_mru_reap_wq = create_singlethread_workqueue("xfs_mru_cache");
+       xfs_mru_reap_wq = alloc_workqueue("xfs_mru_cache", WQ_MEM_RECLAIM, 1);
        if (!xfs_mru_reap_wq)
                goto out_destroy_mru_elem_zone;
 
index 33dbc4e..7692279 100644 (file)
@@ -1446,6 +1446,14 @@ xfs_log_item_batch_insert(
  * Bulk operation version of xfs_trans_committed that takes a log vector of
  * items to insert into the AIL. This uses bulk AIL insertion techniques to
  * minimise lock traffic.
+ *
+ * If we are called with the aborted flag set, it is because a log write during
+ * a CIL checkpoint commit has failed. In this case, all the items in the
+ * checkpoint have already gone through IOP_COMMITED and IOP_UNLOCK, which
+ * means that checkpoint commit abort handling is treated exactly the same
+ * as an iclog write error even though we haven't started any IO yet. Hence in
+ * this case all we need to do is IOP_COMMITTED processing, followed by an
+ * IOP_UNPIN(aborted) call.
  */
 void
 xfs_trans_committed_bulk(
@@ -1472,6 +1480,16 @@ xfs_trans_committed_bulk(
                if (XFS_LSN_CMP(item_lsn, (xfs_lsn_t)-1) == 0)
                        continue;
 
+               /*
+                * if we are aborting the operation, no point in inserting the
+                * object into the AIL as we are in a shutdown situation.
+                */
+               if (aborted) {
+                       ASSERT(XFS_FORCED_SHUTDOWN(ailp->xa_mount));
+                       IOP_UNPIN(lip, 1);
+                       continue;
+               }
+
                if (item_lsn != commit_lsn) {
 
                        /*
@@ -1503,20 +1521,24 @@ xfs_trans_committed_bulk(
 }
 
 /*
- * Called from the trans_commit code when we notice that
- * the filesystem is in the middle of a forced shutdown.
+ * Called from the trans_commit code when we notice that the filesystem is in
+ * the middle of a forced shutdown.
+ *
+ * When we are called here, we have already pinned all the items in the
+ * transaction. However, neither IOP_COMMITTING or IOP_UNLOCK has been called
+ * so we can simply walk the items in the transaction, unpin them with an abort
+ * flag and then free the items. Note that unpinning the items can result in
+ * them being freed immediately, so we need to use a safe list traversal method
+ * here.
  */
 STATIC void
 xfs_trans_uncommit(
        struct xfs_trans        *tp,
        uint                    flags)
 {
-       struct xfs_log_item_desc *lidp;
+       struct xfs_log_item_desc *lidp, *n;
 
-       list_for_each_entry(lidp, &tp->t_items, lid_trans) {
-               /*
-                * Unpin all but those that aren't dirty.
-                */
+       list_for_each_entry_safe(lidp, n, &tp->t_items, lid_trans) {
                if (lidp->lid_flags & XFS_LID_DIRTY)
                        IOP_UNPIN(lidp->lid_item, 1);
        }
@@ -1733,7 +1755,6 @@ xfs_trans_commit_cil(
        int                     flags)
 {
        struct xfs_log_vec      *log_vector;
-       int                     error;
 
        /*
         * Get each log item to allocate a vector structure for
@@ -1744,9 +1765,7 @@ xfs_trans_commit_cil(
        if (!log_vector)
                return ENOMEM;
 
-       error = xfs_log_commit_cil(mp, tp, log_vector, commit_lsn, flags);
-       if (error)
-               return error;
+       xfs_log_commit_cil(mp, tp, log_vector, commit_lsn, flags);
 
        current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
        xfs_trans_free(tp);
index 2bcc5c7..61e03dd 100644 (file)
@@ -30,6 +30,9 @@ typedef u64 cputime64_t;
 #define cputime64_to_jiffies64(__ct)   (__ct)
 #define jiffies64_to_cputime64(__jif)  (__jif)
 #define cputime_to_cputime64(__ct)     ((u64) __ct)
+#define cputime64_gt(__a, __b)         ((__a) >  (__b))
+
+#define nsecs_to_cputime64(__ct)       nsecs_to_jiffies64(__ct)
 
 
 /*
index 0fc16e3..84793c7 100644 (file)
 #define O_SYNC         (__O_SYNC|O_DSYNC)
 #endif
 
+#ifndef O_PATH
+#define O_PATH         010000000
+#endif
+
 #ifndef O_NDELAY
 #define O_NDELAY       O_NONBLOCK
 #endif
index 3c2344f..01f227e 100644 (file)
@@ -6,7 +6,7 @@
 #include <asm/errno.h>
 
 static inline int
-futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
 {
        int op = (encoded_op >> 28) & 7;
        int cmp = (encoded_op >> 24) & 15;
@@ -16,7 +16,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
        if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
                oparg = 1 << oparg;
 
-       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+       if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
                return -EFAULT;
 
        pagefault_disable();
@@ -48,7 +48,8 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
 }
 
 static inline int
-futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+                             u32 oldval, u32 newval)
 {
        return -ENOSYS;
 }
index 31b6188..b4bfe33 100644 (file)
@@ -4,6 +4,8 @@
 #ifndef __ASSEMBLY__
 #ifdef CONFIG_MMU
 
+#include <linux/mm_types.h>
+
 #ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
 extern int ptep_set_access_flags(struct vm_area_struct *vma,
                                 unsigned long address, pte_t *ptep,
index b3bfabc..c1a1216 100644 (file)
@@ -11,6 +11,7 @@ extern char _sinittext[], _einittext[];
 extern char _end[];
 extern char __per_cpu_load[], __per_cpu_start[], __per_cpu_end[];
 extern char __kprobes_text_start[], __kprobes_text_end[];
+extern char __entry_text_start[], __entry_text_end[];
 extern char __initdata_begin[], __initdata_end[];
 extern char __start_rodata[], __end_rodata[];
 
index b969770..57af033 100644 (file)
@@ -646,9 +646,13 @@ __SYSCALL(__NR_prlimit64, sys_prlimit64)
 __SYSCALL(__NR_fanotify_init, sys_fanotify_init)
 #define __NR_fanotify_mark 263
 __SYSCALL(__NR_fanotify_mark, sys_fanotify_mark)
+#define __NR_name_to_handle_at         264
+__SYSCALL(__NR_name_to_handle_at, sys_name_to_handle_at)
+#define __NR_open_by_handle_at         265
+__SYSCALL(__NR_open_by_handle_at, sys_open_by_handle_at)
 
 #undef __NR_syscalls
-#define __NR_syscalls 264
+#define __NR_syscalls 266
 
 /*
  * All syscalls below here should go away really,
index 439df58..32c45e5 100644 (file)
 #endif
 
 #ifdef CONFIG_EVENT_TRACING
-#define FTRACE_EVENTS()        VMLINUX_SYMBOL(__start_ftrace_events) = .;      \
+#define FTRACE_EVENTS()        . = ALIGN(8);                                   \
+                       VMLINUX_SYMBOL(__start_ftrace_events) = .;      \
                        *(_ftrace_events)                               \
                        VMLINUX_SYMBOL(__stop_ftrace_events) = .;
 #else
 #endif
 
 #ifdef CONFIG_FTRACE_SYSCALLS
-#define TRACE_SYSCALLS() VMLINUX_SYMBOL(__start_syscalls_metadata) = .;        \
+#define TRACE_SYSCALLS() . = ALIGN(8);                                 \
+                        VMLINUX_SYMBOL(__start_syscalls_metadata) = .; \
                         *(__syscalls_metadata)                         \
                         VMLINUX_SYMBOL(__stop_syscalls_metadata) = .;
 #else
        CPU_KEEP(exit.data)                                             \
        MEM_KEEP(init.data)                                             \
        MEM_KEEP(exit.data)                                             \
-       . = ALIGN(32);                                                  \
-       VMLINUX_SYMBOL(__start___tracepoints) = .;                      \
+       STRUCT_ALIGN();                                                 \
        *(__tracepoints)                                                \
-       VMLINUX_SYMBOL(__stop___tracepoints) = .;                       \
        /* implement dynamic printk debug */                            \
        . = ALIGN(8);                                                   \
        VMLINUX_SYMBOL(__start___verbose) = .;                          \
        VMLINUX_SYMBOL(__stop___verbose) = .;                           \
        LIKELY_PROFILE()                                                \
        BRANCH_PROFILE()                                                \
-       TRACE_PRINTKS()                                                 \
-                                                                       \
-       STRUCT_ALIGN();                                                 \
-       FTRACE_EVENTS()                                                 \
-                                                                       \
-       STRUCT_ALIGN();                                                 \
-       TRACE_SYSCALLS()
+       TRACE_PRINTKS()
 
 /*
  * Data section helpers
                VMLINUX_SYMBOL(__start_rodata) = .;                     \
                *(.rodata) *(.rodata.*)                                 \
                *(__vermagic)           /* Kernel version magic */      \
+               . = ALIGN(8);                                           \
+               VMLINUX_SYMBOL(__start___tracepoints_ptrs) = .;         \
+               *(__tracepoints_ptrs)   /* Tracepoints: pointer array */\
+               VMLINUX_SYMBOL(__stop___tracepoints_ptrs) = .;          \
                *(__markers_strings)    /* Markers: strings */          \
                *(__tracepoints_strings)/* Tracepoints: strings */      \
        }                                                               \
                *(.kprobes.text)                                        \
                VMLINUX_SYMBOL(__kprobes_text_end) = .;
 
+#define ENTRY_TEXT                                                     \
+               ALIGN_FUNCTION();                                       \
+               VMLINUX_SYMBOL(__entry_text_start) = .;                 \
+               *(.entry.text)                                          \
+               VMLINUX_SYMBOL(__entry_text_end) = .;
+
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 #define IRQENTRY_TEXT                                                  \
                ALIGN_FUNCTION();                                       \
        KERNEL_CTORS()                                                  \
        *(.init.rodata)                                                 \
        MCOUNT_REC()                                                    \
+       FTRACE_EVENTS()                                                 \
+       TRACE_SYSCALLS()                                                \
        DEV_DISCARD(init.rodata)                                        \
        CPU_DISCARD(init.rodata)                                        \
        MEM_DISCARD(init.rodata)                                        \
index a4694c6..348843b 100644 (file)
@@ -1101,7 +1101,7 @@ struct drm_device {
        struct platform_device *platformdev; /**< Platform device struture */
 
        struct drm_sg_mem *sg;  /**< Scatter gather memory */
-       int num_crtcs;                  /**< Number of CRTCs on this device */
+       unsigned int num_crtcs;                  /**< Number of CRTCs on this device */
        void *dev_private;              /**< device private data */
        void *mm_private;
        struct address_space *dev_mapping;
@@ -1367,7 +1367,7 @@ extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq);
 extern u32 drm_vblank_count(struct drm_device *dev, int crtc);
 extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
                                     struct timeval *vblanktime);
-extern void drm_handle_vblank(struct drm_device *dev, int crtc);
+extern bool drm_handle_vblank(struct drm_device *dev, int crtc);
 extern int drm_vblank_get(struct drm_device *dev, int crtc);
 extern void drm_vblank_put(struct drm_device *dev, int crtc);
 extern void drm_vblank_off(struct drm_device *dev, int crtc);
index acd7fad..801be59 100644 (file)
@@ -275,6 +275,7 @@ struct drm_pending_vblank_event;
 
 /**
  * drm_crtc_funcs - control CRTCs for a given device
+ * @reset: reset CRTC after state has been invalidate (e.g. resume)
  * @dpms: control display power levels
  * @save: save CRTC state
  * @resore: restore CRTC state
@@ -302,6 +303,8 @@ struct drm_crtc_funcs {
        void (*save)(struct drm_crtc *crtc); /* suspend? */
        /* Restore CRTC state */
        void (*restore)(struct drm_crtc *crtc); /* resume? */
+       /* Reset CRTC state */
+       void (*reset)(struct drm_crtc *crtc);
 
        /* cursor controls */
        int (*cursor_set)(struct drm_crtc *crtc, struct drm_file *file_priv,
@@ -379,6 +382,7 @@ struct drm_crtc {
  * @dpms: set power state (see drm_crtc_funcs above)
  * @save: save connector state
  * @restore: restore connector state
+ * @reset: reset connector after state has been invalidate (e.g. resume)
  * @mode_valid: is this mode valid on the given connector?
  * @mode_fixup: try to fixup proposed mode for this connector
  * @mode_set: set this mode
@@ -396,6 +400,7 @@ struct drm_connector_funcs {
        void (*dpms)(struct drm_connector *connector, int mode);
        void (*save)(struct drm_connector *connector);
        void (*restore)(struct drm_connector *connector);
+       void (*reset)(struct drm_connector *connector);
 
        /* Check to see if anything is attached to the connector.
         * @force is set to false whilst polling, true when checking the
@@ -413,6 +418,7 @@ struct drm_connector_funcs {
 };
 
 struct drm_encoder_funcs {
+       void (*reset)(struct drm_encoder *encoder);
        void (*destroy)(struct drm_encoder *encoder);
 };
 
@@ -656,6 +662,7 @@ extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
                                                   struct drm_display_mode *mode);
 extern void drm_mode_debug_printmodeline(struct drm_display_mode *mode);
 extern void drm_mode_config_init(struct drm_device *dev);
+extern void drm_mode_config_reset(struct drm_device *dev);
 extern void drm_mode_config_cleanup(struct drm_device *dev);
 extern void drm_mode_set_name(struct drm_display_mode *mode);
 extern bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2);
index fe29ae3..5ff1194 100644 (file)
@@ -28,7 +28,6 @@
        {0x1002, 0x4156, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
        {0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP}, \
        {0x1002, 0x4242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
-       {0x1002, 0x4243, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
        {0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
        {0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
        {0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
index 5cb86c3..fc48754 100644 (file)
@@ -99,7 +99,6 @@ struct rxrpc_key_token {
  * structure of raw payloads passed to add_key() or instantiate key
  */
 struct rxrpc_key_data_v1 {
-       u32             kif_version;            /* 1 */
        u16             security_index;
        u16             ticket_length;
        u32             expiry;                 /* time_t */
index 2296d8b..b0ada6f 100644 (file)
@@ -1,5 +1,6 @@
 header-y += byteorder/
 header-y += can/
+header-y += caif/
 header-y += dvb/
 header-y += hdlc/
 header-y += isdn/
index 4d18ff3..d5063e1 100644 (file)
@@ -699,7 +699,7 @@ extern void blk_start_queue(struct request_queue *q);
 extern void blk_stop_queue(struct request_queue *q);
 extern void blk_sync_queue(struct request_queue *q);
 extern void __blk_stop_queue(struct request_queue *q);
-extern void __blk_run_queue(struct request_queue *);
+extern void __blk_run_queue(struct request_queue *q, bool force_kblockd);
 extern void blk_run_queue(struct request_queue *);
 extern int blk_rq_map_user(struct request_queue *, struct request *,
                           struct rq_map_data *, void __user *, unsigned long,
@@ -1088,7 +1088,6 @@ static inline void put_dev_sector(Sector p)
 
 struct work_struct;
 int kblockd_schedule_work(struct request_queue *q, struct work_struct *work);
-int kblockd_schedule_delayed_work(struct request_queue *q, struct delayed_work *dwork, unsigned long delay);
 
 #ifdef CONFIG_BLK_CGROUP
 /*
@@ -1136,7 +1135,6 @@ static inline uint64_t rq_io_start_time_ns(struct request *req)
 extern int blk_throtl_init(struct request_queue *q);
 extern void blk_throtl_exit(struct request_queue *q);
 extern int blk_throtl_bio(struct request_queue *q, struct bio **bio);
-extern void throtl_schedule_delayed_work(struct request_queue *q, unsigned long delay);
 extern void throtl_shutdown_timer_wq(struct request_queue *q);
 #else /* CONFIG_BLK_DEV_THROTTLING */
 static inline int blk_throtl_bio(struct request_queue *q, struct bio **bio)
@@ -1146,7 +1144,6 @@ static inline int blk_throtl_bio(struct request_queue *q, struct bio **bio)
 
 static inline int blk_throtl_init(struct request_queue *q) { return 0; }
 static inline int blk_throtl_exit(struct request_queue *q) { return 0; }
-static inline void throtl_schedule_delayed_work(struct request_queue *q, unsigned long delay) {}
 static inline void throtl_shutdown_timer_wq(struct request_queue *q) {}
 #endif /* CONFIG_BLK_DEV_THROTTLING */
 
index 3395cf7..b22fb0d 100644 (file)
@@ -245,7 +245,6 @@ static inline int blk_cmd_buf_len(struct request *rq)
 
 extern void blk_dump_cmd(char *buf, struct request *rq);
 extern void blk_fill_rwbs(char *rwbs, u32 rw, int bytes);
-extern void blk_fill_rwbs_rq(char *rwbs, struct request *rq);
 
 #endif /* CONFIG_EVENT_TRACING && CONFIG_BLOCK */
 
diff --git a/include/linux/caif/Kbuild b/include/linux/caif/Kbuild
new file mode 100644 (file)
index 0000000..a9cf250
--- /dev/null
@@ -0,0 +1,2 @@
+header-y += caif_socket.h
+header-y += if_caif.h
index c3011be..31d91a6 100644 (file)
@@ -123,6 +123,7 @@ struct ceph_msg_pos {
 #define SOCK_CLOSED    11 /* socket state changed to closed */
 #define OPENING         13 /* open connection w/ (possibly new) peer */
 #define DEAD            14 /* dead, about to kfree */
+#define BACKOFF         15
 
 /*
  * A single connection with another host.
@@ -160,7 +161,6 @@ struct ceph_connection {
        struct list_head out_queue;
        struct list_head out_sent;   /* sending or sent but unacked */
        u64 out_seq;                 /* last message queued for send */
-       bool out_keepalive_pending;
 
        u64 in_seq, in_seq_acked;  /* last message received, acked */
 
index ce104e3..e654fa2 100644 (file)
@@ -474,7 +474,8 @@ struct cgroup_subsys {
                        struct cgroup *old_cgrp, struct task_struct *tsk,
                        bool threadgroup);
        void (*fork)(struct cgroup_subsys *ss, struct task_struct *task);
-       void (*exit)(struct cgroup_subsys *ss, struct task_struct *task);
+       void (*exit)(struct cgroup_subsys *ss, struct cgroup *cgrp,
+                       struct cgroup *old_cgrp, struct task_struct *task);
        int (*populate)(struct cgroup_subsys *ss,
                        struct cgroup *cgrp);
        void (*post_clone)(struct cgroup_subsys *ss, struct cgroup *cgrp);
@@ -626,6 +627,7 @@ bool css_is_ancestor(struct cgroup_subsys_state *cg,
 /* Get id and depth of css */
 unsigned short css_id(struct cgroup_subsys_state *css);
 unsigned short css_depth(struct cgroup_subsys_state *css);
+struct cgroup_subsys_state *cgroup_css_from_dir(struct file *f, int id);
 
 #else /* !CONFIG_CGROUPS */
 
index ccefff0..cdbfcb8 100644 (file)
@@ -65,4 +65,8 @@ SUBSYS(net_cls)
 SUBSYS(blkio)
 #endif
 
+#ifdef CONFIG_CGROUP_PERF
+SUBSYS(perf)
+#endif
+
 /* */
index 9774fe6..7453cfd 100644 (file)
@@ -139,9 +139,9 @@ extern int update_console_cmdline(char *name, int idx, char *name_new, int idx_n
 extern void register_console(struct console *);
 extern int unregister_console(struct console *);
 extern struct console *console_drivers;
-extern void acquire_console_sem(void);
-extern int try_acquire_console_sem(void);
-extern void release_console_sem(void);
+extern void console_lock(void);
+extern int console_trylock(void);
+extern void console_unlock(void);
 extern void console_conditional_schedule(void);
 extern void console_unblank(void);
 extern struct tty_driver *console_device(int *);
index 68cd248..66900e3 100644 (file)
@@ -101,8 +101,8 @@ struct ieee_pfc {
  */
 struct dcb_app {
        __u8    selector;
-       __u32   protocol;
        __u8    priority;
+       __u16   protocol;
 };
 
 struct dcbmsg {
index 597692f..65970b8 100644 (file)
@@ -34,7 +34,10 @@ struct debug_obj {
 
 /**
  * struct debug_obj_descr - object type specific debug description structure
+ *
  * @name:              name of the object typee
+ * @debug_hint:                function returning address, which have associated
+ *                     kernel symbol, to allow identify the object
  * @fixup_init:                fixup function, which is called when the init check
  *                     fails
  * @fixup_activate:    fixup function, which is called when the activate check
@@ -46,7 +49,7 @@ struct debug_obj {
  */
 struct debug_obj_descr {
        const char              *name;
-
+       void *(*debug_hint)     (void *addr);
        int (*fixup_init)       (void *addr, enum debug_obj_state state);
        int (*fixup_activate)   (void *addr, enum debug_obj_state state);
        int (*fixup_destroy)    (void *addr, enum debug_obj_state state);
index 1bf5cf0..ca5d252 100644 (file)
@@ -128,9 +128,7 @@ struct device_driver {
 
        bool suppress_bind_attrs;       /* disables bind/unbind via sysfs */
 
-#if defined(CONFIG_OF)
        const struct of_device_id       *of_match_table;
-#endif
 
        int (*probe) (struct device *dev);
        int (*remove) (struct device *dev);
@@ -441,9 +439,8 @@ struct device {
                                             override */
        /* arch specific additions */
        struct dev_archdata     archdata;
-#ifdef CONFIG_OF
-       struct device_node      *of_node;
-#endif
+
+       struct device_node      *of_node; /* associated device tree node */
 
        dev_t                   devt;   /* dev_t, creates the sysfs "dev" */
 
index 2802898..33a42f2 100644 (file)
@@ -8,6 +8,9 @@ struct inode;
 struct super_block;
 struct vfsmount;
 
+/* limit the handle size to NFSv4 handle size now */
+#define MAX_HANDLE_SZ 128
+
 /*
  * The fileid_type identifies how the file within the filesystem is encoded.
  * In theory this is freely set and parsed by the filesystem, but we try to
@@ -121,8 +124,10 @@ struct fid {
  *    set, the encode_fh() should store sufficient information so that a good
  *    attempt can be made to find not only the file but also it's place in the
  *    filesystem.   This typically means storing a reference to de->d_parent in
- *    the filehandle fragment.  encode_fh() should return the number of bytes
- *    stored or a negative error code such as %-ENOSPC
+ *    the filehandle fragment.  encode_fh() should return the fileid_type on
+ *    success and on error returns 255 (if the space needed to encode fh is
+ *    greater than @max_len*4 bytes). On error @max_len contains the minimum
+ *    size(in 4 byte unit) needed to encode the file handle.
  *
  * fh_to_dentry:
  *    @fh_to_dentry is given a &struct super_block (@sb) and a file handle
index a562fa5..f550f89 100644 (file)
@@ -46,6 +46,7 @@
                                            unlinking file.  */
 #define AT_SYMLINK_FOLLOW      0x400   /* Follow symbolic links.  */
 #define AT_NO_AUTOMOUNT                0x800   /* Suppress terminal automount traversal */
+#define AT_EMPTY_PATH          0x1000  /* Allow empty relative pathname */
 
 #ifdef __KERNEL__
 
index e85baeb..21a7995 100644 (file)
@@ -29,6 +29,8 @@ static inline void fput_light(struct file *file, int fput_needed)
 
 extern struct file *fget(unsigned int fd);
 extern struct file *fget_light(unsigned int fd, int *fput_needed);
+extern struct file *fget_raw(unsigned int fd);
+extern struct file *fget_raw_light(unsigned int fd, int *fput_needed);
 extern void set_close_on_exec(unsigned int fd, int flag);
 extern void put_filp(struct file *);
 extern int alloc_fd(unsigned start, unsigned flags);
index da7e52b..1effc8b 100644 (file)
@@ -109,7 +109,7 @@ static inline void freezer_count(void)
 }
 
 /*
- * Check if the task should be counted as freezeable by the freezer
+ * Check if the task should be counted as freezable by the freezer
  */
 static inline int freezer_should_skip(struct task_struct *p)
 {
index 32b38cd..13df14e 100644 (file)
@@ -102,6 +102,9 @@ struct inodes_stat_t {
 /* File is huge (eg. /dev/kmem): treat loff_t as unsigned */
 #define FMODE_UNSIGNED_OFFSET  ((__force fmode_t)0x2000)
 
+/* File is opened with O_PATH; almost nothing can be done with it */
+#define FMODE_PATH             ((__force fmode_t)0x4000)
+
 /* File was opened by fanotify and shouldn't generate fanotify events */
 #define FMODE_NONOTIFY         ((__force fmode_t)0x1000000)
 
@@ -649,6 +652,7 @@ struct address_space {
        spinlock_t              private_lock;   /* for use by the address_space */
        struct list_head        private_list;   /* ditto */
        struct address_space    *assoc_mapping; /* ditto */
+       struct mutex            unmap_mutex;    /* to protect unmapping */
 } __attribute__((aligned(sizeof(long))));
        /*
         * On most architectures that alignment is already the case; but
@@ -977,6 +981,13 @@ struct file {
 #endif
 };
 
+struct file_handle {
+       __u32 handle_bytes;
+       int handle_type;
+       /* file identifier */
+       unsigned char f_handle[0];
+};
+
 #define get_file(x)    atomic_long_inc(&(x)->f_count)
 #define fput_atomic(x) atomic_long_add_unless(&(x)->f_count, -1, 1)
 #define file_count(x)  atomic_long_read(&(x)->f_count)
@@ -1400,6 +1411,7 @@ struct super_block {
        wait_queue_head_t       s_wait_unfrozen;
 
        char s_id[32];                          /* Informational name */
+       u8 s_uuid[16];                          /* UUID */
 
        void                    *s_fs_info;     /* Filesystem private info */
        fmode_t                 s_mode;
@@ -1873,6 +1885,8 @@ extern void drop_collected_mounts(struct vfsmount *);
 extern int iterate_mounts(int (*)(struct vfsmount *, void *), void *,
                          struct vfsmount *);
 extern int vfs_statfs(struct path *, struct kstatfs *);
+extern int user_statfs(const char __user *, struct kstatfs *);
+extern int fd_statfs(int, struct kstatfs *);
 extern int statfs_by_dentry(struct dentry *, struct kstatfs *);
 extern int freeze_super(struct super_block *super);
 extern int thaw_super(struct super_block *super);
@@ -1989,6 +2003,8 @@ extern int do_fallocate(struct file *file, int mode, loff_t offset,
 extern long do_sys_open(int dfd, const char __user *filename, int flags,
                        int mode);
 extern struct file *filp_open(const char *, int, int);
+extern struct file *file_open_root(struct dentry *, struct vfsmount *,
+                                  const char *, int);
 extern struct file * dentry_open(struct dentry *, struct vfsmount *, int,
                                 const struct cred *);
 extern int filp_close(struct file *, fl_owner_t id);
@@ -2139,7 +2155,7 @@ extern void check_disk_size_change(struct gendisk *disk,
                                   struct block_device *bdev);
 extern int revalidate_disk(struct gendisk *);
 extern int check_disk_change(struct block_device *);
-extern int __invalidate_device(struct block_device *);
+extern int __invalidate_device(struct block_device *, bool);
 extern int invalidate_partition(struct gendisk *, int);
 #endif
 unsigned long invalidate_mapping_pages(struct address_space *mapping,
@@ -2204,10 +2220,6 @@ extern struct file *create_read_pipe(struct file *f, int flags);
 extern struct file *create_write_pipe(int flags);
 extern void free_write_pipe(struct file *);
 
-extern struct file *do_filp_open(int dfd, const char *pathname,
-               int open_flag, int mode, int acc_mode);
-extern int may_open(struct path *, int, int);
-
 extern int kernel_read(struct file *, loff_t, char *, unsigned long);
 extern struct file * open_exec(const char *);
  
@@ -2225,6 +2237,7 @@ extern loff_t vfs_llseek(struct file *file, loff_t offset, int origin);
 
 extern int inode_init_always(struct super_block *, struct inode *);
 extern void inode_init_once(struct inode *);
+extern void address_space_init_once(struct address_space *mapping);
 extern void ihold(struct inode * inode);
 extern void iput(struct inode *);
 extern struct inode * igrab(struct inode *);
@@ -2555,9 +2568,12 @@ int proc_nr_inodes(struct ctl_table *table, int write,
                   void __user *buffer, size_t *lenp, loff_t *ppos);
 int __init get_filesystem_list(char *buf);
 
+#define __FMODE_EXEC           ((__force int) FMODE_EXEC)
+#define __FMODE_NONOTIFY       ((__force int) FMODE_NONOTIFY)
+
 #define ACC_MODE(x) ("\004\002\006\006"[(x)&O_ACCMODE])
 #define OPEN_FMODE(flag) ((__force fmode_t)(((flag + 1) & O_ACCMODE) | \
-                                           (flag & FMODE_NONOTIFY)))
+                                           (flag & __FMODE_NONOTIFY)))
 
 #endif /* __KERNEL__ */
 #endif /* _LINUX_FS_H */
index dcd6a7c..ca29e03 100644 (file)
@@ -428,6 +428,7 @@ extern void unregister_ftrace_graph(void);
 
 extern void ftrace_graph_init_task(struct task_struct *t);
 extern void ftrace_graph_exit_task(struct task_struct *t);
+extern void ftrace_graph_init_idle_task(struct task_struct *t, int cpu);
 
 static inline int task_curr_ret_stack(struct task_struct *t)
 {
@@ -451,6 +452,7 @@ static inline void unpause_graph_tracing(void)
 
 static inline void ftrace_graph_init_task(struct task_struct *t) { }
 static inline void ftrace_graph_exit_task(struct task_struct *t) { }
+static inline void ftrace_graph_init_idle_task(struct task_struct *t, int cpu) { }
 
 static inline int register_ftrace_graph(trace_func_graph_ret_t retfunc,
                          trace_func_graph_ent_t entryfunc)
index 47e3997..22b32af 100644 (file)
@@ -37,7 +37,6 @@ struct trace_entry {
        unsigned char           flags;
        unsigned char           preempt_count;
        int                     pid;
-       int                     lock_depth;
 };
 
 #define FTRACE_MAX_EVENT                                               \
@@ -208,7 +207,6 @@ struct ftrace_event_call {
 
 #define PERF_MAX_TRACE_SIZE    2048
 
-#define MAX_FILTER_PRED                32
 #define MAX_FILTER_STR_VAL     256     /* Should handle KSYM_SYMBOL_LEN */
 
 extern void destroy_preds(struct ftrace_event_call *call);
index 0b84c61..dca3176 100644 (file)
@@ -332,16 +332,19 @@ alloc_pages(gfp_t gfp_mask, unsigned int order)
        return alloc_pages_current(gfp_mask, order);
 }
 extern struct page *alloc_pages_vma(gfp_t gfp_mask, int order,
-                       struct vm_area_struct *vma, unsigned long addr);
+                       struct vm_area_struct *vma, unsigned long addr,
+                       int node);
 #else
 #define alloc_pages(gfp_mask, order) \
                alloc_pages_node(numa_node_id(), gfp_mask, order)
-#define alloc_pages_vma(gfp_mask, order, vma, addr)    \
+#define alloc_pages_vma(gfp_mask, order, vma, addr, node)      \
        alloc_pages(gfp_mask, order)
 #endif
 #define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)
-#define alloc_page_vma(gfp_mask, vma, addr)    \
-       alloc_pages_vma(gfp_mask, 0, vma, addr)
+#define alloc_page_vma(gfp_mask, vma, addr)                    \
+       alloc_pages_vma(gfp_mask, 0, vma, addr, numa_node_id())
+#define alloc_page_vma_node(gfp_mask, vma, addr, node)         \
+       alloc_pages_vma(gfp_mask, 0, vma, addr, node)
 
 extern unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order);
 extern unsigned long get_zeroed_page(gfp_t gfp_mask);
index f376ddc..62f500c 100644 (file)
@@ -54,11 +54,13 @@ enum hrtimer_restart {
  * 0x00                inactive
  * 0x01                enqueued into rbtree
  * 0x02                callback function running
+ * 0x04                timer is migrated to another cpu
  *
  * Special cases:
  * 0x03                callback function running and enqueued
  *             (was requeued on another CPU)
- * 0x09                timer was migrated on CPU hotunplug
+ * 0x05                timer was migrated on CPU hotunplug
+ *
  * The "callback function running and enqueued" status is only possible on
  * SMP. It happens for example when a posix timer expired and the callback
  * queued a signal. Between dropping the lock which protects the posix timer
@@ -67,8 +69,11 @@ enum hrtimer_restart {
  * as otherwise the timer could be removed before the softirq code finishes the
  * the handling of the timer.
  *
- * The HRTIMER_STATE_ENQUEUED bit is always or'ed to the current state to
- * preserve the HRTIMER_STATE_CALLBACK bit in the above scenario.
+ * The HRTIMER_STATE_ENQUEUED bit is always or'ed to the current state
+ * to preserve the HRTIMER_STATE_CALLBACK in the above scenario. This
+ * also affects HRTIMER_STATE_MIGRATE where the preservation is not
+ * necessary. HRTIMER_STATE_MIGRATE is cleared after the timer is
+ * enqueued on the new cpu.
  *
  * All state transitions are protected by cpu_base->lock.
  */
@@ -148,7 +153,12 @@ struct hrtimer_clock_base {
 #endif
 };
 
-#define HRTIMER_MAX_CLOCK_BASES 2
+enum  hrtimer_base_type {
+       HRTIMER_BASE_REALTIME,
+       HRTIMER_BASE_MONOTONIC,
+       HRTIMER_BASE_BOOTTIME,
+       HRTIMER_MAX_CLOCK_BASES,
+};
 
 /*
  * struct hrtimer_cpu_base - the per cpu clock bases
@@ -308,6 +318,7 @@ static inline int hrtimer_is_hres_active(struct hrtimer *timer)
 
 extern ktime_t ktime_get(void);
 extern ktime_t ktime_get_real(void);
+extern ktime_t ktime_get_boottime(void);
 
 
 DECLARE_PER_CPU(struct tick_device, tick_cpu_device);
@@ -370,8 +381,9 @@ extern int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp);
 extern ktime_t hrtimer_get_next_event(void);
 
 /*
- * A timer is active, when it is enqueued into the rbtree or the callback
- * function is running.
+ * A timer is active, when it is enqueued into the rbtree or the
+ * callback function is running or it's in the state of being migrated
+ * to another cpu.
  */
 static inline int hrtimer_active(const struct hrtimer *timer)
 {
index 8e6c8c4..df29c8f 100644 (file)
@@ -57,7 +57,8 @@ extern pmd_t *page_check_address_pmd(struct page *page,
          (transparent_hugepage_flags &                                 \
           (1<<TRANSPARENT_HUGEPAGE_REQ_MADV_FLAG) &&                   \
           ((__vma)->vm_flags & VM_HUGEPAGE))) &&                       \
-        !((__vma)->vm_flags & VM_NOHUGEPAGE))
+        !((__vma)->vm_flags & VM_NOHUGEPAGE) &&                        \
+        !is_vma_temporary_stack(__vma))
 #define transparent_hugepage_defrag(__vma)                             \
        ((transparent_hugepage_flags &                                  \
          (1<<TRANSPARENT_HUGEPAGE_DEFRAG_FLAG)) ||                     \
index 903576d..06a8d9c 100644 (file)
@@ -258,9 +258,7 @@ struct i2c_board_info {
        unsigned short  addr;
        void            *platform_data;
        struct dev_archdata     *archdata;
-#ifdef CONFIG_OF
        struct device_node *of_node;
-#endif
        int             irq;
 };
 
index e470d38..05e0328 100644 (file)
@@ -12,8 +12,6 @@
  * @cs_en:     pointer to the cs enable function
  * @cs_dis:    pointer to the cs disable function
  * @irq_read_val:    pointer to read the pen irq value function
- * @x_max_res: xmax resolution
- * @y_max_res: ymax resolution
  * @touch_x_max: touch x max
  * @touch_y_max: touch y max
  * @cs_pin: chip select pin
@@ -29,8 +27,6 @@ struct bu21013_platform_device {
        int (*cs_en)(int reset_pin);
        int (*cs_dis)(int reset_pin);
        int (*irq_read_val)(void);
-       int x_max_res;
-       int y_max_res;
        int touch_x_max;
        int touch_y_max;
        unsigned int cs_pin;
index 6974746..fe7c4b9 100644 (file)
@@ -4,8 +4,8 @@
 #include <linux/types.h>
 #include <linux/input.h>
 
-#define MATRIX_MAX_ROWS                16
-#define MATRIX_MAX_COLS                16
+#define MATRIX_MAX_ROWS                32
+#define MATRIX_MAX_COLS                32
 
 #define KEY(row, col, val)     ((((row) & (MATRIX_MAX_ROWS - 1)) << 24) |\
                                 (((col) & (MATRIX_MAX_COLS - 1)) << 16) |\
index 55e0d42..59b72ca 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/smp.h>
 #include <linux/percpu.h>
 #include <linux/hrtimer.h>
+#include <linux/kref.h>
+#include <linux/workqueue.h>
 
 #include <asm/atomic.h>
 #include <asm/ptrace.h>
@@ -55,7 +57,8 @@
  *                Used by threaded interrupts which need to keep the
  *                irq line disabled until the threaded handler has been run.
  * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend
- *
+ * IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set
+ * IRQF_NO_THREAD - Interrupt cannot be threaded
  */
 #define IRQF_DISABLED          0x00000020
 #define IRQF_SAMPLE_RANDOM     0x00000040
 #define IRQF_IRQPOLL           0x00001000
 #define IRQF_ONESHOT           0x00002000
 #define IRQF_NO_SUSPEND                0x00004000
+#define IRQF_FORCE_RESUME      0x00008000
+#define IRQF_NO_THREAD         0x00010000
 
-#define IRQF_TIMER             (__IRQF_TIMER | IRQF_NO_SUSPEND)
-
-/*
- * Bits used by threaded handlers:
- * IRQTF_RUNTHREAD - signals that the interrupt handler thread should run
- * IRQTF_DIED      - handler thread died
- * IRQTF_WARNED    - warning "IRQ_WAKE_THREAD w/o thread_fn" has been printed
- * IRQTF_AFFINITY  - irq thread is requested to adjust affinity
- */
-enum {
-       IRQTF_RUNTHREAD,
-       IRQTF_DIED,
-       IRQTF_WARNED,
-       IRQTF_AFFINITY,
-};
+#define IRQF_TIMER             (__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD)
 
 /*
  * These values can be returned by request_any_context_irq() and
@@ -110,6 +101,7 @@ typedef irqreturn_t (*irq_handler_t)(int, void *);
  * @thread_fn: interupt handler function for threaded interrupts
  * @thread:    thread pointer for threaded interrupts
  * @thread_flags:      flags related to @thread
+ * @thread_mask:       bitmask for keeping track of @thread activity
  */
 struct irqaction {
        irq_handler_t handler;
@@ -120,6 +112,7 @@ struct irqaction {
        irq_handler_t thread_fn;
        struct task_struct *thread;
        unsigned long thread_flags;
+       unsigned long thread_mask;
        const char *name;
        struct proc_dir_entry *dir;
 } ____cacheline_internodealigned_in_smp;
@@ -240,6 +233,35 @@ extern int irq_can_set_affinity(unsigned int irq);
 extern int irq_select_affinity(unsigned int irq);
 
 extern int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m);
+
+/**
+ * struct irq_affinity_notify - context for notification of IRQ affinity changes
+ * @irq:               Interrupt to which notification applies
+ * @kref:              Reference count, for internal use
+ * @work:              Work item, for internal use
+ * @notify:            Function to be called on change.  This will be
+ *                     called in process context.
+ * @release:           Function to be called on release.  This will be
+ *                     called in process context.  Once registered, the
+ *                     structure must only be freed when this function is
+ *                     called or later.
+ */
+struct irq_affinity_notify {
+       unsigned int irq;
+       struct kref kref;
+       struct work_struct work;
+       void (*notify)(struct irq_affinity_notify *, const cpumask_t *mask);
+       void (*release)(struct kref *ref);
+};
+
+extern int
+irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify);
+
+static inline void irq_run_affinity_notifiers(void)
+{
+       flush_scheduled_work();
+}
+
 #else /* CONFIG_SMP */
 
 static inline int irq_set_affinity(unsigned int irq, const struct cpumask *m)
@@ -255,7 +277,7 @@ static inline int irq_can_set_affinity(unsigned int irq)
 static inline int irq_select_affinity(unsigned int irq)  { return 0; }
 
 static inline int irq_set_affinity_hint(unsigned int irq,
-                                        const struct cpumask *m)
+                                       const struct cpumask *m)
 {
        return -EINVAL;
 }
@@ -314,16 +336,24 @@ static inline void enable_irq_lockdep_irqrestore(unsigned int irq, unsigned long
 }
 
 /* IRQ wakeup (PM) control: */
-extern int set_irq_wake(unsigned int irq, unsigned int on);
+extern int irq_set_irq_wake(unsigned int irq, unsigned int on);
+
+#ifndef CONFIG_GENERIC_HARDIRQS_NO_COMPAT
+/* Please do not use: Use the replacement functions instead */
+static inline int set_irq_wake(unsigned int irq, unsigned int on)
+{
+       return irq_set_irq_wake(irq, on);
+}
+#endif
 
 static inline int enable_irq_wake(unsigned int irq)
 {
-       return set_irq_wake(irq, 1);
+       return irq_set_irq_wake(irq, 1);
 }
 
 static inline int disable_irq_wake(unsigned int irq)
 {
-       return set_irq_wake(irq, 0);
+       return irq_set_irq_wake(irq, 0);
 }
 
 #else /* !CONFIG_GENERIC_HARDIRQS */
@@ -353,6 +383,13 @@ static inline int disable_irq_wake(unsigned int irq)
 }
 #endif /* CONFIG_GENERIC_HARDIRQS */
 
+
+#ifdef CONFIG_IRQ_FORCED_THREADING
+extern bool force_irqthreads;
+#else
+#define force_irqthreads       (0)
+#endif
+
 #ifndef __ARCH_SET_SOFTIRQ_PENDING
 #define set_softirq_pending(x) (local_softirq_pending() = (x))
 #define or_softirq_pending(x)  (local_softirq_pending() |= (x))
@@ -426,6 +463,13 @@ extern void raise_softirq(unsigned int nr);
  */
 DECLARE_PER_CPU(struct list_head [NR_SOFTIRQS], softirq_work_list);
 
+DECLARE_PER_CPU(struct task_struct *, ksoftirqd);
+
+static inline struct task_struct *this_cpu_ksoftirqd(void)
+{
+       return this_cpu_read(ksoftirqd);
+}
+
 /* Try to send a softirq to a remote cpu.  If this cannot be done, the
  * work will be queued to the local cpu.
  */
@@ -645,6 +689,7 @@ static inline void init_irq_proc(void)
 
 struct seq_file;
 int show_interrupts(struct seq_file *p, void *v);
+int arch_show_interrupts(struct seq_file *p, int prec);
 
 extern int early_irq_init(void);
 extern int arch_probe_nr_irqs(void);
index abde252..1d3577f 100644 (file)
 #include <asm/irq_regs.h>
 
 struct irq_desc;
+struct irq_data;
 typedef        void (*irq_flow_handler_t)(unsigned int irq,
                                            struct irq_desc *desc);
-
+typedef        void (*irq_preflow_handler_t)(struct irq_data *data);
 
 /*
  * IRQ line status.
  *
- * Bits 0-7 are reserved for the IRQF_* bits in linux/interrupt.h
+ * Bits 0-7 are the same as the IRQF_* bits in linux/interrupt.h
+ *
+ * IRQ_TYPE_NONE               - default, unspecified type
+ * IRQ_TYPE_EDGE_RISING                - rising edge triggered
+ * IRQ_TYPE_EDGE_FALLING       - falling edge triggered
+ * IRQ_TYPE_EDGE_BOTH          - rising and falling edge triggered
+ * IRQ_TYPE_LEVEL_HIGH         - high level triggered
+ * IRQ_TYPE_LEVEL_LOW          - low level triggered
+ * IRQ_TYPE_LEVEL_MASK         - Mask to filter out the level bits
+ * IRQ_TYPE_SENSE_MASK         - Mask for all the above bits
+ * IRQ_TYPE_PROBE              - Special flag for probing in progress
+ *
+ * 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()
+ * 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_NOAUTOEN                        - Interrupt is not automatically enabled in
+ *                               request/setup_irq()
+ * IRQ_NO_BALANCING            - Interrupt cannot be balanced (affinity set)
+ * IRQ_MOVE_PCNTXT             - Interrupt can be migrated from process context
+ * IRQ_NESTED_TRHEAD           - Interrupt nests into another thread
+ *
+ * Deprecated bits. They are kept updated as long as
+ * CONFIG_GENERIC_HARDIRQS_NO_COMPAT is not set. Will go away soon. These bits
+ * are internal state of the core code and if you really need to acces
+ * them then talk to the genirq maintainer instead of hacking
+ * something weird.
  *
- * IRQ types
  */
-#define IRQ_TYPE_NONE          0x00000000      /* Default, unspecified type */
-#define IRQ_TYPE_EDGE_RISING   0x00000001      /* Edge rising type */
-#define IRQ_TYPE_EDGE_FALLING  0x00000002      /* Edge falling type */
-#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
-#define IRQ_TYPE_LEVEL_HIGH    0x00000004      /* Level high type */
-#define IRQ_TYPE_LEVEL_LOW     0x00000008      /* Level low type */
-#define IRQ_TYPE_SENSE_MASK    0x0000000f      /* Mask of the above */
-#define IRQ_TYPE_PROBE         0x00000010      /* Probing in progress */
-
-/* Internal flags */
-#define IRQ_INPROGRESS         0x00000100      /* IRQ handler active - do not enter! */
-#define IRQ_DISABLED           0x00000200      /* IRQ disabled - do not enter! */
-#define IRQ_PENDING            0x00000400      /* IRQ pending - replay on enable */
-#define IRQ_REPLAY             0x00000800      /* IRQ has been replayed but not acked yet */
-#define IRQ_AUTODETECT         0x00001000      /* IRQ is being autodetected */
-#define IRQ_WAITING            0x00002000      /* IRQ not yet seen - for autodetection */
-#define IRQ_LEVEL              0x00004000      /* IRQ level triggered */
-#define IRQ_MASKED             0x00008000      /* IRQ masked - shouldn't be seen again */
-#define IRQ_PER_CPU            0x00010000      /* IRQ is per CPU */
-#define IRQ_NOPROBE            0x00020000      /* IRQ is not valid for probing */
-#define IRQ_NOREQUEST          0x00040000      /* IRQ cannot be requested */
-#define IRQ_NOAUTOEN           0x00080000      /* IRQ will not be enabled on request irq */
-#define IRQ_WAKEUP             0x00100000      /* IRQ triggers system wakeup */
-#define IRQ_MOVE_PENDING       0x00200000      /* need to re-target IRQ destination */
-#define IRQ_NO_BALANCING       0x00400000      /* IRQ is excluded from balancing */
-#define IRQ_SPURIOUS_DISABLED  0x00800000      /* IRQ was disabled by the spurious trap */
-#define IRQ_MOVE_PCNTXT                0x01000000      /* IRQ migration from process context */
-#define IRQ_AFFINITY_SET       0x02000000      /* IRQ affinity was set from userspace*/
-#define IRQ_SUSPENDED          0x04000000      /* IRQ has gone through suspend sequence */
-#define IRQ_ONESHOT            0x08000000      /* IRQ is not unmasked after hardirq */
-#define IRQ_NESTED_THREAD      0x10000000      /* IRQ is nested into another, no own handler thread */
+enum {
+       IRQ_TYPE_NONE           = 0x00000000,
+       IRQ_TYPE_EDGE_RISING    = 0x00000001,
+       IRQ_TYPE_EDGE_FALLING   = 0x00000002,
+       IRQ_TYPE_EDGE_BOTH      = (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING),
+       IRQ_TYPE_LEVEL_HIGH     = 0x00000004,
+       IRQ_TYPE_LEVEL_LOW      = 0x00000008,
+       IRQ_TYPE_LEVEL_MASK     = (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH),
+       IRQ_TYPE_SENSE_MASK     = 0x0000000f,
+
+       IRQ_TYPE_PROBE          = 0x00000010,
+
+       IRQ_LEVEL               = (1 <<  8),
+       IRQ_PER_CPU             = (1 <<  9),
+       IRQ_NOPROBE             = (1 << 10),
+       IRQ_NOREQUEST           = (1 << 11),
+       IRQ_NOAUTOEN            = (1 << 12),
+       IRQ_NO_BALANCING        = (1 << 13),
+       IRQ_MOVE_PCNTXT         = (1 << 14),
+       IRQ_NESTED_THREAD       = (1 << 15),
+
+#ifndef CONFIG_GENERIC_HARDIRQS_NO_COMPAT
+       IRQ_INPROGRESS          = (1 << 16),
+       IRQ_REPLAY              = (1 << 17),
+       IRQ_WAITING             = (1 << 18),
+       IRQ_DISABLED            = (1 << 19),
+       IRQ_PENDING             = (1 << 20),
+       IRQ_MASKED              = (1 << 21),
+       IRQ_MOVE_PENDING        = (1 << 22),
+       IRQ_AFFINITY_SET        = (1 << 23),
+       IRQ_WAKEUP              = (1 << 24),
+#endif
+};
 
 #define IRQF_MODIFY_MASK       \
        (IRQ_TYPE_SENSE_MASK | IRQ_NOPROBE | IRQ_NOREQUEST | \
-        IRQ_NOAUTOEN | IRQ_MOVE_PCNTXT | IRQ_LEVEL)
+        IRQ_NOAUTOEN | IRQ_MOVE_PCNTXT | IRQ_LEVEL | IRQ_NO_BALANCING | \
+        IRQ_PER_CPU | IRQ_NESTED_THREAD)
 
-#ifdef CONFIG_IRQ_PER_CPU
-# define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU)
-# define IRQ_NO_BALANCING_MASK (IRQ_PER_CPU | IRQ_NO_BALANCING)
-#else
-# define CHECK_IRQ_PER_CPU(var) 0
-# define IRQ_NO_BALANCING_MASK IRQ_NO_BALANCING
-#endif
+#define IRQ_NO_BALANCING_MASK  (IRQ_PER_CPU | IRQ_NO_BALANCING)
+
+static inline __deprecated bool CHECK_IRQ_PER_CPU(unsigned int status)
+{
+       return status & IRQ_PER_CPU;
+}
+
+/*
+ * Return value for chip->irq_set_affinity()
+ *
+ * IRQ_SET_MASK_OK     - OK, core updates irq_data.affinity
+ * IRQ_SET_MASK_NOCPY  - OK, chip did update irq_data.affinity
+ */
+enum {
+       IRQ_SET_MASK_OK = 0,
+       IRQ_SET_MASK_OK_NOCOPY,
+};
 
 struct msi_desc;
 
@@ -90,6 +134,8 @@ struct msi_desc;
  * struct irq_data - per irq and irq chip data passed down to chip functions
  * @irq:               interrupt number
  * @node:              node index useful for balancing
+ * @state_use_accessor: status information for irq chip functions.
+ *                     Use accessor functions to deal with it
  * @chip:              low level interrupt hardware access
  * @handler_data:      per-IRQ data for the irq_chip methods
  * @chip_data:         platform-specific per-chip private data for the chip
@@ -104,6 +150,7 @@ struct msi_desc;
 struct irq_data {
        unsigned int            irq;
        unsigned int            node;
+       unsigned int            state_use_accessors;
        struct irq_chip         *chip;
        void                    *handler_data;
        void                    *chip_data;
@@ -113,6 +160,80 @@ struct irq_data {
 #endif
 };
 
+/*
+ * Bit masks for irq_data.state
+ *
+ * IRQD_TRIGGER_MASK           - Mask for the trigger type bits
+ * IRQD_SETAFFINITY_PENDING    - Affinity setting is pending
+ * IRQD_NO_BALANCING           - Balancing disabled for this IRQ
+ * IRQD_PER_CPU                        - Interrupt is per cpu
+ * IRQD_AFFINITY_SET           - Interrupt affinity was set
+ * IRQD_LEVEL                  - Interrupt is level triggered
+ * IRQD_WAKEUP_STATE           - Interrupt is configured for wakeup
+ *                               from suspend
+ * IRDQ_MOVE_PCNTXT            - Interrupt can be moved in process
+ *                               context
+ */
+enum {
+       IRQD_TRIGGER_MASK               = 0xf,
+       IRQD_SETAFFINITY_PENDING        = (1 <<  8),
+       IRQD_NO_BALANCING               = (1 << 10),
+       IRQD_PER_CPU                    = (1 << 11),
+       IRQD_AFFINITY_SET               = (1 << 12),
+       IRQD_LEVEL                      = (1 << 13),
+       IRQD_WAKEUP_STATE               = (1 << 14),
+       IRQD_MOVE_PCNTXT                = (1 << 15),
+};
+
+static inline bool irqd_is_setaffinity_pending(struct irq_data *d)
+{
+       return d->state_use_accessors & IRQD_SETAFFINITY_PENDING;
+}
+
+static inline bool irqd_is_per_cpu(struct irq_data *d)
+{
+       return d->state_use_accessors & IRQD_PER_CPU;
+}
+
+static inline bool irqd_can_balance(struct irq_data *d)
+{
+       return !(d->state_use_accessors & (IRQD_PER_CPU | IRQD_NO_BALANCING));
+}
+
+static inline bool irqd_affinity_was_set(struct irq_data *d)
+{
+       return d->state_use_accessors & IRQD_AFFINITY_SET;
+}
+
+static inline u32 irqd_get_trigger_type(struct irq_data *d)
+{
+       return d->state_use_accessors & IRQD_TRIGGER_MASK;
+}
+
+/*
+ * Must only be called inside irq_chip.irq_set_type() functions.
+ */
+static inline void irqd_set_trigger_type(struct irq_data *d, u32 type)
+{
+       d->state_use_accessors &= ~IRQD_TRIGGER_MASK;
+       d->state_use_accessors |= type & IRQD_TRIGGER_MASK;
+}
+
+static inline bool irqd_is_level_type(struct irq_data *d)
+{
+       return d->state_use_accessors & IRQD_LEVEL;
+}
+
+static inline bool irqd_is_wakeup_set(struct irq_data *d)
+{
+       return d->state_use_accessors & IRQD_WAKEUP_STATE;
+}
+
+static inline bool irqd_can_move_in_process_context(struct irq_data *d)
+{
+       return d->state_use_accessors & IRQD_MOVE_PCNTXT;
+}
+
 /**
  * struct irq_chip - hardware interrupt chip descriptor
  *
@@ -149,6 +270,7 @@ struct irq_data {
  * @irq_set_wake:      enable/disable power-management wake-on of an IRQ
  * @irq_bus_lock:      function to lock access to slow bus (i2c) chips
  * @irq_bus_sync_unlock:function to sync and unlock slow bus (i2c) chips
+ * @flags:             chip specific flags
  *
  * @release:           release function solely used by UML
  */
@@ -195,12 +317,27 @@ struct irq_chip {
        void            (*irq_bus_lock)(struct irq_data *data);
        void            (*irq_bus_sync_unlock)(struct irq_data *data);
 
+       unsigned long   flags;
+
        /* Currently used only by UML, might disappear one day.*/
 #ifdef CONFIG_IRQ_RELEASE_METHOD
        void            (*release)(unsigned int irq, void *dev_id);
 #endif
 };
 
+/*
+ * irq_chip specific flags
+ *
+ * IRQCHIP_SET_TYPE_MASKED:    Mask before calling chip.irq_set_type()
+ * IRQCHIP_EOI_IF_HANDLED:     Only issue irq_eoi() when irq was handled
+ * IRQCHIP_MASK_ON_SUSPEND:    Mask non wake irqs in the suspend path
+ */
+enum {
+       IRQCHIP_SET_TYPE_MASKED         = (1 <<  0),
+       IRQCHIP_EOI_IF_HANDLED          = (1 <<  1),
+       IRQCHIP_MASK_ON_SUSPEND         = (1 <<  2),
+};
+
 /* This include will go away once we isolated irq_desc usage to core code */
 #include <linux/irqdesc.h>
 
@@ -217,7 +354,7 @@ struct irq_chip {
 # define ARCH_IRQ_INIT_FLAGS   0
 #endif
 
-#define IRQ_DEFAULT_INIT_FLAGS (IRQ_DISABLED | ARCH_IRQ_INIT_FLAGS)
+#define IRQ_DEFAULT_INIT_FLAGS ARCH_IRQ_INIT_FLAGS
 
 struct irqaction;
 extern int setup_irq(unsigned int irq, struct irqaction *new);
@@ -228,9 +365,13 @@ extern void remove_irq(unsigned int irq, struct irqaction *act);
 #if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_PENDING_IRQ)
 void move_native_irq(int irq);
 void move_masked_irq(int irq);
+void irq_move_irq(struct irq_data *data);
+void irq_move_masked_irq(struct irq_data *data);
 #else
 static inline void move_native_irq(int irq) { }
 static inline void move_masked_irq(int irq) { }
+static inline void irq_move_irq(struct irq_data *data) { }
+static inline void irq_move_masked_irq(struct irq_data *data) { }
 #endif
 
 extern int no_irq_affinity;
@@ -266,23 +407,23 @@ extern struct irq_chip no_irq_chip;
 extern struct irq_chip dummy_irq_chip;
 
 extern void
-set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip,
-                        irq_flow_handler_t handle);
-extern void
-set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
+irq_set_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
                              irq_flow_handler_t handle, const char *name);
 
+static inline void irq_set_chip_and_handler(unsigned int irq, struct irq_chip *chip,
+                                           irq_flow_handler_t handle)
+{
+       irq_set_chip_and_handler_name(irq, chip, handle, NULL);
+}
+
 extern void
-__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
+__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
                  const char *name);
 
-/*
- * Set a highlevel flow handler for a given IRQ:
- */
 static inline void
-set_irq_handler(unsigned int irq, irq_flow_handler_t handle)
+irq_set_handler(unsigned int irq, irq_flow_handler_t handle)
 {
-       __set_irq_handler(irq, handle, 0, NULL);
+       __irq_set_handler(irq, handle, 0, NULL);
 }
 
 /*
@@ -291,14 +432,11 @@ set_irq_handler(unsigned int irq, irq_flow_handler_t handle)
  *  IRQ_NOREQUEST and IRQ_NOPROBE)
  */
 static inline void
-set_irq_chained_handler(unsigned int irq,
-                       irq_flow_handler_t handle)
+irq_set_chained_handler(unsigned int irq, irq_flow_handler_t handle)
 {
-       __set_irq_handler(irq, handle, 1, NULL);
+       __irq_set_handler(irq, handle, 1, NULL);
 }
 
-extern void set_irq_nested_thread(unsigned int irq, int nest);
-
 void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set);
 
 static inline void irq_set_status_flags(unsigned int irq, unsigned long set)
@@ -311,16 +449,24 @@ static inline void irq_clear_status_flags(unsigned int irq, unsigned long clr)
        irq_modify_status(irq, clr, 0);
 }
 
-static inline void set_irq_noprobe(unsigned int irq)
+static inline void irq_set_noprobe(unsigned int irq)
 {
        irq_modify_status(irq, 0, IRQ_NOPROBE);
 }
 
-static inline void set_irq_probe(unsigned int irq)
+static inline void irq_set_probe(unsigned int irq)
 {
        irq_modify_status(irq, IRQ_NOPROBE, 0);
 }
 
+static inline void irq_set_nested_thread(unsigned int irq, bool nest)
+{
+       if (nest)
+               irq_set_status_flags(irq, IRQ_NESTED_THREAD);
+       else
+               irq_clear_status_flags(irq, IRQ_NESTED_THREAD);
+}
+
 /* Handle dynamic irq creation and destruction */
 extern unsigned int create_irq_nr(unsigned int irq_want, int node);
 extern int create_irq(void);
@@ -337,14 +483,14 @@ static inline void dynamic_irq_init(unsigned int irq)
 }
 
 /* Set/get chip/data for an IRQ: */
-extern int set_irq_chip(unsigned int irq, struct irq_chip *chip);
-extern int set_irq_data(unsigned int irq, void *data);
-extern int set_irq_chip_data(unsigned int irq, void *data);
-extern int set_irq_type(unsigned int irq, unsigned int type);
-extern int set_irq_msi(unsigned int irq, struct msi_desc *entry);
+extern int irq_set_chip(unsigned int irq, struct irq_chip *chip);
+extern int irq_set_handler_data(unsigned int irq, void *data);
+extern int irq_set_chip_data(unsigned int irq, void *data);
+extern int irq_set_irq_type(unsigned int irq, unsigned int type);
+extern int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry);
 extern struct irq_data *irq_get_irq_data(unsigned int irq);
 
-static inline struct irq_chip *get_irq_chip(unsigned int irq)
+static inline struct irq_chip *irq_get_chip(unsigned int irq)
 {
        struct irq_data *d = irq_get_irq_data(irq);
        return d ? d->chip : NULL;
@@ -355,7 +501,7 @@ static inline struct irq_chip *irq_data_get_irq_chip(struct irq_data *d)
        return d->chip;
 }
 
-static inline void *get_irq_chip_data(unsigned int irq)
+static inline void *irq_get_chip_data(unsigned int irq)
 {
        struct irq_data *d = irq_get_irq_data(irq);
        return d ? d->chip_data : NULL;
@@ -366,18 +512,18 @@ static inline void *irq_data_get_irq_chip_data(struct irq_data *d)
        return d->chip_data;
 }
 
-static inline void *get_irq_data(unsigned int irq)
+static inline void *irq_get_handler_data(unsigned int irq)
 {
        struct irq_data *d = irq_get_irq_data(irq);
        return d ? d->handler_data : NULL;
 }
 
-static inline void *irq_data_get_irq_data(struct irq_data *d)
+static inline void *irq_data_get_irq_handler_data(struct irq_data *d)
 {
        return d->handler_data;
 }
 
-static inline struct msi_desc *get_irq_msi(unsigned int irq)
+static inline struct msi_desc *irq_get_msi_desc(unsigned int irq)
 {
        struct irq_data *d = irq_get_irq_data(irq);
        return d ? d->msi_desc : NULL;
@@ -388,6 +534,89 @@ static inline struct msi_desc *irq_data_get_msi(struct irq_data *d)
        return d->msi_desc;
 }
 
+#ifndef CONFIG_GENERIC_HARDIRQS_NO_COMPAT
+/* Please do not use: Use the replacement functions instead */
+static inline int set_irq_chip(unsigned int irq, struct irq_chip *chip)
+{
+       return irq_set_chip(irq, chip);
+}
+static inline int set_irq_data(unsigned int irq, void *data)
+{
+       return irq_set_handler_data(irq, data);
+}
+static inline int set_irq_chip_data(unsigned int irq, void *data)
+{
+       return irq_set_chip_data(irq, data);
+}
+static inline int set_irq_type(unsigned int irq, unsigned int type)
+{
+       return irq_set_irq_type(irq, type);
+}
+static inline int set_irq_msi(unsigned int irq, struct msi_desc *entry)
+{
+       return irq_set_msi_desc(irq, entry);
+}
+static inline struct irq_chip *get_irq_chip(unsigned int irq)
+{
+       return irq_get_chip(irq);
+}
+static inline void *get_irq_chip_data(unsigned int irq)
+{
+       return irq_get_chip_data(irq);
+}
+static inline void *get_irq_data(unsigned int irq)
+{
+       return irq_get_handler_data(irq);
+}
+static inline void *irq_data_get_irq_data(struct irq_data *d)
+{
+       return irq_data_get_irq_handler_data(d);
+}
+static inline struct msi_desc *get_irq_msi(unsigned int irq)
+{
+       return irq_get_msi_desc(irq);
+}
+static inline void set_irq_noprobe(unsigned int irq)
+{
+       irq_set_noprobe(irq);
+}
+static inline void set_irq_probe(unsigned int irq)
+{
+       irq_set_probe(irq);
+}
+static inline void set_irq_nested_thread(unsigned int irq, int nest)
+{
+       irq_set_nested_thread(irq, nest);
+}
+static inline void
+set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
+                             irq_flow_handler_t handle, const char *name)
+{
+       irq_set_chip_and_handler_name(irq, chip, handle, name);
+}
+static inline void
+set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip,
+                        irq_flow_handler_t handle)
+{
+       irq_set_chip_and_handler(irq, chip, handle);
+}
+static inline void
+__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
+                 const char *name)
+{
+       __irq_set_handler(irq, handle, is_chained, name);
+}
+static inline void set_irq_handler(unsigned int irq, irq_flow_handler_t handle)
+{
+       irq_set_handler(irq, handle);
+}
+static inline void
+set_irq_chained_handler(unsigned int irq, irq_flow_handler_t handle)
+{
+       irq_set_chained_handler(irq, handle);
+}
+#endif
+
 int irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node);
 void irq_free_descs(unsigned int irq, unsigned int cnt);
 int irq_reserve_irqs(unsigned int from, unsigned int cnt);
index c1a95b7..0021837 100644 (file)
@@ -8,6 +8,7 @@
  * For now it's included from <linux/irq.h>
  */
 
+struct irq_affinity_notify;
 struct proc_dir_entry;
 struct timer_rand_state;
 /**
@@ -18,13 +19,16 @@ struct timer_rand_state;
  * @handle_irq:                highlevel irq-events handler [if NULL, __do_IRQ()]
  * @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
  * @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_notify:   context for notification of affinity changes
  * @pending_mask:      pending rebalanced interrupts
+ * @threads_oneshot:   bitfield to handle shared oneshot threads
  * @threads_active:    number of irqaction threads currently running
  * @wait_for_threads:  wait queue for sync_irq to wait for threaded handlers
  * @dir:               /proc/irq/ procfs entry
@@ -45,6 +49,7 @@ struct irq_desc {
                struct {
                        unsigned int            irq;
                        unsigned int            node;
+                       unsigned int            pad_do_not_even_think_about_it;
                        struct irq_chip         *chip;
                        void                    *handler_data;
                        void                    *chip_data;
@@ -59,9 +64,16 @@ struct irq_desc {
        struct timer_rand_state *timer_rand_state;
        unsigned int __percpu   *kstat_irqs;
        irq_flow_handler_t      handle_irq;
+#ifdef CONFIG_IRQ_PREFLOW_FASTEOI
+       irq_preflow_handler_t   preflow_handler;
+#endif
        struct irqaction        *action;        /* IRQ action list */
+#ifdef CONFIG_GENERIC_HARDIRQS_NO_COMPAT
+       unsigned int            status_use_accessors;
+#else
        unsigned int            status;         /* IRQ status */
-
+#endif
+       unsigned int            core_internal_state__do_not_mess_with_it;
        unsigned int            depth;          /* nested irq disables */
        unsigned int            wake_depth;     /* nested wake enables */
        unsigned int            irq_count;      /* For detecting broken IRQs */
@@ -70,10 +82,12 @@ struct irq_desc {
        raw_spinlock_t          lock;
 #ifdef CONFIG_SMP
        const struct cpumask    *affinity_hint;
+       struct irq_affinity_notify *affinity_notify;
 #ifdef CONFIG_GENERIC_PENDING_IRQ
        cpumask_var_t           pending_mask;
 #endif
 #endif
+       unsigned long           threads_oneshot;
        atomic_t                threads_active;
        wait_queue_head_t       wait_for_threads;
 #ifdef CONFIG_PROC_FS
@@ -95,10 +109,51 @@ static inline struct irq_desc *move_irq_desc(struct irq_desc *desc, int node)
 
 #ifdef CONFIG_GENERIC_HARDIRQS
 
-#define get_irq_desc_chip(desc)                ((desc)->irq_data.chip)
-#define get_irq_desc_chip_data(desc)   ((desc)->irq_data.chip_data)
-#define get_irq_desc_data(desc)                ((desc)->irq_data.handler_data)
-#define get_irq_desc_msi(desc)         ((desc)->irq_data.msi_desc)
+static inline struct irq_data *irq_desc_get_irq_data(struct irq_desc *desc)
+{
+       return &desc->irq_data;
+}
+
+static inline struct irq_chip *irq_desc_get_chip(struct irq_desc *desc)
+{
+       return desc->irq_data.chip;
+}
+
+static inline void *irq_desc_get_chip_data(struct irq_desc *desc)
+{
+       return desc->irq_data.chip_data;
+}
+
+static inline void *irq_desc_get_handler_data(struct irq_desc *desc)
+{
+       return desc->irq_data.handler_data;
+}
+
+static inline struct msi_desc *irq_desc_get_msi_desc(struct irq_desc *desc)
+{
+       return desc->irq_data.msi_desc;
+}
+
+#ifndef CONFIG_GENERIC_HARDIRQS_NO_COMPAT
+static inline struct irq_chip *get_irq_desc_chip(struct irq_desc *desc)
+{
+       return irq_desc_get_chip(desc);
+}
+static inline void *get_irq_desc_data(struct irq_desc *desc)
+{
+       return irq_desc_get_handler_data(desc);
+}
+
+static inline void *get_irq_desc_chip_data(struct irq_desc *desc)
+{
+       return irq_desc_get_chip_data(desc);
+}
+
+static inline struct msi_desc *get_irq_desc_msi(struct irq_desc *desc)
+{
+       return irq_desc_get_msi_desc(desc);
+}
+#endif
 
 /*
  * Architectures call this to let the generic IRQ layer
@@ -123,6 +178,7 @@ static inline int irq_has_action(unsigned int irq)
        return desc->action != NULL;
 }
 
+#ifndef CONFIG_GENERIC_HARDIRQS_NO_COMPAT
 static inline int irq_balancing_disabled(unsigned int irq)
 {
        struct irq_desc *desc;
@@ -130,6 +186,7 @@ static inline int irq_balancing_disabled(unsigned int irq)
        desc = irq_to_desc(irq);
        return desc->status & IRQ_NO_BALANCING_MASK;
 }
+#endif
 
 /* caller has locked the irq_desc and both params are valid */
 static inline void __set_irq_handler_unlocked(int irq,
@@ -140,6 +197,17 @@ static inline void __set_irq_handler_unlocked(int irq,
        desc = irq_to_desc(irq);
        desc->handle_irq = handler;
 }
+
+#ifdef CONFIG_IRQ_PREFLOW_FASTEOI
+static inline void
+__irq_set_preflow_handler(unsigned int irq, irq_preflow_handler_t handler)
+{
+       struct irq_desc *desc;
+
+       desc = irq_to_desc(irq);
+       desc->preflow_handler = handler;
+}
+#endif
 #endif
 
 #endif
index 6811f4b..922aa31 100644 (file)
@@ -307,6 +307,7 @@ extern clock_t jiffies_to_clock_t(long x);
 extern unsigned long clock_t_to_jiffies(unsigned long x);
 extern u64 jiffies_64_to_clock_t(u64 x);
 extern u64 nsec_to_clock_t(u64 x);
+extern u64 nsecs_to_jiffies64(u64 n);
 extern unsigned long nsecs_to_jiffies(u64 n);
 
 #define TIMESTAMP_SIZE 30
index e2f4d6a..2fe6e84 100644 (file)
@@ -588,7 +588,7 @@ struct sysinfo {
 
 /**
  * BUILD_BUG_ON - break compile if a condition is true.
- * @cond: the condition which the compiler should know is false.
+ * @condition: the condition which the compiler should know is false.
  *
  * If you have some code which relies on certain constants being equal, or
  * other compile-time-evaluated condition, you should use BUILD_BUG_ON to
index e91a4e5..a370ce5 100644 (file)
@@ -22,7 +22,7 @@ struct klist {
        struct list_head        k_list;
        void                    (*get)(struct klist_node *);
        void                    (*put)(struct klist_node *);
-} __attribute__ ((aligned (4)));
+} __attribute__ ((aligned (sizeof(void *))));
 
 #define KLIST_INIT(_name, _get, _put)                                  \
        { .k_lock       = __SPIN_LOCK_UNLOCKED(_name.k_lock),           \
index ce0775a..7ff16f7 100644 (file)
@@ -64,7 +64,7 @@ struct kthread_work {
 };
 
 #define KTHREAD_WORKER_INIT(worker)    {                               \
-       .lock = SPIN_LOCK_UNLOCKED,                                     \
+       .lock = __SPIN_LOCK_UNLOCKED((worker).lock),                    \
        .work_list = LIST_HEAD_INIT((worker).work_list),                \
        }
 
index 9a5f8a7..3a54266 100644 (file)
@@ -96,6 +96,11 @@ static inline void __list_del(struct list_head * prev, struct list_head * next)
  * in an undefined state.
  */
 #ifndef CONFIG_DEBUG_LIST
+static inline void __list_del_entry(struct list_head *entry)
+{
+       __list_del(entry->prev, entry->next);
+}
+
 static inline void list_del(struct list_head *entry)
 {
        __list_del(entry->prev, entry->next);
@@ -103,6 +108,7 @@ static inline void list_del(struct list_head *entry)
        entry->prev = LIST_POISON2;
 }
 #else
+extern void __list_del_entry(struct list_head *entry);
 extern void list_del(struct list_head *entry);
 #endif
 
@@ -135,7 +141,7 @@ static inline void list_replace_init(struct list_head *old,
  */
 static inline void list_del_init(struct list_head *entry)
 {
-       __list_del(entry->prev, entry->next);
+       __list_del_entry(entry);
        INIT_LIST_HEAD(entry);
 }
 
@@ -146,7 +152,7 @@ static inline void list_del_init(struct list_head *entry)
  */
 static inline void list_move(struct list_head *list, struct list_head *head)
 {
-       __list_del(list->prev, list->next);
+       __list_del_entry(list);
        list_add(list, head);
 }
 
@@ -158,7 +164,7 @@ static inline void list_move(struct list_head *list, struct list_head *head)
 static inline void list_move_tail(struct list_head *list,
                                  struct list_head *head)
 {
-       __list_del(list->prev, list->next);
+       __list_del_entry(list);
        list_add_tail(list, head);
 }
 
index 3fd3684..ef4f0b6 100644 (file)
@@ -71,6 +71,7 @@ struct wm8994 {
        u16 irq_masks_cache[WM8994_NUM_IRQ_REGS];
 
        /* Used over suspend/resume */
+       bool suspended;
        u16 ldo_regs[WM8994_NUM_LDO_REGS];
        u16 gpio_regs[WM8994_NUM_GPIO_REGS];
 
index f6385fc..679300c 100644 (file)
@@ -1309,8 +1309,6 @@ int add_from_early_node_map(struct range *range, int az,
                                   int nr_range, int nid);
 u64 __init find_memory_core_early(int nid, u64 size, u64 align,
                                        u64 goal, u64 limit);
-void *__alloc_memory_core_early(int nodeid, u64 size, u64 align,
-                                u64 goal, u64 limit);
 typedef int (*work_fn_t)(unsigned long, unsigned long, void *);
 extern void work_with_active_regions(int nid, work_fn_t work_fn, void *data);
 extern void sparse_memory_present_with_active_regions(int nid);
index bf17350..38d3930 100644 (file)
@@ -94,12 +94,12 @@ struct sh_mmcif_plat_data {
 
 static inline u32 sh_mmcif_readl(void __iomem *addr, int reg)
 {
-       return readl(addr + reg);
+       return __raw_readl(addr + reg);
 }
 
 static inline void sh_mmcif_writel(void __iomem *addr, int reg, u32 val)
 {
-       writel(val, addr + reg);
+       __raw_writel(val, addr + reg);
 }
 
 #define SH_MMCIF_BBS 512 /* boot block size */
index e7c6385..5de4204 100644 (file)
@@ -62,7 +62,7 @@ struct module_version_attribute {
        struct module_attribute mattr;
        const char *module_name;
        const char *version;
-};
+} __attribute__ ((__aligned__(sizeof(void *))));
 
 struct module_kobject
 {
@@ -377,7 +377,7 @@ struct module
           keeping pointers to this stuff */
        char *args;
 #ifdef CONFIG_TRACEPOINTS
-       struct tracepoint *tracepoints;
+       struct tracepoint * const *tracepoints_ptrs;
        unsigned int num_tracepoints;
 #endif
 #ifdef HAVE_JUMP_LABEL
@@ -389,7 +389,7 @@ struct module
        unsigned int num_trace_bprintk_fmt;
 #endif
 #ifdef CONFIG_EVENT_TRACING
-       struct ftrace_event_call *trace_events;
+       struct ftrace_event_call **trace_events;
        unsigned int num_trace_events;
 #endif
 #ifdef CONFIG_FTRACE_MCOUNT_RECORD
index 0fa7a3a..b21d567 100644 (file)
@@ -150,6 +150,7 @@ static inline int ip_mroute_opt(int opt)
 extern int ip_mroute_setsockopt(struct sock *, int, char __user *, unsigned int);
 extern int ip_mroute_getsockopt(struct sock *, int, char __user *, int __user *);
 extern int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg);
+extern int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg);
 extern int ip_mr_init(void);
 #else
 static inline
index 6091ab7..9d2deb2 100644 (file)
@@ -136,6 +136,7 @@ extern int ip6_mroute_setsockopt(struct sock *, int, char __user *, unsigned int
 extern int ip6_mroute_getsockopt(struct sock *, int, char __user *, int __user *);
 extern int ip6_mr_input(struct sk_buff *skb);
 extern int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg);
+extern int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg);
 extern int ip6_mr_init(void);
 extern void ip6_mr_cleanup(void);
 #else
index f276d4f..9c86038 100644 (file)
@@ -19,7 +19,6 @@ struct nameidata {
        struct path     path;
        struct qstr     last;
        struct path     root;
-       struct file     *file;
        struct inode    *inode; /* path.dentry.d_inode */
        unsigned int    flags;
        unsigned        seq;
@@ -63,6 +62,10 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
 #define LOOKUP_EXCL            0x0400
 #define LOOKUP_RENAME_TARGET   0x0800
 
+#define LOOKUP_JUMPED          0x1000
+#define LOOKUP_ROOT            0x2000
+#define LOOKUP_EMPTY           0x4000
+
 extern int user_path_at(int, const char __user *, unsigned, struct path *);
 
 #define user_path(name, path) user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW, path)
@@ -72,7 +75,7 @@ extern int user_path_at(int, const char __user *, unsigned, struct path *);
 
 extern int kern_path(const char *, unsigned, struct path *);
 
-extern int path_lookup(const char *, unsigned, struct nameidata *);
+extern int kern_path_parent(const char *, struct nameidata *);
 extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
                           const char *, unsigned int, struct nameidata *);
 
index d971346..71caf7a 100644 (file)
@@ -2392,6 +2392,9 @@ extern int netdev_notice(const struct net_device *dev, const char *format, ...)
 extern int netdev_info(const struct net_device *dev, const char *format, ...)
        __attribute__ ((format (printf, 2, 3)));
 
+#define MODULE_ALIAS_NETDEV(device) \
+       MODULE_ALIAS("netdev-" device)
+
 #if defined(DEBUG)
 #define netdev_dbg(__dev, format, args...)                     \
        netdev_printk(KERN_DEBUG, __dev, format, ##args)
index b197563..3e112de 100644 (file)
@@ -68,11 +68,7 @@ struct nfs_client {
        unsigned char           cl_id_uniquifier;
        u32                     cl_cb_ident;    /* v4.0 callback identifier */
        const struct nfs4_minor_version_ops *cl_mvops;
-#endif /* CONFIG_NFS_V4 */
 
-#ifdef CONFIG_NFS_V4_1
-       /* clientid returned from EXCHANGE_ID, used by session operations */
-       u64                     cl_ex_clid;
        /* The sequence id to use for the next CREATE_SESSION */
        u32                     cl_seqid;
        /* The flags used for obtaining the clientid during EXCHANGE_ID */
@@ -80,7 +76,7 @@ struct nfs_client {
        struct nfs4_session     *cl_session;    /* sharred session */
        struct list_head        cl_layouts;
        struct pnfs_deviceid_cache *cl_devid_cache; /* pNFS deviceid cache */
-#endif /* CONFIG_NFS_V4_1 */
+#endif /* CONFIG_NFS_V4 */
 
 #ifdef CONFIG_NFS_FSCACHE
        struct fscache_cookie   *fscache;       /* client index cache cookie */
@@ -185,7 +181,7 @@ struct nfs_server {
 /* maximum number of slots to use */
 #define NFS4_MAX_SLOT_TABLE RPC_MAX_SLOT_TABLE
 
-#if defined(CONFIG_NFS_V4_1)
+#if defined(CONFIG_NFS_V4)
 
 /* Sessions */
 #define SLOT_TABLE_SZ (NFS4_MAX_SLOT_TABLE/(8*sizeof(long)))
@@ -225,5 +221,5 @@ struct nfs4_session {
        struct nfs_client               *clp;
 };
 
-#endif /* CONFIG_NFS_V4_1 */
+#endif /* CONFIG_NFS_V4 */
 #endif
index f321b57..fabcb1e 100644 (file)
@@ -51,10 +51,10 @@ nfsacl_size(struct posix_acl *acl_access, struct posix_acl *acl_default)
        return w;
 }
 
-extern unsigned int
+extern int
 nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
              struct posix_acl *acl, int encode_entries, int typeflag);
-extern unsigned int
+extern int
 nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt,
              struct posix_acl **pacl);
 
index cad7cf0..266db1d 100644 (file)
@@ -23,8 +23,6 @@
 
 #include <asm/byteorder.h>
 
-#ifdef CONFIG_OF
-
 typedef u32 phandle;
 typedef u32 ihandle;
 
@@ -65,11 +63,18 @@ struct device_node {
 #endif
 };
 
+#ifdef CONFIG_OF
+
 /* Pointer for first entry in chain of all nodes. */
 extern struct device_node *allnodes;
 extern struct device_node *of_chosen;
 extern rwlock_t devtree_lock;
 
+static inline bool of_have_populated_dt(void)
+{
+       return allnodes != NULL;
+}
+
 static inline bool of_node_is_root(const struct device_node *node)
 {
        return node && (node->parent == NULL);
@@ -222,5 +227,12 @@ extern void of_attach_node(struct device_node *);
 extern void of_detach_node(struct device_node *);
 #endif
 
+#else
+
+static inline bool of_have_populated_dt(void)
+{
+       return false;
+}
+
 #endif /* CONFIG_OF */
 #endif /* _LINUX_OF_H */
diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
new file mode 100644 (file)
index 0000000..85a27b6
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __OF_PCI_H
+#define __OF_PCI_H
+
+#include <linux/pci.h>
+
+struct pci_dev;
+struct of_irq;
+int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq);
+#endif
index 32fb812..1ca6411 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/types.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/printk.h>
 #include <asm/atomic.h>
  
 /* Each escaped entry is prefixed by ESCAPE_CODE
@@ -186,10 +188,17 @@ int oprofile_add_data(struct op_entry *entry, unsigned long val);
 int oprofile_add_data64(struct op_entry *entry, u64 val);
 int oprofile_write_commit(struct op_entry *entry);
 
-#ifdef CONFIG_PERF_EVENTS
+#ifdef CONFIG_HW_PERF_EVENTS
 int __init oprofile_perf_init(struct oprofile_operations *ops);
 void oprofile_perf_exit(void);
 char *op_name_from_perf_id(void);
-#endif /* CONFIG_PERF_EVENTS */
+#else
+static inline int __init oprofile_perf_init(struct oprofile_operations *ops)
+{
+       pr_info("oprofile: hardware counters not available\n");
+       return -ENODEV;
+}
+static inline void oprofile_perf_exit(void) { }
+#endif /* CONFIG_HW_PERF_EVENTS */
 
 #endif /* OPROFILE_H */
index 3adb06e..580de67 100644 (file)
 #define PCI_DEVICE_ID_AMD_11H_NB_MISC  0x1303
 #define PCI_DEVICE_ID_AMD_11H_NB_LINK  0x1304
 #define PCI_DEVICE_ID_AMD_15H_NB_MISC  0x1603
+#define PCI_DEVICE_ID_AMD_15H_NB_LINK  0x1604
 #define PCI_DEVICE_ID_AMD_CNB17H_F3    0x1703
 #define PCI_DEVICE_ID_AMD_LANCE                0x2000
 #define PCI_DEVICE_ID_AMD_LANCE_HOME   0x2001
index dda5b0a..614615b 100644 (file)
@@ -225,8 +225,14 @@ struct perf_event_attr {
        };
 
        __u32                   bp_type;
-       __u64                   bp_addr;
-       __u64                   bp_len;
+       union {
+               __u64           bp_addr;
+               __u64           config1; /* extension of config */
+       };
+       union {
+               __u64           bp_len;
+               __u64           config2; /* extension of config1 */
+       };
 };
 
 /*
@@ -464,6 +470,7 @@ enum perf_callchain_context {
 
 #define PERF_FLAG_FD_NO_GROUP  (1U << 0)
 #define PERF_FLAG_FD_OUTPUT    (1U << 1)
+#define PERF_FLAG_PID_CGROUP   (1U << 2) /* pid=cgroup id, per-cpu mode only */
 
 #ifdef __KERNEL__
 /*
@@ -471,6 +478,7 @@ enum perf_callchain_context {
  */
 
 #ifdef CONFIG_PERF_EVENTS
+# include <linux/cgroup.h>
 # include <asm/perf_event.h>
 # include <asm/local64.h>
 #endif
@@ -539,6 +547,9 @@ struct hw_perf_event {
                        unsigned long   event_base;
                        int             idx;
                        int             last_cpu;
+                       unsigned int    extra_reg;
+                       u64             extra_config;
+                       int             extra_alloc;
                };
                struct { /* software */
                        struct hrtimer  hrtimer;
@@ -716,6 +727,22 @@ struct swevent_hlist {
 #define PERF_ATTACH_GROUP      0x02
 #define PERF_ATTACH_TASK       0x04
 
+#ifdef CONFIG_CGROUP_PERF
+/*
+ * perf_cgroup_info keeps track of time_enabled for a cgroup.
+ * This is a per-cpu dynamically allocated data structure.
+ */
+struct perf_cgroup_info {
+       u64 time;
+       u64 timestamp;
+};
+
+struct perf_cgroup {
+       struct cgroup_subsys_state css;
+       struct perf_cgroup_info *info;  /* timing info, one per cpu */
+};
+#endif
+
 /**
  * struct perf_event - performance event kernel representation:
  */
@@ -832,6 +859,11 @@ struct perf_event {
        struct event_filter             *filter;
 #endif
 
+#ifdef CONFIG_CGROUP_PERF
+       struct perf_cgroup              *cgrp; /* cgroup event is attach to */
+       int                             cgrp_defer_enabled;
+#endif
+
 #endif /* CONFIG_PERF_EVENTS */
 };
 
@@ -886,6 +918,7 @@ struct perf_event_context {
        u64                             generation;
        int                             pin_count;
        struct rcu_head                 rcu_head;
+       int                             nr_cgroups; /* cgroup events present */
 };
 
 /*
@@ -905,6 +938,9 @@ struct perf_cpu_context {
        struct list_head                rotation_list;
        int                             jiffies_interval;
        struct pmu                      *active_pmu;
+#ifdef CONFIG_CGROUP_PERF
+       struct perf_cgroup              *cgrp;
+#endif
 };
 
 struct perf_output_handle {
@@ -1040,11 +1076,11 @@ have_event:
        __perf_sw_event(event_id, nr, nmi, regs, addr);
 }
 
-extern atomic_t perf_task_events;
+extern atomic_t perf_sched_events;
 
 static inline void perf_event_task_sched_in(struct task_struct *task)
 {
-       COND_STMT(&perf_task_events, __perf_event_task_sched_in(task));
+       COND_STMT(&perf_sched_events, __perf_event_task_sched_in(task));
 }
 
 static inline
@@ -1052,7 +1088,7 @@ void perf_event_task_sched_out(struct task_struct *task, struct task_struct *nex
 {
        perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 1, NULL, 0);
 
-       COND_STMT(&perf_task_events, __perf_event_task_sched_out(task, next));
+       COND_STMT(&perf_sched_events, __perf_event_task_sched_out(task, next));
 }
 
 extern void perf_event_mmap(struct vm_area_struct *vma);
@@ -1083,6 +1119,10 @@ extern int sysctl_perf_event_paranoid;
 extern int sysctl_perf_event_mlock;
 extern int sysctl_perf_event_sample_rate;
 
+extern int perf_proc_update_handler(struct ctl_table *table, int write,
+               void __user *buffer, size_t *lenp,
+               loff_t *ppos);
+
 static inline bool perf_paranoid_tracepoint_raw(void)
 {
        return sysctl_perf_event_paranoid > -1;
index 7254eda..c9b9f32 100644 (file)
  *
  * Simple ASCII art explanation:
  *
- * |HEAD          |
- * |              |
- * |prio_list.prev|<------------------------------------|
- * |prio_list.next|<->|pl|<->|pl|<--------------->|pl|<-|
- * |10            |   |10|   |21|   |21|   |21|   |40|   (prio)
- * |              |   |  |   |  |   |  |   |  |   |  |
- * |              |   |  |   |  |   |  |   |  |   |  |
- * |node_list.next|<->|nl|<->|nl|<->|nl|<->|nl|<->|nl|<-|
- * |node_list.prev|<------------------------------------|
+ * pl:prio_list (only for plist_node)
+ * nl:node_list
+ *   HEAD|             NODE(S)
+ *       |
+ *       ||------------------------------------|
+ *       ||->|pl|<->|pl|<--------------->|pl|<-|
+ *       |   |10|   |21|   |21|   |21|   |40|   (prio)
+ *       |   |  |   |  |   |  |   |  |   |  |
+ *       |   |  |   |  |   |  |   |  |   |  |
+ * |->|nl|<->|nl|<->|nl|<->|nl|<->|nl|<->|nl|<-|
+ * |-------------------------------------------|
  *
  * The nodes on the prio_list list are sorted by priority to simplify
  * the insertion of new nodes. There are no nodes with duplicate
@@ -78,7 +80,6 @@
 #include <linux/spinlock_types.h>
 
 struct plist_head {
-       struct list_head prio_list;
        struct list_head node_list;
 #ifdef CONFIG_DEBUG_PI_LIST
        raw_spinlock_t *rawlock;
@@ -88,7 +89,8 @@ struct plist_head {
 
 struct plist_node {
        int                     prio;
-       struct plist_head       plist;
+       struct list_head        prio_list;
+       struct list_head        node_list;
 };
 
 #ifdef CONFIG_DEBUG_PI_LIST
@@ -100,7 +102,6 @@ struct plist_node {
 #endif
 
 #define _PLIST_HEAD_INIT(head)                         \
-       .prio_list = LIST_HEAD_INIT((head).prio_list),  \
        .node_list = LIST_HEAD_INIT((head).node_list)
 
 /**
@@ -133,7 +134,8 @@ struct plist_node {
 #define PLIST_NODE_INIT(node, __prio)                  \
 {                                                      \
        .prio  = (__prio),                              \
-       .plist = { _PLIST_HEAD_INIT((node).plist) },    \
+       .prio_list = LIST_HEAD_INIT((node).prio_list),  \
+       .node_list = LIST_HEAD_INIT((node).node_list),  \
 }
 
 /**
@@ -144,7 +146,6 @@ struct plist_node {
 static inline void
 plist_head_init(struct plist_head *head, spinlock_t *lock)
 {
-       INIT_LIST_HEAD(&head->prio_list);
        INIT_LIST_HEAD(&head->node_list);
 #ifdef CONFIG_DEBUG_PI_LIST
        head->spinlock = lock;
@@ -160,7 +161,6 @@ plist_head_init(struct plist_head *head, spinlock_t *lock)
 static inline void
 plist_head_init_raw(struct plist_head *head, raw_spinlock_t *lock)
 {
-       INIT_LIST_HEAD(&head->prio_list);
        INIT_LIST_HEAD(&head->node_list);
 #ifdef CONFIG_DEBUG_PI_LIST
        head->rawlock = lock;
@@ -176,7 +176,8 @@ plist_head_init_raw(struct plist_head *head, raw_spinlock_t *lock)
 static inline void plist_node_init(struct plist_node *node, int prio)
 {
        node->prio = prio;
-       plist_head_init(&node->plist, NULL);
+       INIT_LIST_HEAD(&node->prio_list);
+       INIT_LIST_HEAD(&node->node_list);
 }
 
 extern void plist_add(struct plist_node *node, struct plist_head *head);
@@ -188,7 +189,7 @@ extern void plist_del(struct plist_node *node, struct plist_head *head);
  * @head:      the head for your list
  */
 #define plist_for_each(pos, head)      \
-        list_for_each_entry(pos, &(head)->node_list, plist.node_list)
+        list_for_each_entry(pos, &(head)->node_list, node_list)
 
 /**
  * plist_for_each_safe - iterate safely over a plist of given type
@@ -199,7 +200,7 @@ extern void plist_del(struct plist_node *node, struct plist_head *head);
  * Iterate over a plist of given type, safe against removal of list entry.
  */
 #define plist_for_each_safe(pos, n, head)      \
-        list_for_each_entry_safe(pos, n, &(head)->node_list, plist.node_list)
+        list_for_each_entry_safe(pos, n, &(head)->node_list, node_list)
 
 /**
  * plist_for_each_entry        - iterate over list of given type
@@ -208,7 +209,7 @@ extern void plist_del(struct plist_node *node, struct plist_head *head);
  * @mem:       the name of the list_struct within the struct
  */
 #define plist_for_each_entry(pos, head, mem)   \
-        list_for_each_entry(pos, &(head)->node_list, mem.plist.node_list)
+        list_for_each_entry(pos, &(head)->node_list, mem.node_list)
 
 /**
  * plist_for_each_entry_safe - iterate safely over list of given type
@@ -220,7 +221,7 @@ extern void plist_del(struct plist_node *node, struct plist_head *head);
  * Iterate over list of given type, safe against removal of list entry.
  */
 #define plist_for_each_entry_safe(pos, n, head, m)     \
-       list_for_each_entry_safe(pos, n, &(head)->node_list, m.plist.node_list)
+       list_for_each_entry_safe(pos, n, &(head)->node_list, m.node_list)
 
 /**
  * plist_head_empty - return !0 if a plist_head is empty
@@ -237,7 +238,7 @@ static inline int plist_head_empty(const struct plist_head *head)
  */
 static inline int plist_node_empty(const struct plist_node *node)
 {
-       return plist_head_empty(&node->plist);
+       return list_empty(&node->node_list);
 }
 
 /* All functions below assume the plist_head is not empty. */
@@ -285,7 +286,7 @@ static inline int plist_node_empty(const struct plist_node *node)
 static inline struct plist_node *plist_first(const struct plist_head *head)
 {
        return list_entry(head->node_list.next,
-                         struct plist_node, plist.node_list);
+                         struct plist_node, node_list);
 }
 
 /**
@@ -297,7 +298,7 @@ static inline struct plist_node *plist_first(const struct plist_head *head)
 static inline struct plist_node *plist_last(const struct plist_head *head)
 {
        return list_entry(head->node_list.prev,
-                         struct plist_node, plist.node_list);
+                         struct plist_node, node_list);
 }
 
 #endif
index dd9c7ab..21415cc 100644 (file)
@@ -431,6 +431,8 @@ struct dev_pm_info {
        struct list_head        entry;
        struct completion       completion;
        struct wakeup_source    *wakeup;
+#else
+       unsigned int            should_wakeup:1;
 #endif
 #ifdef CONFIG_PM_RUNTIME
        struct timer_list       suspend_timer;
index 9cff00d..03a67db 100644 (file)
@@ -109,11 +109,6 @@ static inline bool device_can_wakeup(struct device *dev)
        return dev->power.can_wakeup;
 }
 
-static inline bool device_may_wakeup(struct device *dev)
-{
-       return false;
-}
-
 static inline struct wakeup_source *wakeup_source_create(const char *name)
 {
        return NULL;
@@ -134,24 +129,32 @@ static inline void wakeup_source_unregister(struct wakeup_source *ws) {}
 
 static inline int device_wakeup_enable(struct device *dev)
 {
-       return -EINVAL;
+       dev->power.should_wakeup = true;
+       return 0;
 }
 
 static inline int device_wakeup_disable(struct device *dev)
 {
+       dev->power.should_wakeup = false;
        return 0;
 }
 
-static inline int device_init_wakeup(struct device *dev, bool val)
+static inline int device_set_wakeup_enable(struct device *dev, bool enable)
 {
-       dev->power.can_wakeup = val;
-       return val ? -EINVAL : 0;
+       dev->power.should_wakeup = enable;
+       return 0;
 }
 
+static inline int device_init_wakeup(struct device *dev, bool val)
+{
+       device_set_wakeup_capable(dev, val);
+       device_set_wakeup_enable(dev, val);
+       return 0;
+}
 
-static inline int device_set_wakeup_enable(struct device *dev, bool enable)
+static inline bool device_may_wakeup(struct device *dev)
 {
-       return -EINVAL;
+       return dev->power.can_wakeup && dev->power.should_wakeup;
 }
 
 static inline void __pm_stay_awake(struct wakeup_source *ws) {}
diff --git a/include/linux/posix-clock.h b/include/linux/posix-clock.h
new file mode 100644 (file)
index 0000000..369e19d
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * posix-clock.h - support for dynamic clock devices
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _LINUX_POSIX_CLOCK_H_
+#define _LINUX_POSIX_CLOCK_H_
+
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/posix-timers.h>
+
+struct posix_clock;
+
+/**
+ * struct posix_clock_operations - functional interface to the clock
+ *
+ * Every posix clock is represented by a character device. Drivers may
+ * optionally offer extended capabilities by implementing the
+ * character device methods. The character device file operations are
+ * first handled by the clock device layer, then passed on to the
+ * driver by calling these functions.
+ *
+ * @owner:          The clock driver should set to THIS_MODULE
+ * @clock_adjtime:  Adjust the clock
+ * @clock_gettime:  Read the current time
+ * @clock_getres:   Get the clock resolution
+ * @clock_settime:  Set the current time value
+ * @timer_create:   Create a new timer
+ * @timer_delete:   Remove a previously created timer
+ * @timer_gettime:  Get remaining time and interval of a timer
+ * @timer_setttime: Set a timer's initial expiration and interval
+ * @fasync:         Optional character device fasync method
+ * @mmap:           Optional character device mmap method
+ * @open:           Optional character device open method
+ * @release:        Optional character device release method
+ * @ioctl:          Optional character device ioctl method
+ * @read:           Optional character device read method
+ * @poll:           Optional character device poll method
+ */
+struct posix_clock_operations {
+       struct module *owner;
+
+       int  (*clock_adjtime)(struct posix_clock *pc, struct timex *tx);
+
+       int  (*clock_gettime)(struct posix_clock *pc, struct timespec *ts);
+
+       int  (*clock_getres) (struct posix_clock *pc, struct timespec *ts);
+
+       int  (*clock_settime)(struct posix_clock *pc,
+                             const struct timespec *ts);
+
+       int  (*timer_create) (struct posix_clock *pc, struct k_itimer *kit);
+
+       int  (*timer_delete) (struct posix_clock *pc, struct k_itimer *kit);
+
+       void (*timer_gettime)(struct posix_clock *pc,
+                             struct k_itimer *kit, struct itimerspec *tsp);
+
+       int  (*timer_settime)(struct posix_clock *pc,
+                             struct k_itimer *kit, int flags,
+                             struct itimerspec *tsp, struct itimerspec *old);
+       /*
+        * Optional character device methods:
+        */
+       int     (*fasync)  (struct posix_clock *pc,
+                           int fd, struct file *file, int on);
+
+       long    (*ioctl)   (struct posix_clock *pc,
+                           unsigned int cmd, unsigned long arg);
+
+       int     (*mmap)    (struct posix_clock *pc,
+                           struct vm_area_struct *vma);
+
+       int     (*open)    (struct posix_clock *pc, fmode_t f_mode);
+
+       uint    (*poll)    (struct posix_clock *pc,
+                           struct file *file, poll_table *wait);
+
+       int     (*release) (struct posix_clock *pc);
+
+       ssize_t (*read)    (struct posix_clock *pc,
+                           uint flags, char __user *buf, size_t cnt);
+};
+
+/**
+ * struct posix_clock - represents a dynamic posix clock
+ *
+ * @ops:     Functional interface to the clock
+ * @cdev:    Character device instance for this clock
+ * @kref:    Reference count.
+ * @mutex:   Protects the 'zombie' field from concurrent access.
+ * @zombie:  If 'zombie' is true, then the hardware has disappeared.
+ * @release: A function to free the structure when the reference count reaches
+ *           zero. May be NULL if structure is statically allocated.
+ *
+ * Drivers should embed their struct posix_clock within a private
+ * structure, obtaining a reference to it during callbacks using
+ * container_of().
+ */
+struct posix_clock {
+       struct posix_clock_operations ops;
+       struct cdev cdev;
+       struct kref kref;
+       struct mutex mutex;
+       bool zombie;
+       void (*release)(struct posix_clock *clk);
+};
+
+/**
+ * posix_clock_register() - register a new clock
+ * @clk:   Pointer to the clock. Caller must provide 'ops' and 'release'
+ * @devid: Allocated device id
+ *
+ * A clock driver calls this function to register itself with the
+ * clock device subsystem. If 'clk' points to dynamically allocated
+ * memory, then the caller must provide a 'release' function to free
+ * that memory.
+ *
+ * Returns zero on success, non-zero otherwise.
+ */
+int posix_clock_register(struct posix_clock *clk, dev_t devid);
+
+/**
+ * posix_clock_unregister() - unregister a clock
+ * @clk: Clock instance previously registered via posix_clock_register()
+ *
+ * A clock driver calls this function to remove itself from the clock
+ * device subsystem. The posix_clock itself will remain (in an
+ * inactive state) until its reference count drops to zero, at which
+ * point it will be deallocated with its 'release' method.
+ */
+void posix_clock_unregister(struct posix_clock *clk);
+
+#endif
index 3e23844..d51243a 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/spinlock.h>
 #include <linux/list.h>
 #include <linux/sched.h>
+#include <linux/timex.h>
 
 union cpu_time_count {
        cputime_t cpu;
@@ -17,10 +18,21 @@ struct cpu_timer_list {
        int firing;
 };
 
+/*
+ * Bit fields within a clockid:
+ *
+ * The most significant 29 bits hold either a pid or a file descriptor.
+ *
+ * Bit 2 indicates whether a cpu clock refers to a thread or a process.
+ *
+ * Bits 1 and 0 give the type: PROF=0, VIRT=1, SCHED=2, or FD=3.
+ *
+ * A clockid is invalid if bits 2, 1, and 0 are all set.
+ */
 #define CPUCLOCK_PID(clock)            ((pid_t) ~((clock) >> 3))
 #define CPUCLOCK_PERTHREAD(clock) \
        (((clock) & (clockid_t) CPUCLOCK_PERTHREAD_MASK) != 0)
-#define CPUCLOCK_PID_MASK      7
+
 #define CPUCLOCK_PERTHREAD_MASK        4
 #define CPUCLOCK_WHICH(clock)  ((clock) & (clockid_t) CPUCLOCK_CLOCK_MASK)
 #define CPUCLOCK_CLOCK_MASK    3
@@ -28,12 +40,17 @@ struct cpu_timer_list {
 #define CPUCLOCK_VIRT          1
 #define CPUCLOCK_SCHED         2
 #define CPUCLOCK_MAX           3
+#define CLOCKFD                        CPUCLOCK_MAX
+#define CLOCKFD_MASK           (CPUCLOCK_PERTHREAD_MASK|CPUCLOCK_CLOCK_MASK)
 
 #define MAKE_PROCESS_CPUCLOCK(pid, clock) \
        ((~(clockid_t) (pid) << 3) | (clockid_t) (clock))
 #define MAKE_THREAD_CPUCLOCK(tid, clock) \
        MAKE_PROCESS_CPUCLOCK((tid), (clock) | CPUCLOCK_PERTHREAD_MASK)
 
+#define FD_TO_CLOCKID(fd)      ((~(clockid_t) (fd) << 3) | CLOCKFD)
+#define CLOCKID_TO_FD(clk)     ((unsigned int) ~((clk) >> 3))
+
 /* POSIX.1b interval timer structure. */
 struct k_itimer {
        struct list_head list;          /* free/ allocate list */
@@ -67,10 +84,11 @@ struct k_itimer {
 };
 
 struct k_clock {
-       int res;                /* in nanoseconds */
        int (*clock_getres) (const clockid_t which_clock, struct timespec *tp);
-       int (*clock_set) (const clockid_t which_clock, struct timespec * tp);
+       int (*clock_set) (const clockid_t which_clock,
+                         const struct timespec *tp);
        int (*clock_get) (const clockid_t which_clock, struct timespec * tp);
+       int (*clock_adj) (const clockid_t which_clock, struct timex *tx);
        int (*timer_create) (struct k_itimer *timer);
        int (*nsleep) (const clockid_t which_clock, int flags,
                       struct timespec *, struct timespec __user *);
@@ -84,28 +102,14 @@ struct k_clock {
                           struct itimerspec * cur_setting);
 };
 
-void register_posix_clock(const clockid_t clock_id, struct k_clock *new_clock);
+extern struct k_clock clock_posix_cpu;
+extern struct k_clock clock_posix_dynamic;
 
-/* error handlers for timer_create, nanosleep and settime */
-int do_posix_clock_nonanosleep(const clockid_t, int flags, struct timespec *,
-                              struct timespec __user *);
-int do_posix_clock_nosettime(const clockid_t, struct timespec *tp);
+void posix_timers_register_clock(const clockid_t clock_id, struct k_clock *new_clock);
 
 /* function to call to trigger timer event */
 int posix_timer_event(struct k_itimer *timr, int si_private);
 
-int posix_cpu_clock_getres(const clockid_t which_clock, struct timespec *ts);
-int posix_cpu_clock_get(const clockid_t which_clock, struct timespec *ts);
-int posix_cpu_clock_set(const clockid_t which_clock, const struct timespec *ts);
-int posix_cpu_timer_create(struct k_itimer *timer);
-int posix_cpu_nsleep(const clockid_t which_clock, int flags,
-                    struct timespec *rqtp, struct timespec __user *rmtp);
-long posix_cpu_nsleep_restart(struct restart_block *restart_block);
-int posix_cpu_timer_set(struct k_itimer *timer, int flags,
-                       struct itimerspec *new, struct itimerspec *old);
-int posix_cpu_timer_del(struct k_itimer *timer);
-void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp);
-
 void posix_cpu_timer_schedule(struct k_itimer *timer);
 
 void run_posix_cpu_timers(struct task_struct *task);
index d68283a..54211c1 100644 (file)
@@ -71,6 +71,7 @@ posix_acl_release(struct posix_acl *acl)
 
 /* posix_acl.c */
 
+extern void posix_acl_init(struct posix_acl *, int);
 extern struct posix_acl *posix_acl_alloc(int, gfp_t);
 extern struct posix_acl *posix_acl_clone(const struct posix_acl *, gfp_t);
 extern int posix_acl_valid(const struct posix_acl *);
index 092a04f..a1147e5 100644 (file)
 
 extern long arch_ptrace(struct task_struct *child, long request,
                        unsigned long addr, unsigned long data);
-extern int ptrace_traceme(void);
 extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len);
 extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len);
-extern int ptrace_attach(struct task_struct *tsk);
-extern int ptrace_detach(struct task_struct *, unsigned int);
 extern void ptrace_disable(struct task_struct *);
 extern int ptrace_check_attach(struct task_struct *task, int kill);
 extern int ptrace_request(struct task_struct *child, long request,
index fcb9884..a5930cb 100644 (file)
@@ -182,6 +182,26 @@ static inline bool res_counter_check_under_limit(struct res_counter *cnt)
        return ret;
 }
 
+/**
+ * res_counter_check_margin - check if the counter allows charging
+ * @cnt: the resource counter to check
+ * @bytes: the number of bytes to check the remaining space against
+ *
+ * Returns a boolean value on whether the counter can be charged
+ * @bytes or whether this would exceed the limit.
+ */
+static inline bool res_counter_check_margin(struct res_counter *cnt,
+                                           unsigned long bytes)
+{
+       bool ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&cnt->lock, flags);
+       ret = cnt->limit - cnt->usage >= bytes;
+       spin_unlock_irqrestore(&cnt->lock, flags);
+       return ret;
+}
+
 static inline bool res_counter_check_under_soft_limit(struct res_counter *cnt)
 {
        bool ret;
index 8d3a248..ab38ac8 100644 (file)
@@ -100,6 +100,8 @@ void ring_buffer_free(struct ring_buffer *buffer);
 
 int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size);
 
+void ring_buffer_change_overwrite(struct ring_buffer *buffer, int val);
+
 struct ring_buffer_event *ring_buffer_lock_reserve(struct ring_buffer *buffer,
                                                   unsigned long length);
 int ring_buffer_unlock_commit(struct ring_buffer *buffer,
index d63dcba..9026b30 100644 (file)
 #define LINUX_RIO_REGS_H
 
 /*
- * In RapidIO, each device has a 2MB configuration space that is
+ * In RapidIO, each device has a 16MB configuration space that is
  * accessed via maintenance transactions.  Portions of configuration
  * space are standardized and/or reserved.
  */
+#define RIO_MAINT_SPACE_SZ     0x1000000 /* 16MB of RapidIO mainenance space */
+
 #define RIO_DEV_ID_CAR         0x00    /* [I] Device Identity CAR */
 #define RIO_DEV_INFO_CAR       0x04    /* [I] Device Information CAR */
 #define RIO_ASM_ID_CAR         0x08    /* [I] Assembly Identity CAR */
index a0b639f..2ca7e8a 100644 (file)
@@ -133,7 +133,6 @@ extern struct class *rtc_class;
  * The (current) exceptions are mostly filesystem hooks:
  *   - the proc() hook for procfs
  *   - non-ioctl() chardev hooks:  open(), release(), read_callback()
- *   - periodic irq calls:  irq_set_state(), irq_set_freq()
  *
  * REVISIT those periodic irq calls *do* have ops_lock when they're
  * issued through ioctl() ...
@@ -148,11 +147,8 @@ struct rtc_class_ops {
        int (*set_alarm)(struct device *, struct rtc_wkalrm *);
        int (*proc)(struct device *, struct seq_file *);
        int (*set_mmss)(struct device *, unsigned long secs);
-       int (*irq_set_state)(struct device *, int enabled);
-       int (*irq_set_freq)(struct device *, int freq);
        int (*read_callback)(struct device *, int data);
        int (*alarm_irq_enable)(struct device *, unsigned int enabled);
-       int (*update_irq_enable)(struct device *, unsigned int enabled);
 };
 
 #define RTC_DEVICE_NAME_SIZE 20
@@ -203,6 +199,18 @@ struct rtc_device
        struct hrtimer pie_timer; /* sub second exp, so needs hrtimer */
        int pie_enabled;
        struct work_struct irqwork;
+
+
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+       struct work_struct uie_task;
+       struct timer_list uie_timer;
+       /* Those fields are protected by rtc->irq_lock */
+       unsigned int oldsecs;
+       unsigned int uie_irq_active:1;
+       unsigned int stop_uie_polling:1;
+       unsigned int uie_task_active:1;
+       unsigned int uie_timer_active:1;
+#endif
 };
 #define to_rtc_device(d) container_of(d, struct rtc_device, dev)
 
@@ -215,6 +223,7 @@ extern void rtc_device_unregister(struct rtc_device *rtc);
 extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm);
 extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm);
 extern int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs);
+int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm);
 extern int rtc_read_alarm(struct rtc_device *rtc,
                        struct rtc_wkalrm *alrm);
 extern int rtc_set_alarm(struct rtc_device *rtc,
@@ -235,7 +244,10 @@ extern int rtc_irq_set_freq(struct rtc_device *rtc,
                                struct rtc_task *task, int freq);
 extern int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled);
 extern int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled);
+extern int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc,
+                                               unsigned int enabled);
 
+void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode);
 void rtc_aie_update_irq(void *private);
 void rtc_uie_update_irq(void *private);
 enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer);
index bd31808..cc0072e 100644 (file)
@@ -43,14 +43,6 @@ typedef struct {
                                RW_DEP_MAP_INIT(lockname) }
 #endif
 
-/*
- * RW_LOCK_UNLOCKED defeat lockdep state tracking and is hence
- * deprecated.
- *
- * Please use DEFINE_RWLOCK() or __RW_LOCK_UNLOCKED() as appropriate.
- */
-#define RW_LOCK_UNLOCKED       __RW_LOCK_UNLOCKED(old_style_rw_init)
-
 #define DEFINE_RWLOCK(x)       rwlock_t x = __RW_LOCK_UNLOCKED(x)
 
 #endif /* __LINUX_RWLOCK_TYPES_H */
index bdfcc25..3470124 100644 (file)
 #error "please don't include linux/rwsem-spinlock.h directly, use linux/rwsem.h instead"
 #endif
 
-#include <linux/spinlock.h>
-#include <linux/list.h>
-
 #ifdef __KERNEL__
-
-#include <linux/types.h>
-
-struct rwsem_waiter;
-
 /*
  * the rw-semaphore definition
  * - if activity is 0 then there are no active readers or writers
@@ -37,28 +29,7 @@ struct rw_semaphore {
 #endif
 };
 
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
-#else
-# define __RWSEM_DEP_MAP_INIT(lockname)
-#endif
-
-#define __RWSEM_INITIALIZER(name) \
-{ 0, __SPIN_LOCK_UNLOCKED(name.wait_lock), LIST_HEAD_INIT((name).wait_list) \
-  __RWSEM_DEP_MAP_INIT(name) }
-
-#define DECLARE_RWSEM(name) \
-       struct rw_semaphore name = __RWSEM_INITIALIZER(name)
-
-extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
-                        struct lock_class_key *key);
-
-#define init_rwsem(sem)                                                \
-do {                                                           \
-       static struct lock_class_key __key;                     \
-                                                               \
-       __init_rwsem((sem), #sem, &__key);                      \
-} while (0)
+#define RWSEM_UNLOCKED_VALUE           0x00000000
 
 extern void __down_read(struct rw_semaphore *sem);
 extern int __down_read_trylock(struct rw_semaphore *sem);
index efd348f..a8afe9c 100644 (file)
@@ -11,6 +11,9 @@
 
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
 #include <asm/system.h>
 #include <asm/atomic.h>
 
@@ -19,9 +22,57 @@ struct rw_semaphore;
 #ifdef CONFIG_RWSEM_GENERIC_SPINLOCK
 #include <linux/rwsem-spinlock.h> /* use a generic implementation */
 #else
-#include <asm/rwsem.h> /* use an arch-specific implementation */
+/* All arch specific implementations share the same struct */
+struct rw_semaphore {
+       long                    count;
+       spinlock_t              wait_lock;
+       struct list_head        wait_list;
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       struct lockdep_map      dep_map;
+#endif
+};
+
+extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *);
+extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
+
+/* Include the arch specific part */
+#include <asm/rwsem.h>
+
+/* In all implementations count != 0 means locked */
+static inline int rwsem_is_locked(struct rw_semaphore *sem)
+{
+       return sem->count != 0;
+}
+
+#endif
+
+/* Common initializer macros and functions */
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
+#else
+# define __RWSEM_DEP_MAP_INIT(lockname)
 #endif
 
+#define __RWSEM_INITIALIZER(name) \
+       { RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED(name.wait_lock),   \
+         LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) }
+
+#define DECLARE_RWSEM(name) \
+       struct rw_semaphore name = __RWSEM_INITIALIZER(name)
+
+extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
+                        struct lock_class_key *key);
+
+#define init_rwsem(sem)                                                \
+do {                                                           \
+       static struct lock_class_key __key;                     \
+                                                               \
+       __init_rwsem((sem), #sem, &__key);                      \
+} while (0)
+
 /*
  * lock for reading
  */
index d747f94..c15936f 100644 (file)
@@ -1058,6 +1058,7 @@ struct sched_class {
        void (*enqueue_task) (struct rq *rq, struct task_struct *p, int flags);
        void (*dequeue_task) (struct rq *rq, struct task_struct *p, int flags);
        void (*yield_task) (struct rq *rq);
+       bool (*yield_to_task) (struct rq *rq, struct task_struct *p, bool preempt);
 
        void (*check_preempt_curr) (struct rq *rq, struct task_struct *p, int flags);
 
@@ -1084,12 +1085,10 @@ struct sched_class {
        void (*task_tick) (struct rq *rq, struct task_struct *p, int queued);
        void (*task_fork) (struct task_struct *p);
 
-       void (*switched_from) (struct rq *this_rq, struct task_struct *task,
-                              int running);
-       void (*switched_to) (struct rq *this_rq, struct task_struct *task,
-                            int running);
+       void (*switched_from) (struct rq *this_rq, struct task_struct *task);
+       void (*switched_to) (struct rq *this_rq, struct task_struct *task);
        void (*prio_changed) (struct rq *this_rq, struct task_struct *task,
-                            int oldprio, int running);
+                            int oldprio);
 
        unsigned int (*get_rr_interval) (struct rq *rq,
                                         struct task_struct *task);
@@ -1715,7 +1714,6 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *
 /*
  * Per process flags
  */
-#define PF_KSOFTIRQD   0x00000001      /* I am ksoftirqd */
 #define PF_STARTING    0x00000002      /* being created */
 #define PF_EXITING     0x00000004      /* getting shut down */
 #define PF_EXITPIDONE  0x00000008      /* pi exit done on shut down */
@@ -1744,7 +1742,7 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *
 #define PF_MCE_EARLY    0x08000000      /* Early kill for mce process policy */
 #define PF_MEMPOLICY   0x10000000      /* Non-default NUMA mempolicy */
 #define PF_MUTEX_TESTER        0x20000000      /* Thread belongs to the rt mutex tester */
-#define PF_FREEZER_SKIP        0x40000000      /* Freezer should not count it as freezeable */
+#define PF_FREEZER_SKIP        0x40000000      /* Freezer should not count it as freezable */
 #define PF_FREEZER_NOSIG 0x80000000    /* Freezer won't send signals to it */
 
 /*
@@ -1945,8 +1943,6 @@ int sched_rt_handler(struct ctl_table *table, int write,
                void __user *buffer, size_t *lenp,
                loff_t *ppos);
 
-extern unsigned int sysctl_sched_compat_yield;
-
 #ifdef CONFIG_SCHED_AUTOGROUP
 extern unsigned int sysctl_sched_autogroup_enabled;
 
@@ -1977,6 +1973,7 @@ static inline int rt_mutex_getprio(struct task_struct *p)
 # define rt_mutex_adjust_pi(p)         do { } while (0)
 #endif
 
+extern bool yield_to(struct task_struct *p, bool preempt);
 extern void set_user_nice(struct task_struct *p, long nice);
 extern int task_prio(const struct task_struct *p);
 extern int task_nice(const struct task_struct *p);
@@ -2049,7 +2046,7 @@ extern void release_uids(struct user_namespace *ns);
 
 #include <asm/current.h>
 
-extern void do_timer(unsigned long ticks);
+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);
@@ -2578,13 +2575,6 @@ static inline void inc_syscw(struct task_struct *tsk)
 #define TASK_SIZE_OF(tsk)      TASK_SIZE
 #endif
 
-/*
- * Call the function if the target task is executing on a CPU right now:
- */
-extern void task_oncpu_function_call(struct task_struct *p,
-                                    void (*func) (void *info), void *info);
-
-
 #ifdef CONFIG_MM_OWNER
 extern void mm_update_next_owner(struct mm_struct *mm);
 extern void mm_init_owner(struct mm_struct *mm, struct task_struct *p);
index c642bb8..debbd97 100644 (file)
@@ -53,7 +53,7 @@ struct audit_krule;
  */
 extern int cap_capable(struct task_struct *tsk, const struct cred *cred,
                       int cap, int audit);
-extern int cap_settime(struct timespec *ts, struct timezone *tz);
+extern int cap_settime(const struct timespec *ts, const struct timezone *tz);
 extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode);
 extern int cap_ptrace_traceme(struct task_struct *parent);
 extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
@@ -1387,7 +1387,7 @@ struct security_operations {
        int (*quotactl) (int cmds, int type, int id, struct super_block *sb);
        int (*quota_on) (struct dentry *dentry);
        int (*syslog) (int type);
-       int (*settime) (struct timespec *ts, struct timezone *tz);
+       int (*settime) (const struct timespec *ts, const struct timezone *tz);
        int (*vm_enough_memory) (struct mm_struct *mm, long pages);
 
        int (*bprm_set_creds) (struct linux_binprm *bprm);
@@ -1662,14 +1662,14 @@ int security_capset(struct cred *new, const struct cred *old,
                    const kernel_cap_t *effective,
                    const kernel_cap_t *inheritable,
                    const kernel_cap_t *permitted);
-int security_capable(int cap);
+int security_capable(const struct cred *cred, int cap);
 int security_real_capable(struct task_struct *tsk, int cap);
 int security_real_capable_noaudit(struct task_struct *tsk, int cap);
 int security_sysctl(struct ctl_table *table, int op);
 int security_quotactl(int cmds, int type, int id, struct super_block *sb);
 int security_quota_on(struct dentry *dentry);
 int security_syslog(int type);
-int security_settime(struct timespec *ts, struct timezone *tz);
+int security_settime(const struct timespec *ts, const struct timezone *tz);
 int security_vm_enough_memory(long pages);
 int security_vm_enough_memory_mm(struct mm_struct *mm, long pages);
 int security_vm_enough_memory_kern(long pages);
@@ -1856,9 +1856,9 @@ static inline int security_capset(struct cred *new,
        return cap_capset(new, old, effective, inheritable, permitted);
 }
 
-static inline int security_capable(int cap)
+static inline int security_capable(const struct cred *cred, int cap)
 {
-       return cap_capable(current, current_cred(), cap, SECURITY_CAP_AUDIT);
+       return cap_capable(current, cred, cap, SECURITY_CAP_AUDIT);
 }
 
 static inline int security_real_capable(struct task_struct *tsk, int cap)
@@ -1904,7 +1904,8 @@ static inline int security_syslog(int type)
        return 0;
 }
 
-static inline int security_settime(struct timespec *ts, struct timezone *tz)
+static inline int security_settime(const struct timespec *ts,
+                                  const struct timezone *tz)
 {
        return cap_settime(ts, tz);
 }
index 851b778..73548eb 100644 (file)
@@ -81,14 +81,6 @@ typedef struct spinlock {
 #define __SPIN_LOCK_UNLOCKED(lockname) \
        (spinlock_t ) __SPIN_LOCK_INITIALIZER(lockname)
 
-/*
- * SPIN_LOCK_UNLOCKED defeats lockdep state tracking and is hence
- * deprecated.
- * Please use DEFINE_SPINLOCK() or __SPIN_LOCK_UNLOCKED() as
- * appropriate.
- */
-#define SPIN_LOCK_UNLOCKED     __SPIN_LOCK_UNLOCKED(old_style_spin_init)
-
 #define DEFINE_SPINLOCK(x)     spinlock_t x = __SPIN_LOCK_UNLOCKED(x)
 
 #include <linux/rwlock_types.h>
index c50b458..0828842 100644 (file)
@@ -47,14 +47,6 @@ static inline int svc_is_backchannel(const struct svc_rqst *rqstp)
                return 1;
        return 0;
 }
-static inline struct nfs4_sessionid *bc_xprt_sid(struct svc_rqst *rqstp)
-{
-       if (svc_is_backchannel(rqstp))
-               return (struct nfs4_sessionid *)
-                       rqstp->rq_server->sv_bc_xprt->xpt_bc_sid;
-       return NULL;
-}
-
 #else /* CONFIG_NFS_V4_1 */
 static inline int xprt_setup_backchannel(struct rpc_xprt *xprt,
                                         unsigned int min_reqs)
@@ -67,11 +59,6 @@ static inline int svc_is_backchannel(const struct svc_rqst *rqstp)
        return 0;
 }
 
-static inline struct nfs4_sessionid *bc_xprt_sid(struct svc_rqst *rqstp)
-{
-       return NULL;
-}
-
 static inline void xprt_free_bc_request(struct rpc_rqst *req)
 {
 }
index 88513fd..d81db80 100644 (file)
@@ -212,6 +212,7 @@ struct rpc_task *rpc_run_task(const struct rpc_task_setup *);
 struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req,
                                const struct rpc_call_ops *ops);
 void           rpc_put_task(struct rpc_task *);
+void           rpc_put_task_async(struct rpc_task *);
 void           rpc_exit_task(struct rpc_task *);
 void           rpc_exit(struct rpc_task *, int);
 void           rpc_release_calldata(const struct rpc_call_ops *, void *);
index 059877b..7ad9751 100644 (file)
@@ -77,7 +77,6 @@ struct svc_xprt {
        size_t                  xpt_remotelen;  /* length of address */
        struct rpc_wait_queue   xpt_bc_pending; /* backchannel wait queue */
        struct list_head        xpt_users;      /* callbacks on free */
-       void                    *xpt_bc_sid;    /* back channel session ID */
 
        struct net              *xpt_net;
        struct rpc_xprt         *xpt_bc_xprt;   /* NFSv4.1 backchannel */
index 18cd068..1f5c18e 100644 (file)
@@ -62,6 +62,7 @@ struct robust_list_head;
 struct getcpu_cache;
 struct old_linux_dirent;
 struct perf_event_attr;
+struct file_handle;
 
 #include <linux/types.h>
 #include <linux/aio_abi.h>
@@ -125,62 +126,66 @@ extern struct trace_event_functions enter_syscall_print_funcs;
 extern struct trace_event_functions exit_syscall_print_funcs;
 
 #define SYSCALL_TRACE_ENTER_EVENT(sname)                               \
-       static struct syscall_metadata                                  \
-       __attribute__((__aligned__(4))) __syscall_meta_##sname;         \
+       static struct syscall_metadata __syscall_meta_##sname;          \
        static struct ftrace_event_call __used                          \
-         __attribute__((__aligned__(4)))                               \
-         __attribute__((section("_ftrace_events")))                    \
          event_enter_##sname = {                                       \
                .name                   = "sys_enter"#sname,            \
                .class                  = &event_class_syscall_enter,   \
                .event.funcs            = &enter_syscall_print_funcs,   \
                .data                   = (void *)&__syscall_meta_##sname,\
+               .flags                  = TRACE_EVENT_FL_CAP_ANY,       \
        };                                                              \
-       __TRACE_EVENT_FLAGS(enter_##sname, TRACE_EVENT_FL_CAP_ANY)
+       static struct ftrace_event_call __used                          \
+         __attribute__((section("_ftrace_events")))                    \
+        *__event_enter_##sname = &event_enter_##sname;
 
 #define SYSCALL_TRACE_EXIT_EVENT(sname)                                        \
-       static struct syscall_metadata                                  \
-       __attribute__((__aligned__(4))) __syscall_meta_##sname;         \
+       static struct syscall_metadata __syscall_meta_##sname;          \
        static struct ftrace_event_call __used                          \
-         __attribute__((__aligned__(4)))                               \
-         __attribute__((section("_ftrace_events")))                    \
          event_exit_##sname = {                                        \
                .name                   = "sys_exit"#sname,             \
                .class                  = &event_class_syscall_exit,    \
                .event.funcs            = &exit_syscall_print_funcs,    \
                .data                   = (void *)&__syscall_meta_##sname,\
+               .flags                  = TRACE_EVENT_FL_CAP_ANY,       \
        };                                                              \
-       __TRACE_EVENT_FLAGS(exit_##sname, TRACE_EVENT_FL_CAP_ANY)
+       static struct ftrace_event_call __used                          \
+         __attribute__((section("_ftrace_events")))                    \
+       *__event_exit_##sname = &event_exit_##sname;
 
 #define SYSCALL_METADATA(sname, nb)                            \
        SYSCALL_TRACE_ENTER_EVENT(sname);                       \
        SYSCALL_TRACE_EXIT_EVENT(sname);                        \
        static struct syscall_metadata __used                   \
-         __attribute__((__aligned__(4)))                       \
-         __attribute__((section("__syscalls_metadata")))       \
          __syscall_meta_##sname = {                            \
                .name           = "sys"#sname,                  \
+               .syscall_nr     = -1,   /* Filled in at boot */ \
                .nb_args        = nb,                           \
                .types          = types_##sname,                \
                .args           = args_##sname,                 \
                .enter_event    = &event_enter_##sname,         \
                .exit_event     = &event_exit_##sname,          \
                .enter_fields   = LIST_HEAD_INIT(__syscall_meta_##sname.enter_fields), \
-       };
+       };                                                      \
+       static struct syscall_metadata __used                   \
+         __attribute__((section("__syscalls_metadata")))       \
+        *__p_syscall_meta_##sname = &__syscall_meta_##sname;
 
 #define SYSCALL_DEFINE0(sname)                                 \
        SYSCALL_TRACE_ENTER_EVENT(_##sname);                    \
        SYSCALL_TRACE_EXIT_EVENT(_##sname);                     \
        static struct syscall_metadata __used                   \
-         __attribute__((__aligned__(4)))                       \
-         __attribute__((section("__syscalls_metadata")))       \
          __syscall_meta__##sname = {                           \
                .name           = "sys_"#sname,                 \
+               .syscall_nr     = -1,   /* Filled in at boot */ \
                .nb_args        = 0,                            \
                .enter_event    = &event_enter__##sname,        \
                .exit_event     = &event_exit__##sname,         \
                .enter_fields   = LIST_HEAD_INIT(__syscall_meta__##sname.enter_fields), \
        };                                                      \
+       static struct syscall_metadata __used                   \
+         __attribute__((section("__syscalls_metadata")))       \
+        *__p_syscall_meta_##sname = &__syscall_meta__##sname;  \
        asmlinkage long sys_##sname(void)
 #else
 #define SYSCALL_DEFINE0(name)     asmlinkage long sys_##name(void)
@@ -311,6 +316,8 @@ asmlinkage long sys_clock_settime(clockid_t which_clock,
                                const struct timespec __user *tp);
 asmlinkage long sys_clock_gettime(clockid_t which_clock,
                                struct timespec __user *tp);
+asmlinkage long sys_clock_adjtime(clockid_t which_clock,
+                               struct timex __user *tx);
 asmlinkage long sys_clock_getres(clockid_t which_clock,
                                struct timespec __user *tp);
 asmlinkage long sys_clock_nanosleep(clockid_t which_clock, int flags,
@@ -830,5 +837,10 @@ asmlinkage long sys_mmap_pgoff(unsigned long addr, unsigned long len,
                        unsigned long prot, unsigned long flags,
                        unsigned long fd, unsigned long pgoff);
 asmlinkage long sys_old_mmap(struct mmap_arg_struct __user *arg);
-
+asmlinkage long sys_name_to_handle_at(int dfd, const char __user *name,
+                                     struct file_handle __user *handle,
+                                     int __user *mnt_id, int flag);
+asmlinkage long sys_open_by_handle_at(int mountdirfd,
+                                     struct file_handle __user *handle,
+                                     int flags);
 #endif
index 7bb5cb6..11684d9 100644 (file)
@@ -930,6 +930,7 @@ enum
 
 #ifdef __KERNEL__
 #include <linux/list.h>
+#include <linux/rcupdate.h>
 
 /* For the /proc/sys support */
 struct ctl_table;
@@ -1037,10 +1038,15 @@ struct ctl_table_root {
    struct ctl_table trees. */
 struct ctl_table_header
 {
-       struct ctl_table *ctl_table;
-       struct list_head ctl_entry;
-       int used;
-       int count;
+       union {
+               struct {
+                       struct ctl_table *ctl_table;
+                       struct list_head ctl_entry;
+                       int used;
+                       int count;
+               };
+               struct rcu_head rcu;
+       };
        struct completion *unregistering;
        struct ctl_table *ctl_table_arg;
        struct ctl_table_root *root;
index 387fa7d..7faf933 100644 (file)
@@ -17,6 +17,9 @@
 #include <linux/errno.h>
 #include <linux/types.h>
 
+/* Enable/disable SYSRQ support by default (0==no, 1==yes). */
+#define SYSRQ_DEFAULT_ENABLE   1
+
 /* Possible values of bitmask for enabling sysrq functions */
 /* 0x0001 is reserved for enable everything */
 #define SYSRQ_ENABLE_LOG       0x0002
index 8651556..d3ec89f 100644 (file)
@@ -172,6 +172,14 @@ void thermal_zone_device_update(struct thermal_zone_device *);
 struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
                const struct thermal_cooling_device_ops *);
 void thermal_cooling_device_unregister(struct thermal_cooling_device *);
+
+#ifdef CONFIG_NET
 extern int generate_netlink_event(u32 orig, enum events event);
+#else
+static inline int generate_netlink_event(u32 orig, enum events event)
+{
+       return 0;
+}
+#endif
 
 #endif /* __THERMAL_H__ */
index c906965..20fc303 100644 (file)
@@ -18,9 +18,6 @@ struct compat_timespec;
 struct restart_block {
        long (*fn)(struct restart_block *);
        union {
-               struct {
-                       unsigned long arg0, arg1, arg2, arg3;
-               };
                /* For futex_wait and futex_wait_requeue_pi */
                struct {
                        u32 __user *uaddr;
index 1e6d3b5..454a262 100644 (file)
@@ -113,8 +113,6 @@ static inline struct timespec timespec_sub(struct timespec lhs,
 #define timespec_valid(ts) \
        (((ts)->tv_sec >= 0) && (((unsigned long) (ts)->tv_nsec) < NSEC_PER_SEC))
 
-extern seqlock_t xtime_lock;
-
 extern void read_persistent_clock(struct timespec *ts);
 extern void read_boot_clock(struct timespec *ts);
 extern int update_persistent_clock(struct timespec now);
@@ -125,8 +123,9 @@ extern int timekeeping_suspended;
 unsigned long get_seconds(void);
 struct timespec current_kernel_time(void);
 struct timespec __current_kernel_time(void); /* does not take xtime_lock */
-struct timespec __get_wall_to_monotonic(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);
 
 #define CURRENT_TIME           (current_kernel_time())
 #define CURRENT_TIME_SEC       ((struct timespec) { get_seconds(), 0 })
@@ -147,8 +146,9 @@ static inline u32 arch_gettimeoffset(void) { return 0; }
 #endif
 
 extern void do_gettimeofday(struct timeval *tv);
-extern int do_settimeofday(struct timespec *tv);
-extern int do_sys_settimeofday(struct timespec *tv, struct timezone *tz);
+extern int do_settimeofday(const struct timespec *tv);
+extern int do_sys_settimeofday(const struct timespec *tv,
+                              const struct timezone *tz);
 #define do_posix_clock_monotonic_gettime(ts) ktime_get_ts(ts)
 extern long do_utimes(int dfd, const char __user *filename, struct timespec *times, int flags);
 struct itimerval;
@@ -162,12 +162,13 @@ extern void getnstime_raw_and_real(struct timespec *ts_raw,
                struct timespec *ts_real);
 extern void getboottime(struct timespec *ts);
 extern void monotonic_to_bootbased(struct timespec *ts);
+extern void get_monotonic_boottime(struct timespec *ts);
 
 extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
 extern int timekeeping_valid_for_hres(void);
 extern u64 timekeeping_max_deferment(void);
-extern void update_wall_time(void);
 extern void timekeeping_leap_insert(int leapsecond);
+extern int timekeeping_inject_offset(struct timespec *ts);
 
 struct tms;
 extern void do_sys_times(struct tms *);
@@ -292,6 +293,7 @@ struct itimerval {
 #define CLOCK_MONOTONIC_RAW            4
 #define CLOCK_REALTIME_COARSE          5
 #define CLOCK_MONOTONIC_COARSE         6
+#define CLOCK_BOOTTIME                 7
 
 /*
  * The IDs of various hardware clocks:
index d23999f..aa60fe7 100644 (file)
@@ -73,7 +73,7 @@ struct timex {
        long tolerance;         /* clock frequency tolerance (ppm)
                                 * (read only)
                                 */
-       struct timeval time;    /* (read only) */
+       struct timeval time;    /* (read only, except for ADJ_SETOFFSET) */
        long tick;              /* (modified) usecs between clock ticks */
 
        long ppsfreq;           /* pps frequency (scaled ppm) (ro) */
@@ -102,6 +102,7 @@ struct timex {
 #define ADJ_STATUS             0x0010  /* clock status */
 #define ADJ_TIMECONST          0x0020  /* pll time constant */
 #define ADJ_TAI                        0x0080  /* set TAI offset */
+#define ADJ_SETOFFSET          0x0100  /* add 'time' to current time */
 #define ADJ_MICRO              0x1000  /* select microsecond resolution */
 #define ADJ_NANO               0x2000  /* select nanosecond resolution */
 #define ADJ_TICK               0x4000  /* tick value */
index c681461..97c84a5 100644 (file)
@@ -33,12 +33,7 @@ struct tracepoint {
        void (*regfunc)(void);
        void (*unregfunc)(void);
        struct tracepoint_func __rcu *funcs;
-} __attribute__((aligned(32)));                /*
-                                        * Aligned on 32 bytes because it is
-                                        * globally visible and gcc happily
-                                        * align these on the structure size.
-                                        * Keep in sync with vmlinux.lds.h.
-                                        */
+};
 
 /*
  * Connect a probe to a tracepoint.
@@ -61,15 +56,15 @@ extern void tracepoint_probe_update_all(void);
 
 struct tracepoint_iter {
        struct module *module;
-       struct tracepoint *tracepoint;
+       struct tracepoint * const *tracepoint;
 };
 
 extern void tracepoint_iter_start(struct tracepoint_iter *iter);
 extern void tracepoint_iter_next(struct tracepoint_iter *iter);
 extern void tracepoint_iter_stop(struct tracepoint_iter *iter);
 extern void tracepoint_iter_reset(struct tracepoint_iter *iter);
-extern int tracepoint_get_iter_range(struct tracepoint **tracepoint,
-       struct tracepoint *begin, struct tracepoint *end);
+extern int tracepoint_get_iter_range(struct tracepoint * const **tracepoint,
+       struct tracepoint * const *begin, struct tracepoint * const *end);
 
 /*
  * tracepoint_synchronize_unregister must be called between the last tracepoint
@@ -84,11 +79,13 @@ static inline void tracepoint_synchronize_unregister(void)
 #define PARAMS(args...) args
 
 #ifdef CONFIG_TRACEPOINTS
-extern void tracepoint_update_probe_range(struct tracepoint *begin,
-       struct tracepoint *end);
+extern
+void tracepoint_update_probe_range(struct tracepoint * const *begin,
+       struct tracepoint * const *end);
 #else
-static inline void tracepoint_update_probe_range(struct tracepoint *begin,
-       struct tracepoint *end)
+static inline
+void tracepoint_update_probe_range(struct tracepoint * const *begin,
+       struct tracepoint * const *end)
 { }
 #endif /* CONFIG_TRACEPOINTS */
 
@@ -174,12 +171,20 @@ do_trace:                                                         \
        {                                                               \
        }
 
+/*
+ * We have no guarantee that gcc and the linker won't up-align the tracepoint
+ * structures, so we create an array of pointers that will be used for iteration
+ * on the tracepoints.
+ */
 #define DEFINE_TRACE_FN(name, reg, unreg)                              \
        static const char __tpstrtab_##name[]                           \
        __attribute__((section("__tracepoints_strings"))) = #name;      \
        struct tracepoint __tracepoint_##name                           \
-       __attribute__((section("__tracepoints"), aligned(32))) =        \
-               { __tpstrtab_##name, 0, reg, unreg, NULL }
+       __attribute__((section("__tracepoints"))) =                     \
+               { __tpstrtab_##name, 0, reg, unreg, NULL };             \
+       static struct tracepoint * const __tracepoint_ptr_##name __used \
+       __attribute__((section("__tracepoints_ptrs"))) =                \
+               &__tracepoint_##name;
 
 #define DEFINE_TRACE(name)                                             \
        DEFINE_TRACE_FN(name, NULL, NULL);
index 5e86dc7..81a9279 100644 (file)
@@ -89,7 +89,7 @@ struct usb_cdc_acm_descriptor {
 
 #define USB_CDC_COMM_FEATURE   0x01
 #define USB_CDC_CAP_LINE       0x02
-#define USB_CDC_CAP_BRK        0x04
+#define USB_CDC_CAP_BRK                0x04
 #define USB_CDC_CAP_NOTIFY     0x08
 
 /* "Union Functional Descriptor" from CDC spec 5.2.3.8 */
@@ -271,6 +271,11 @@ struct usb_cdc_notification {
        __le16  wLength;
 } __attribute__ ((packed));
 
+struct usb_cdc_speed_change {
+       __le32  DLBitRRate;     /* contains the downlink bit rate (IN pipe) */
+       __le32  ULBitRate;      /* contains the uplink bit rate (OUT pipe) */
+} __attribute__ ((packed));
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -292,7 +297,7 @@ struct usb_cdc_ncm_ntb_parameters {
        __le16  wNdpOutDivisor;
        __le16  wNdpOutPayloadRemainder;
        __le16  wNdpOutAlignment;
-       __le16  wPadding2;
+       __le16  wNtbOutMaxDatagrams;
 } __attribute__ ((packed));
 
 /*
@@ -307,7 +312,7 @@ struct usb_cdc_ncm_nth16 {
        __le16  wHeaderLength;
        __le16  wSequence;
        __le16  wBlockLength;
-       __le16  wFpIndex;
+       __le16  wNdpIndex;
 } __attribute__ ((packed));
 
 struct usb_cdc_ncm_nth32 {
@@ -315,7 +320,7 @@ struct usb_cdc_ncm_nth32 {
        __le16  wHeaderLength;
        __le16  wSequence;
        __le32  dwBlockLength;
-       __le32  dwFpIndex;
+       __le32  dwNdpIndex;
 } __attribute__ ((packed));
 
 /*
@@ -337,7 +342,7 @@ struct usb_cdc_ncm_dpe16 {
 struct usb_cdc_ncm_ndp16 {
        __le32  dwSignature;
        __le16  wLength;
-       __le16  wNextFpIndex;
+       __le16  wNextNdpIndex;
        struct  usb_cdc_ncm_dpe16 dpe16[0];
 } __attribute__ ((packed));
 
@@ -375,6 +380,7 @@ struct usb_cdc_ncm_ndp32 {
 #define USB_CDC_NCM_NCAP_ENCAP_COMMAND                 (1 << 2)
 #define USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE             (1 << 3)
 #define USB_CDC_NCM_NCAP_CRC_MODE                      (1 << 4)
+#define        USB_CDC_NCM_NCAP_NTB_INPUT_SIZE                 (1 << 5)
 
 /* CDC NCM subclass Table 6-3: NTB Parameter Structure */
 #define USB_CDC_NCM_NTB16_SUPPORTED                    (1 << 0)
@@ -392,6 +398,13 @@ struct usb_cdc_ncm_ndp32 {
 #define USB_CDC_NCM_NTB_MIN_IN_SIZE                    2048
 #define USB_CDC_NCM_NTB_MIN_OUT_SIZE                   2048
 
+/* NTB Input Size Structure */
+struct usb_cdc_ncm_ndp_input_size {
+       __le32  dwNtbInMaxSize;
+       __le16  wNtbInMaxDatagrams;
+       __le16  wReserved;
+} __attribute__ ((packed));
+
 /* CDC NCM subclass 6.2.11 SetCrcMode */
 #define USB_CDC_NCM_CRC_NOT_APPENDED                   0x00
 #define USB_CDC_NCM_CRC_APPENDED                       0x01
index dd6ee49..a854fe8 100644 (file)
@@ -112,6 +112,7 @@ struct usb_hcd {
        /* Flags that get set only during HCD registration or removal. */
        unsigned                rh_registered:1;/* is root hub registered? */
        unsigned                rh_pollable:1;  /* may we poll the root hub? */
+       unsigned                msix_enabled:1; /* driver has MSI-X enabled? */
 
        /* The next flag is a stopgap, to be removed when all the HCDs
         * support the new root-hub polling mechanism. */
index b92e173..7d1babb 100644 (file)
 #ifndef __LINUX_USB_GADGET_MSM72K_UDC_H__
 #define __LINUX_USB_GADGET_MSM72K_UDC_H__
 
-#ifdef CONFIG_ARCH_MSM7X00A
-#define USB_SBUSCFG          (MSM_USB_BASE + 0x0090)
-#else
 #define USB_AHBBURST         (MSM_USB_BASE + 0x0090)
 #define USB_AHBMODE          (MSM_USB_BASE + 0x0098)
-#endif
 #define USB_CAPLENGTH        (MSM_USB_BASE + 0x0100) /* 8 bit */
 
 #define USB_USBCMD           (MSM_USB_BASE + 0x0140)
index 16d682f..c904913 100644 (file)
@@ -347,6 +347,9 @@ extern int usb_serial_generic_prepare_write_buffer(struct usb_serial_port *port,
 extern int usb_serial_handle_sysrq_char(struct usb_serial_port *port,
                                        unsigned int ch);
 extern int usb_serial_handle_break(struct usb_serial_port *port);
+extern void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port,
+                                        struct tty_struct *tty,
+                                        unsigned int status);
 
 
 extern int usb_serial_bus_register(struct usb_serial_driver *device);
index a85064d..e4d3335 100644 (file)
@@ -7,7 +7,8 @@
  * This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
  * anyone can use the definitions to implement compatible drivers/servers.
  *
- * Copyright (C) Red Hat, Inc., 2009, 2010
+ * Copyright (C) Red Hat, Inc., 2009, 2010, 2011
+ * Copyright (C) Amit Shah <amit.shah@redhat.com>, 2009, 2010, 2011
  */
 
 /* Feature bits */
index 1ac1158..f584aba 100644 (file)
@@ -250,7 +250,7 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
 enum {
        WQ_NON_REENTRANT        = 1 << 0, /* guarantee non-reentrance */
        WQ_UNBOUND              = 1 << 1, /* not bound to any cpu */
-       WQ_FREEZEABLE           = 1 << 2, /* freeze during suspend */
+       WQ_FREEZABLE            = 1 << 2, /* freeze during suspend */
        WQ_MEM_RECLAIM          = 1 << 3, /* may be used for memory reclaim */
        WQ_HIGHPRI              = 1 << 4, /* high priority */
        WQ_CPU_INTENSIVE        = 1 << 5, /* cpu instensive workqueue */
@@ -286,11 +286,15 @@ enum {
  * any specific CPU, not concurrency managed, and all queued works are
  * executed immediately as long as max_active limit is not reached and
  * resources are available.
+ *
+ * system_freezable_wq is equivalent to system_wq except that it's
+ * freezable.
  */
 extern struct workqueue_struct *system_wq;
 extern struct workqueue_struct *system_long_wq;
 extern struct workqueue_struct *system_nrt_wq;
 extern struct workqueue_struct *system_unbound_wq;
+extern struct workqueue_struct *system_freezable_wq;
 
 extern struct workqueue_struct *
 __alloc_workqueue_key(const char *name, unsigned int flags, int max_active,
@@ -318,7 +322,7 @@ __alloc_workqueue_key(const char *name, unsigned int flags, int max_active,
 /**
  * alloc_ordered_workqueue - allocate an ordered workqueue
  * @name: name of the workqueue
- * @flags: WQ_* flags (only WQ_FREEZEABLE and WQ_MEM_RECLAIM are meaningful)
+ * @flags: WQ_* flags (only WQ_FREEZABLE and WQ_MEM_RECLAIM are meaningful)
  *
  * Allocate an ordered workqueue.  An ordered workqueue executes at
  * most one work item at any given time in the queued order.  They are
@@ -335,8 +339,8 @@ alloc_ordered_workqueue(const char *name, unsigned int flags)
 
 #define create_workqueue(name)                                 \
        alloc_workqueue((name), WQ_MEM_RECLAIM, 1)
-#define create_freezeable_workqueue(name)                      \
-       alloc_workqueue((name), WQ_FREEZEABLE | WQ_UNBOUND | WQ_MEM_RECLAIM, 1)
+#define create_freezable_workqueue(name)                       \
+       alloc_workqueue((name), WQ_FREEZABLE | WQ_UNBOUND | WQ_MEM_RECLAIM, 1)
 #define create_singlethread_workqueue(name)                    \
        alloc_workqueue((name), WQ_UNBOUND | WQ_MEM_RECLAIM, 1)
 
index a29feb0..d2cf884 100644 (file)
@@ -184,6 +184,7 @@ struct hci_conn {
        __u32            link_mode;
        __u8             auth_type;
        __u8             sec_level;
+       __u8             pending_sec_level;
        __u8             power_save;
        __u16            disc_timeout;
        unsigned long    pend;
index 8a64b81..b4c7c1c 100644 (file)
@@ -195,7 +195,8 @@ static inline int genlmsg_end(struct sk_buff *skb, void *hdr)
  */
 static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr)
 {
-       nlmsg_cancel(skb, hdr - GENL_HDRLEN - NLMSG_HDRLEN);
+       if (hdr)
+               nlmsg_cancel(skb, hdr - GENL_HDRLEN - NLMSG_HDRLEN);
 }
 
 /**
index 4a3cd2c..96e50e0 100644 (file)
 #define IPV6_ADDR_SCOPE_ORGLOCAL       0x08
 #define IPV6_ADDR_SCOPE_GLOBAL         0x0e
 
+/*
+ *     Addr flags
+ */
+#ifdef __KERNEL__
+#define IPV6_ADDR_MC_FLAG_TRANSIENT(a) \
+       ((a)->s6_addr[1] & 0x10)
+#define IPV6_ADDR_MC_FLAG_PREFIX(a)    \
+       ((a)->s6_addr[1] & 0x20)
+#define IPV6_ADDR_MC_FLAG_RENDEZVOUS(a)        \
+       ((a)->s6_addr[1] & 0x40)
+#endif
+
 /*
  *     fragmentation header
  */
index 96ba5f7..349cefe 100644 (file)
@@ -77,9 +77,6 @@ nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct)
        if (e == NULL)
                return;
 
-       if (!(e->ctmask & (1 << event)))
-               return;
-
        set_bit(event, &e->cache);
 }
 
index cd85b3b..e505358 100644 (file)
@@ -201,18 +201,8 @@ nf_tproxy_get_sock_v6(struct net *net, const u8 protocol,
 }
 #endif
 
-static inline void
-nf_tproxy_put_sock(struct sock *sk)
-{
-       /* TIME_WAIT inet sockets have to be handled differently */
-       if ((sk->sk_protocol == IPPROTO_TCP) && (sk->sk_state == TCP_TIME_WAIT))
-               inet_twsk_put(inet_twsk(sk));
-       else
-               sock_put(sk);
-}
-
 /* assign a socket to the skb -- consumes sk */
-int
+void
 nf_tproxy_assign_sock(struct sk_buff *skb, struct sock *sk);
 
 #endif
index e9eee99..04f8556 100644 (file)
@@ -199,7 +199,7 @@ struct tcf_proto {
 
 struct qdisc_skb_cb {
        unsigned int            pkt_len;
-       char                    data[];
+       long                    data[];
 };
 
 static inline int qdisc_qlen(struct Qdisc *q)
@@ -445,7 +445,6 @@ static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch,
 {
        __skb_queue_tail(list, skb);
        sch->qstats.backlog += qdisc_pkt_len(skb);
-       qdisc_bstats_update(sch, skb);
 
        return NET_XMIT_SUCCESS;
 }
@@ -460,8 +459,10 @@ static inline struct sk_buff *__qdisc_dequeue_head(struct Qdisc *sch,
 {
        struct sk_buff *skb = __skb_dequeue(list);
 
-       if (likely(skb != NULL))
+       if (likely(skb != NULL)) {
                sch->qstats.backlog -= qdisc_pkt_len(skb);
+               qdisc_bstats_update(sch, skb);
+       }
 
        return skb;
 }
@@ -474,10 +475,11 @@ static inline struct sk_buff *qdisc_dequeue_head(struct Qdisc *sch)
 static inline unsigned int __qdisc_queue_drop_head(struct Qdisc *sch,
                                              struct sk_buff_head *list)
 {
-       struct sk_buff *skb = __qdisc_dequeue_head(sch, list);
+       struct sk_buff *skb = __skb_dequeue(list);
 
        if (likely(skb != NULL)) {
                unsigned int len = qdisc_pkt_len(skb);
+               sch->qstats.backlog -= len;
                kfree_skb(skb);
                return len;
        }
index d884d26..bc1cf7d 100644 (file)
@@ -753,6 +753,8 @@ struct proto {
                                        int level,
                                        int optname, char __user *optval,
                                        int __user *option);
+       int                     (*compat_ioctl)(struct sock *sk,
+                                       unsigned int cmd, unsigned long arg);
 #endif
        int                     (*sendmsg)(struct kiocb *iocb, struct sock *sk,
                                           struct msghdr *msg, size_t len);
index 8479b66..3fd5064 100644 (file)
@@ -261,6 +261,7 @@ void pcmcia_disable_device(struct pcmcia_device *p_dev);
 #define CONF_ENABLE_ESR         0x0008
 #define CONF_ENABLE_IOCARD     0x0010 /* auto-enabled if IO resources or IRQ
                                        * (CONF_ENABLE_IRQ) in use */
+#define CONF_ENABLE_ZVCARD     0x0020
 
 /* flags used by pcmcia_loop_config() autoconfiguration */
 #define CONF_AUTO_CHECK_VCC    0x0100 /* check for matching Vcc? */
index 648d233..b76d400 100644 (file)
@@ -9,6 +9,7 @@
 #define _SCSI_SCSI_H
 
 #include <linux/types.h>
+#include <linux/scatterlist.h>
 
 struct scsi_cmnd;
 
index b4a0db2..1eeebd5 100644 (file)
 /*
  * R6 (0x06) - Mic Bias Control 0
  */
-#define WM8903_MICDET_HYST_ENA                  0x0080  /* MICDET_HYST_ENA */
-#define WM8903_MICDET_HYST_ENA_MASK             0x0080  /* MICDET_HYST_ENA */
-#define WM8903_MICDET_HYST_ENA_SHIFT                 7  /* MICDET_HYST_ENA */
-#define WM8903_MICDET_HYST_ENA_WIDTH                 1  /* MICDET_HYST_ENA */
-#define WM8903_MICDET_THR_MASK                  0x0070  /* MICDET_THR - [6:4] */
-#define WM8903_MICDET_THR_SHIFT                      4  /* MICDET_THR - [6:4] */
-#define WM8903_MICDET_THR_WIDTH                      3  /* MICDET_THR - [6:4] */
+#define WM8903_MICDET_THR_MASK                  0x0030  /* MICDET_THR - [5:4] */
+#define WM8903_MICDET_THR_SHIFT                      4  /* MICDET_THR - [5:4] */
+#define WM8903_MICDET_THR_WIDTH                      2  /* MICDET_THR - [5:4] */
 #define WM8903_MICSHORT_THR_MASK                0x000C  /* MICSHORT_THR - [3:2] */
 #define WM8903_MICSHORT_THR_SHIFT                    2  /* MICSHORT_THR - [3:2] */
 #define WM8903_MICSHORT_THR_WIDTH                    2  /* MICSHORT_THR - [3:2] */
index 07fdfb6..0828b6c 100644 (file)
@@ -8,7 +8,6 @@
 #include <scsi/scsi_cmnd.h>
 #include <net/sock.h>
 #include <net/tcp.h>
-#include "target_core_mib.h"
 
 #define TARGET_CORE_MOD_VERSION                "v4.0.0-rc6"
 #define SHUTDOWN_SIGS  (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGABRT))
@@ -195,6 +194,21 @@ typedef enum {
        SAM_TASK_ATTR_EMULATED
 } t10_task_attr_index_t;
 
+/*
+ * Used for target SCSI statistics
+ */
+typedef enum {
+       SCSI_INST_INDEX,
+       SCSI_DEVICE_INDEX,
+       SCSI_AUTH_INTR_INDEX,
+       SCSI_INDEX_TYPE_MAX
+} scsi_index_t;
+
+struct scsi_index_table {
+       spinlock_t      lock;
+       u32             scsi_mib_index[SCSI_INDEX_TYPE_MAX];
+} ____cacheline_aligned;
+
 struct se_cmd;
 
 struct t10_alua {
@@ -578,8 +592,6 @@ struct se_node_acl {
        spinlock_t              stats_lock;
        /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */
        atomic_t                acl_pr_ref_count;
-       /* Used for MIB access */
-       atomic_t                mib_ref_count;
        struct se_dev_entry     *device_list;
        struct se_session       *nacl_sess;
        struct se_portal_group *se_tpg;
@@ -595,8 +607,6 @@ struct se_node_acl {
 } ____cacheline_aligned;
 
 struct se_session {
-       /* Used for MIB access */
-       atomic_t                mib_ref_count;
        u64                     sess_bin_isid;
        struct se_node_acl      *se_node_acl;
        struct se_portal_group *se_tpg;
@@ -806,7 +816,6 @@ struct se_hba {
        /* Virtual iSCSI devices attached. */
        u32                     dev_count;
        u32                     hba_index;
-       atomic_t                dev_mib_access_count;
        atomic_t                load_balance_queue;
        atomic_t                left_queue_depth;
        /* Maximum queue depth the HBA can handle. */
@@ -845,6 +854,12 @@ struct se_lun {
 
 #define SE_LUN(c)              ((struct se_lun *)(c)->se_lun)
 
+struct scsi_port_stats {
+       u64     cmd_pdus;
+       u64     tx_data_octets;
+       u64     rx_data_octets;
+} ____cacheline_aligned;
+
 struct se_port {
        /* RELATIVE TARGET PORT IDENTIFER */
        u16             sep_rtpi;
@@ -867,6 +882,7 @@ struct se_port {
 } ____cacheline_aligned;
 
 struct se_tpg_np {
+       struct se_portal_group *tpg_np_parent;
        struct config_group     tpg_np_group;
 } ____cacheline_aligned;
 
index 66f44e5..2e8ec51 100644 (file)
@@ -111,6 +111,8 @@ struct se_subsystem_api;
 
 extern int init_se_global(void);
 extern void release_se_global(void);
+extern void init_scsi_index_table(void);
+extern u32 scsi_get_new_index(scsi_index_t);
 extern void transport_init_queue_obj(struct se_queue_obj *);
 extern int transport_subsystem_check_init(void);
 extern int transport_subsystem_register(struct se_subsystem_api *);
@@ -133,6 +135,8 @@ extern void transport_complete_task(struct se_task *, int);
 extern void transport_add_task_to_execute_queue(struct se_task *,
                                                struct se_task *,
                                                struct se_device *);
+extern void transport_remove_task_from_execute_queue(struct se_task *,
+                                               struct se_device *);
 unsigned char *transport_dump_cmd_direction(struct se_cmd *);
 extern void transport_dump_dev_state(struct se_device *, char *, int *);
 extern void transport_dump_dev_info(struct se_device *, struct se_lun *,
index aba421d..78f18ad 100644 (file)
@@ -31,7 +31,7 @@ DECLARE_EVENT_CLASS(block_rq_with_error,
                                        0 : blk_rq_sectors(rq);
                __entry->errors    = rq->errors;
 
-               blk_fill_rwbs_rq(__entry->rwbs, rq);
+               blk_fill_rwbs(__entry->rwbs, rq->cmd_flags, blk_rq_bytes(rq));
                blk_dump_cmd(__get_str(cmd), rq);
        ),
 
@@ -118,7 +118,7 @@ DECLARE_EVENT_CLASS(block_rq,
                __entry->bytes     = (rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
                                        blk_rq_bytes(rq) : 0;
 
-               blk_fill_rwbs_rq(__entry->rwbs, rq);
+               blk_fill_rwbs(__entry->rwbs, rq->cmd_flags, blk_rq_bytes(rq));
                blk_dump_cmd(__get_str(cmd), rq);
                memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
        ),
@@ -563,7 +563,7 @@ TRACE_EVENT(block_rq_remap,
                __entry->nr_sector      = blk_rq_sectors(rq);
                __entry->old_dev        = dev;
                __entry->old_sector     = from;
-               blk_fill_rwbs_rq(__entry->rwbs, rq);
+               blk_fill_rwbs(__entry->rwbs, rq->cmd_flags, blk_rq_bytes(rq));
        ),
 
        TP_printk("%d,%d %s %llu + %u <- (%d,%d) %llu",
index 7eee778..4cbbcef 100644 (file)
@@ -17,36 +17,36 @@ TRACE_EVENT(mce_record,
        TP_STRUCT__entry(
                __field(        u64,            mcgcap          )
                __field(        u64,            mcgstatus       )
-               __field(        u8,             bank            )
                __field(        u64,            status          )
                __field(        u64,            addr            )
                __field(        u64,            misc            )
                __field(        u64,            ip              )
-               __field(        u8,             cs              )
                __field(        u64,            tsc             )
                __field(        u64,            walltime        )
                __field(        u32,            cpu             )
                __field(        u32,            cpuid           )
                __field(        u32,            apicid          )
                __field(        u32,            socketid        )
+               __field(        u8,             cs              )
+               __field(        u8,             bank            )
                __field(        u8,             cpuvendor       )
        ),
 
        TP_fast_assign(
                __entry->mcgcap         = m->mcgcap;
                __entry->mcgstatus      = m->mcgstatus;
-               __entry->bank           = m->bank;
                __entry->status         = m->status;
                __entry->addr           = m->addr;
                __entry->misc           = m->misc;
                __entry->ip             = m->ip;
-               __entry->cs             = m->cs;
                __entry->tsc            = m->tsc;
                __entry->walltime       = m->time;
                __entry->cpu            = m->extcpu;
                __entry->cpuid          = m->cpuid;
                __entry->apicid         = m->apicid;
                __entry->socketid       = m->socketid;
+               __entry->cs             = m->cs;
+               __entry->bank           = m->bank;
                __entry->cpuvendor      = m->cpuvendor;
        ),
 
index c6bae36..21a546d 100644 (file)
@@ -108,14 +108,14 @@ TRACE_EVENT(module_request,
        TP_ARGS(name, wait, ip),
 
        TP_STRUCT__entry(
-               __field(        bool,           wait            )
                __field(        unsigned long,  ip              )
+               __field(        bool,           wait            )
                __string(       name,           name            )
        ),
 
        TP_fast_assign(
-               __entry->wait   = wait;
                __entry->ip     = ip;
+               __entry->wait   = wait;
                __assign_str(name, name);
        ),
 
@@ -129,4 +129,3 @@ TRACE_EVENT(module_request,
 
 /* This part must be outside protection */
 #include <trace/define_trace.h>
-
index f10293c..0c68ae2 100644 (file)
@@ -19,14 +19,14 @@ TRACE_EVENT(kfree_skb,
 
        TP_STRUCT__entry(
                __field(        void *,         skbaddr         )
-               __field(        unsigned short, protocol        )
                __field(        void *,         location        )
+               __field(        unsigned short, protocol        )
        ),
 
        TP_fast_assign(
                __entry->skbaddr = skb;
-               __entry->protocol = ntohs(skb->protocol);
                __entry->location = location;
+               __entry->protocol = ntohs(skb->protocol);
        ),
 
        TP_printk("skbaddr=%p protocol=%u location=%p",
index e16610c..3e68366 100644 (file)
@@ -446,14 +446,16 @@ static inline notrace int ftrace_get_offsets_##call(                      \
  *     .reg                    = ftrace_event_reg,
  * };
  *
- * static struct ftrace_event_call __used
- * __attribute__((__aligned__(4)))
- * __attribute__((section("_ftrace_events"))) event_<call> = {
+ * static struct ftrace_event_call event_<call> = {
  *     .name                   = "<call>",
  *     .class                  = event_class_<template>,
  *     .event                  = &ftrace_event_type_<call>,
  *     .print_fmt              = print_fmt_<call>,
  * };
+ * // its only safe to use pointers when doing linker tricks to
+ * // create an array.
+ * static struct ftrace_event_call __used
+ * __attribute__((section("_ftrace_events"))) *__event_<call> = &event_<call>;
  *
  */
 
@@ -579,28 +581,28 @@ static struct ftrace_event_class __used event_class_##call = {            \
 #undef DEFINE_EVENT
 #define DEFINE_EVENT(template, call, proto, args)                      \
                                                                        \
-static struct ftrace_event_call __used                                 \
-__attribute__((__aligned__(4)))                                                \
-__attribute__((section("_ftrace_events"))) event_##call = {            \
+static struct ftrace_event_call __used event_##call = {                        \
        .name                   = #call,                                \
        .class                  = &event_class_##template,              \
        .event.funcs            = &ftrace_event_type_funcs_##template,  \
        .print_fmt              = print_fmt_##template,                 \
-};
+};                                                                     \
+static struct ftrace_event_call __used                                 \
+__attribute__((section("_ftrace_events"))) *__event_##call = &event_##call
 
 #undef DEFINE_EVENT_PRINT
 #define DEFINE_EVENT_PRINT(template, call, proto, args, print)         \
                                                                        \
 static const char print_fmt_##call[] = print;                          \
                                                                        \
-static struct ftrace_event_call __used                                 \
-__attribute__((__aligned__(4)))                                                \
-__attribute__((section("_ftrace_events"))) event_##call = {            \
+static struct ftrace_event_call __used event_##call = {                        \
        .name                   = #call,                                \
        .class                  = &event_class_##template,              \
        .event.funcs            = &ftrace_event_type_funcs_##call,      \
        .print_fmt              = print_fmt_##call,                     \
-}
+};                                                                     \
+static struct ftrace_event_call __used                                 \
+__attribute__((section("_ftrace_events"))) *__event_##call = &event_##call
 
 #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
 
index 00f53dd..962da2c 100644 (file)
@@ -75,11 +75,9 @@ int xen_allocate_pirq(unsigned gsi, int shareable, char *name);
 int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name);
 
 #ifdef CONFIG_PCI_MSI
-/* Allocate an irq and a pirq to be used with MSIs. */
-#define XEN_ALLOC_PIRQ (1 << 0)
-#define XEN_ALLOC_IRQ  (1 << 1)
-void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc_mask);
-int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type);
+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);
 #endif
 
 /* De-allocates the above mentioned physical interrupt. */
index c2d1fa4..61e523a 100644 (file)
@@ -51,11 +51,7 @@ typedef uint64_t blkif_sector_t;
  */
 #define BLKIF_MAX_SEGMENTS_PER_REQUEST 11
 
-struct blkif_request {
-       uint8_t        operation;    /* BLKIF_OP_???                         */
-       uint8_t        nr_segments;  /* number of segments                   */
-       blkif_vdev_t   handle;       /* only for read/write requests         */
-       uint64_t       id;           /* private guest value, echoed in resp  */
+struct blkif_request_rw {
        blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
        struct blkif_request_segment {
                grant_ref_t gref;        /* reference to I/O buffer frame        */
@@ -65,6 +61,16 @@ struct blkif_request {
        } seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
 };
 
+struct blkif_request {
+       uint8_t        operation;    /* BLKIF_OP_???                         */
+       uint8_t        nr_segments;  /* number of segments                   */
+       blkif_vdev_t   handle;       /* only for read/write requests         */
+       uint64_t       id;           /* private guest value, echoed in resp  */
+       union {
+               struct blkif_request_rw rw;
+       } u;
+};
+
 struct blkif_response {
        uint64_t        id;              /* copied from request */
        uint8_t         operation;       /* copied from request */
@@ -91,4 +97,25 @@ DEFINE_RING_TYPES(blkif, struct blkif_request, struct blkif_response);
 #define VDISK_REMOVABLE    0x2
 #define VDISK_READONLY     0x4
 
+/* Xen-defined major numbers for virtual disks, they look strangely
+ * familiar */
+#define XEN_IDE0_MAJOR 3
+#define XEN_IDE1_MAJOR 22
+#define XEN_SCSI_DISK0_MAJOR   8
+#define XEN_SCSI_DISK1_MAJOR   65
+#define XEN_SCSI_DISK2_MAJOR   66
+#define XEN_SCSI_DISK3_MAJOR   67
+#define XEN_SCSI_DISK4_MAJOR   68
+#define XEN_SCSI_DISK5_MAJOR   69
+#define XEN_SCSI_DISK6_MAJOR   70
+#define XEN_SCSI_DISK7_MAJOR   71
+#define XEN_SCSI_DISK8_MAJOR   128
+#define XEN_SCSI_DISK9_MAJOR   129
+#define XEN_SCSI_DISK10_MAJOR  130
+#define XEN_SCSI_DISK11_MAJOR  131
+#define XEN_SCSI_DISK12_MAJOR  132
+#define XEN_SCSI_DISK13_MAJOR  133
+#define XEN_SCSI_DISK14_MAJOR  134
+#define XEN_SCSI_DISK15_MAJOR  135
+
 #endif /* __XEN_PUBLIC_IO_BLKIF_H__ */
index 2befa3e..b33257b 100644 (file)
@@ -30,7 +30,7 @@
 #define __HYPERVISOR_stack_switch          3
 #define __HYPERVISOR_set_callbacks         4
 #define __HYPERVISOR_fpu_taskswitch        5
-#define __HYPERVISOR_sched_op              6
+#define __HYPERVISOR_sched_op_compat       6
 #define __HYPERVISOR_dom0_op               7
 #define __HYPERVISOR_set_debugreg          8
 #define __HYPERVISOR_get_debugreg          9
@@ -52,7 +52,7 @@
 #define __HYPERVISOR_mmuext_op            26
 #define __HYPERVISOR_acm_op               27
 #define __HYPERVISOR_nmi_op               28
-#define __HYPERVISOR_sched_op_new         29
+#define __HYPERVISOR_sched_op             29
 #define __HYPERVISOR_callback_op          30
 #define __HYPERVISOR_xenoprof_op          31
 #define __HYPERVISOR_event_channel_op     32
index 98b9215..03c85d7 100644 (file)
@@ -5,9 +5,9 @@
 
 DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu);
 
-void xen_pre_suspend(void);
-void xen_post_suspend(int suspend_cancelled);
-void xen_hvm_post_suspend(int suspend_cancelled);
+void xen_arch_pre_suspend(void);
+void xen_arch_post_suspend(int suspend_cancelled);
+void xen_arch_hvm_post_suspend(int suspend_cancelled);
 
 void xen_mm_pin_all(void);
 void xen_mm_unpin_all(void);
index be788c0..5721d27 100644 (file)
@@ -287,6 +287,18 @@ config BSD_PROCESS_ACCT_V3
          for processing it. A preliminary version of these tools is available
          at <http://www.gnu.org/software/acct/>.
 
+config FHANDLE
+       bool "open by fhandle syscalls"
+       select EXPORTFS
+       help
+         If you say Y here, a user level program will be able to map
+         file names to handle and then later use the handle for
+         different file system operations. This is useful in implementing
+         userspace file servers, which now track files using handles instead
+         of names. The handle would remain the same even if file names
+         get renamed. Enables open_by_handle_at(2) and name_to_handle_at(2)
+         syscalls.
+
 config TASKSTATS
        bool "Export task/process statistics through netlink (EXPERIMENTAL)"
        depends on NET
@@ -683,6 +695,16 @@ config CGROUP_MEM_RES_CTLR_SWAP_ENABLED
          select this option (if, for some reason, they need to disable it
          then noswapaccount does the trick).
 
+config CGROUP_PERF
+       bool "Enable perf_event per-cpu per-container group (cgroup) monitoring"
+       depends on PERF_EVENTS && CGROUPS
+       help
+         This option extends the per-cpu mode to restrict monitoring to
+         threads which belong to the cgroup specified and run on the
+         designated cpu.
+
+         Say N if unsure.
+
 menuconfig CGROUP_SCHED
        bool "Group CPU scheduler"
        depends on EXPERIMENTAL
index 6eb48e5..24fe022 100644 (file)
@@ -66,7 +66,7 @@ static unsigned long __cpuinit calibrate_delay_direct(void)
                pre_start = 0;
                read_current_timer(&start);
                start_jiffies = jiffies;
-               while (jiffies <= (start_jiffies + 1)) {
+               while (time_before_eq(jiffies, start_jiffies + 1)) {
                        pre_start = start;
                        read_current_timer(&start);
                }
@@ -74,8 +74,8 @@ static unsigned long __cpuinit calibrate_delay_direct(void)
 
                pre_end = 0;
                end = post_start;
-               while (jiffies <=
-                      (start_jiffies + 1 + DELAY_CALIBRATION_TICKS)) {
+               while (time_before_eq(jiffies, start_jiffies + 1 +
+                                              DELAY_CALIBRATION_TICKS)) {
                        pre_end = end;
                        read_current_timer(&end);
                }
index d2e3c78..e683869 100644 (file)
@@ -144,9 +144,9 @@ int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev)
 }
 
 /* Initialize a parent watch entry. */
-static struct audit_parent *audit_init_parent(struct nameidata *ndp)
+static struct audit_parent *audit_init_parent(struct path *path)
 {
-       struct inode *inode = ndp->path.dentry->d_inode;
+       struct inode *inode = path->dentry->d_inode;
        struct audit_parent *parent;
        int ret;
 
@@ -353,53 +353,40 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
 }
 
 /* Get path information necessary for adding watches. */
-static int audit_get_nd(char *path, struct nameidata **ndp, struct nameidata **ndw)
+static int audit_get_nd(struct audit_watch *watch, struct path *parent)
 {
-       struct nameidata *ndparent, *ndwatch;
+       struct nameidata nd;
+       struct dentry *d;
        int err;
 
-       ndparent = kmalloc(sizeof(*ndparent), GFP_KERNEL);
-       if (unlikely(!ndparent))
-               return -ENOMEM;
+       err = kern_path_parent(watch->path, &nd);
+       if (err)
+               return err;
 
-       ndwatch = kmalloc(sizeof(*ndwatch), GFP_KERNEL);
-       if (unlikely(!ndwatch)) {
-               kfree(ndparent);
-               return -ENOMEM;
+       if (nd.last_type != LAST_NORM) {
+               path_put(&nd.path);
+               return -EINVAL;
        }
 
-       err = path_lookup(path, LOOKUP_PARENT, ndparent);
-       if (err) {
-               kfree(ndparent);
-               kfree(ndwatch);
-               return err;
+       mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
+       d = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
+       if (IS_ERR(d)) {
+               mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+               path_put(&nd.path);
+               return PTR_ERR(d);
        }
-
-       err = path_lookup(path, 0, ndwatch);
-       if (err) {
-               kfree(ndwatch);
-               ndwatch = NULL;
+       if (d->d_inode) {
+               /* update watch filter fields */
+               watch->dev = d->d_inode->i_sb->s_dev;
+               watch->ino = d->d_inode->i_ino;
        }
+       mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
 
-       *ndp = ndparent;
-       *ndw = ndwatch;
-
+       *parent = nd.path;
+       dput(d);
        return 0;
 }
 
-/* Release resources used for watch path information. */
-static void audit_put_nd(struct nameidata *ndp, struct nameidata *ndw)
-{
-       if (ndp) {
-               path_put(&ndp->path);
-               kfree(ndp);
-       }
-       if (ndw) {
-               path_put(&ndw->path);
-               kfree(ndw);
-       }
-}
-
 /* Associate the given rule with an existing parent.
  * Caller must hold audit_filter_mutex. */
 static void audit_add_to_parent(struct audit_krule *krule,
@@ -440,31 +427,24 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list)
 {
        struct audit_watch *watch = krule->watch;
        struct audit_parent *parent;
-       struct nameidata *ndp = NULL, *ndw = NULL;
+       struct path parent_path;
        int h, ret = 0;
 
        mutex_unlock(&audit_filter_mutex);
 
        /* Avoid calling path_lookup under audit_filter_mutex. */
-       ret = audit_get_nd(watch->path, &ndp, &ndw);
-       if (ret) {
-               /* caller expects mutex locked */
-               mutex_lock(&audit_filter_mutex);
-               goto error;
-       }
+       ret = audit_get_nd(watch, &parent_path);
 
+       /* caller expects mutex locked */
        mutex_lock(&audit_filter_mutex);
 
-       /* update watch filter fields */
-       if (ndw) {
-               watch->dev = ndw->path.dentry->d_inode->i_sb->s_dev;
-               watch->ino = ndw->path.dentry->d_inode->i_ino;
-       }
+       if (ret)
+               return ret;
 
        /* either find an old parent or attach a new one */
-       parent = audit_find_parent(ndp->path.dentry->d_inode);
+       parent = audit_find_parent(parent_path.dentry->d_inode);
        if (!parent) {
-               parent = audit_init_parent(ndp);
+               parent = audit_init_parent(&parent_path);
                if (IS_ERR(parent)) {
                        ret = PTR_ERR(parent);
                        goto error;
@@ -479,9 +459,8 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list)
        h = audit_hash_ino((u32)watch->ino);
        *list = &audit_inode_hash[h];
 error:
-       audit_put_nd(ndp, ndw);         /* NULL args OK */
+       path_put(&parent_path);
        return ret;
-
 }
 
 void audit_remove_watch_rule(struct audit_krule *krule)
index 2f05303..9e9385f 100644 (file)
@@ -306,7 +306,7 @@ int capable(int cap)
                BUG();
        }
 
-       if (security_capable(cap) == 0) {
+       if (security_capable(current_cred(), cap) == 0) {
                current->flags |= PF_SUPERPRIV;
                return 1;
        }
index b24d702..95362d1 100644 (file)
@@ -4230,20 +4230,8 @@ void cgroup_post_fork(struct task_struct *child)
  */
 void cgroup_exit(struct task_struct *tsk, int run_callbacks)
 {
-       int i;
        struct css_set *cg;
-
-       if (run_callbacks && need_forkexit_callback) {
-               /*
-                * modular subsystems can't use callbacks, so no need to lock
-                * the subsys array
-                */
-               for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
-                       struct cgroup_subsys *ss = subsys[i];
-                       if (ss->exit)
-                               ss->exit(ss, tsk);
-               }
-       }
+       int i;
 
        /*
         * Unlink from the css_set task list if necessary.
@@ -4261,7 +4249,24 @@ void cgroup_exit(struct task_struct *tsk, int run_callbacks)
        task_lock(tsk);
        cg = tsk->cgroups;
        tsk->cgroups = &init_css_set;
+
+       if (run_callbacks && need_forkexit_callback) {
+               /*
+                * modular subsystems can't use callbacks, so no need to lock
+                * the subsys array
+                */
+               for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
+                       struct cgroup_subsys *ss = subsys[i];
+                       if (ss->exit) {
+                               struct cgroup *old_cgrp =
+                                       rcu_dereference_raw(cg->subsys[i])->cgroup;
+                               struct cgroup *cgrp = task_cgroup(tsk, i);
+                               ss->exit(ss, cgrp, old_cgrp, tsk);
+                       }
+               }
+       }
        task_unlock(tsk);
+
        if (cg)
                put_css_set_taskexit(cg);
 }
@@ -4813,6 +4818,29 @@ css_get_next(struct cgroup_subsys *ss, int id,
        return ret;
 }
 
+/*
+ * get corresponding css from file open on cgroupfs directory
+ */
+struct cgroup_subsys_state *cgroup_css_from_dir(struct file *f, int id)
+{
+       struct cgroup *cgrp;
+       struct inode *inode;
+       struct cgroup_subsys_state *css;
+
+       inode = f->f_dentry->d_inode;
+       /* check in cgroup filesystem dir */
+       if (inode->i_op != &cgroup_dir_inode_operations)
+               return ERR_PTR(-EBADF);
+
+       if (id < 0 || id >= CGROUP_SUBSYS_COUNT)
+               return ERR_PTR(-EINVAL);
+
+       /* get cgroup */
+       cgrp = __d_cgrp(f->f_dentry);
+       css = cgrp->subsys[id];
+       return css ? css : ERR_PTR(-ENOENT);
+}
+
 #ifdef CONFIG_CGROUP_DEBUG
 static struct cgroup_subsys_state *debug_create(struct cgroup_subsys *ss,
                                                   struct cgroup *cont)
index c9e2ec0..38b1d2c 100644 (file)
@@ -52,6 +52,64 @@ static int compat_put_timeval(struct compat_timeval __user *o,
                put_user(i->tv_usec, &o->tv_usec)) ? -EFAULT : 0;
 }
 
+static int compat_get_timex(struct timex *txc, struct compat_timex __user *utp)
+{
+       memset(txc, 0, sizeof(struct timex));
+
+       if (!access_ok(VERIFY_READ, utp, sizeof(struct compat_timex)) ||
+                       __get_user(txc->modes, &utp->modes) ||
+                       __get_user(txc->offset, &utp->offset) ||
+                       __get_user(txc->freq, &utp->freq) ||
+                       __get_user(txc->maxerror, &utp->maxerror) ||
+                       __get_user(txc->esterror, &utp->esterror) ||
+                       __get_user(txc->status, &utp->status) ||
+                       __get_user(txc->constant, &utp->constant) ||
+                       __get_user(txc->precision, &utp->precision) ||
+                       __get_user(txc->tolerance, &utp->tolerance) ||
+                       __get_user(txc->time.tv_sec, &utp->time.tv_sec) ||
+                       __get_user(txc->time.tv_usec, &utp->time.tv_usec) ||
+                       __get_user(txc->tick, &utp->tick) ||
+                       __get_user(txc->ppsfreq, &utp->ppsfreq) ||
+                       __get_user(txc->jitter, &utp->jitter) ||
+                       __get_user(txc->shift, &utp->shift) ||
+                       __get_user(txc->stabil, &utp->stabil) ||
+                       __get_user(txc->jitcnt, &utp->jitcnt) ||
+                       __get_user(txc->calcnt, &utp->calcnt) ||
+                       __get_user(txc->errcnt, &utp->errcnt) ||
+                       __get_user(txc->stbcnt, &utp->stbcnt))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int compat_put_timex(struct compat_timex __user *utp, struct timex *txc)
+{
+       if (!access_ok(VERIFY_WRITE, utp, sizeof(struct compat_timex)) ||
+                       __put_user(txc->modes, &utp->modes) ||
+                       __put_user(txc->offset, &utp->offset) ||
+                       __put_user(txc->freq, &utp->freq) ||
+                       __put_user(txc->maxerror, &utp->maxerror) ||
+                       __put_user(txc->esterror, &utp->esterror) ||
+                       __put_user(txc->status, &utp->status) ||
+                       __put_user(txc->constant, &utp->constant) ||
+                       __put_user(txc->precision, &utp->precision) ||
+                       __put_user(txc->tolerance, &utp->tolerance) ||
+                       __put_user(txc->time.tv_sec, &utp->time.tv_sec) ||
+                       __put_user(txc->time.tv_usec, &utp->time.tv_usec) ||
+                       __put_user(txc->tick, &utp->tick) ||
+                       __put_user(txc->ppsfreq, &utp->ppsfreq) ||
+                       __put_user(txc->jitter, &utp->jitter) ||
+                       __put_user(txc->shift, &utp->shift) ||
+                       __put_user(txc->stabil, &utp->stabil) ||
+                       __put_user(txc->jitcnt, &utp->jitcnt) ||
+                       __put_user(txc->calcnt, &utp->calcnt) ||
+                       __put_user(txc->errcnt, &utp->errcnt) ||
+                       __put_user(txc->stbcnt, &utp->stbcnt) ||
+                       __put_user(txc->tai, &utp->tai))
+               return -EFAULT;
+       return 0;
+}
+
 asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv,
                struct timezone __user *tz)
 {
@@ -617,6 +675,29 @@ long compat_sys_clock_gettime(clockid_t which_clock,
        return err;
 }
 
+long compat_sys_clock_adjtime(clockid_t which_clock,
+               struct compat_timex __user *utp)
+{
+       struct timex txc;
+       mm_segment_t oldfs;
+       int err, ret;
+
+       err = compat_get_timex(&txc, utp);
+       if (err)
+               return err;
+
+       oldfs = get_fs();
+       set_fs(KERNEL_DS);
+       ret = sys_clock_adjtime(which_clock, (struct timex __user *) &txc);
+       set_fs(oldfs);
+
+       err = compat_put_timex(utp, &txc);
+       if (err)
+               return err;
+
+       return ret;
+}
+
 long compat_sys_clock_getres(clockid_t which_clock,
                struct compat_timespec __user *tp)
 {
@@ -951,58 +1032,17 @@ asmlinkage long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, compat
 asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp)
 {
        struct timex txc;
-       int ret;
-
-       memset(&txc, 0, sizeof(struct timex));
+       int err, ret;
 
-       if (!access_ok(VERIFY_READ, utp, sizeof(struct compat_timex)) ||
-                       __get_user(txc.modes, &utp->modes) ||
-                       __get_user(txc.offset, &utp->offset) ||
-                       __get_user(txc.freq, &utp->freq) ||
-                       __get_user(txc.maxerror, &utp->maxerror) ||
-                       __get_user(txc.esterror, &utp->esterror) ||
-                       __get_user(txc.status, &utp->status) ||
-                       __get_user(txc.constant, &utp->constant) ||
-                       __get_user(txc.precision, &utp->precision) ||
-                       __get_user(txc.tolerance, &utp->tolerance) ||
-                       __get_user(txc.time.tv_sec, &utp->time.tv_sec) ||
-                       __get_user(txc.time.tv_usec, &utp->time.tv_usec) ||
-                       __get_user(txc.tick, &utp->tick) ||
-                       __get_user(txc.ppsfreq, &utp->ppsfreq) ||
-                       __get_user(txc.jitter, &utp->jitter) ||
-                       __get_user(txc.shift, &utp->shift) ||
-                       __get_user(txc.stabil, &utp->stabil) ||
-                       __get_user(txc.jitcnt, &utp->jitcnt) ||
-                       __get_user(txc.calcnt, &utp->calcnt) ||
-                       __get_user(txc.errcnt, &utp->errcnt) ||
-                       __get_user(txc.stbcnt, &utp->stbcnt))
-               return -EFAULT;
+       err = compat_get_timex(&txc, utp);
+       if (err)
+               return err;
 
        ret = do_adjtimex(&txc);
 
-       if (!access_ok(VERIFY_WRITE, utp, sizeof(struct compat_timex)) ||
-                       __put_user(txc.modes, &utp->modes) ||
-                       __put_user(txc.offset, &utp->offset) ||
-                       __put_user(txc.freq, &utp->freq) ||
-                       __put_user(txc.maxerror, &utp->maxerror) ||
-                       __put_user(txc.esterror, &utp->esterror) ||
-                       __put_user(txc.status, &utp->status) ||
-                       __put_user(txc.constant, &utp->constant) ||
-                       __put_user(txc.precision, &utp->precision) ||
-                       __put_user(txc.tolerance, &utp->tolerance) ||
-                       __put_user(txc.time.tv_sec, &utp->time.tv_sec) ||
-                       __put_user(txc.time.tv_usec, &utp->time.tv_usec) ||
-                       __put_user(txc.tick, &utp->tick) ||
-                       __put_user(txc.ppsfreq, &utp->ppsfreq) ||
-                       __put_user(txc.jitter, &utp->jitter) ||
-                       __put_user(txc.shift, &utp->shift) ||
-                       __put_user(txc.stabil, &utp->stabil) ||
-                       __put_user(txc.jitcnt, &utp->jitcnt) ||
-                       __put_user(txc.calcnt, &utp->calcnt) ||
-                       __put_user(txc.errcnt, &utp->errcnt) ||
-                       __put_user(txc.stbcnt, &utp->stbcnt) ||
-                       __put_user(txc.tai, &utp->tai))
-               ret = -EFAULT;
+       err = compat_put_timex(utp, &txc);
+       if (err)
+               return err;
 
        return ret;
 }
index 4349935..e92e981 100644 (file)
@@ -1575,8 +1575,10 @@ static int cpuset_write_resmask(struct cgroup *cgrp, struct cftype *cft,
                return -ENODEV;
 
        trialcs = alloc_trial_cpuset(cs);
-       if (!trialcs)
-               return -ENOMEM;
+       if (!trialcs) {
+               retval = -ENOMEM;
+               goto out;
+       }
 
        switch (cft->private) {
        case FILE_CPULIST:
@@ -1591,6 +1593,7 @@ static int cpuset_write_resmask(struct cgroup *cgrp, struct cftype *cft,
        }
 
        free_trial_cpuset(trialcs);
+out:
        cgroup_unlock();
        return retval;
 }
index 6a1aa00..2343c13 100644 (file)
@@ -35,7 +35,7 @@ static struct kmem_cache *cred_jar;
 static struct thread_group_cred init_tgcred = {
        .usage  = ATOMIC_INIT(2),
        .tgid   = 0,
-       .lock   = SPIN_LOCK_UNLOCKED,
+       .lock   = __SPIN_LOCK_UNLOCKED(init_cred.tgcred.lock),
 };
 #endif
 
@@ -252,13 +252,13 @@ struct cred *cred_alloc_blank(void)
 #endif
 
        atomic_set(&new->usage, 1);
+#ifdef CONFIG_DEBUG_CREDENTIALS
+       new->magic = CRED_MAGIC;
+#endif
 
        if (security_cred_alloc_blank(new, GFP_KERNEL) < 0)
                goto error;
 
-#ifdef CONFIG_DEBUG_CREDENTIALS
-       new->magic = CRED_MAGIC;
-#endif
        return new;
 
 error:
@@ -657,6 +657,8 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
        validate_creds(old);
 
        *new = *old;
+       atomic_set(&new->usage, 1);
+       set_cred_subscribers(new, 0);
        get_uid(new->user);
        get_group_info(new->group_info);
 
@@ -674,8 +676,6 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
        if (security_prepare_creds(new, old, GFP_KERNEL) < 0)
                goto error;
 
-       atomic_set(&new->usage, 1);
-       set_cred_subscribers(new, 0);
        put_cred(old);
        validate_creds(new);
        return new;
@@ -748,7 +748,11 @@ bool creds_are_invalid(const struct cred *cred)
        if (cred->magic != CRED_MAGIC)
                return true;
 #ifdef CONFIG_SECURITY_SELINUX
-       if (selinux_is_enabled()) {
+       /*
+        * cred->security == NULL if security_cred_alloc_blank() or
+        * security_prepare_creds() returned an error.
+        */
+       if (selinux_is_enabled() && cred->security) {
                if ((unsigned long) cred->security < PAGE_SIZE)
                        return true;
                if ((*(u32 *)cred->security & 0xffffff00) ==
index b766d28..bda4157 100644 (file)
@@ -381,15 +381,16 @@ static struct futex_q *futex_top_waiter(struct futex_hash_bucket *hb,
        return NULL;
 }
 
-static u32 cmpxchg_futex_value_locked(u32 __user *uaddr, u32 uval, u32 newval)
+static int cmpxchg_futex_value_locked(u32 *curval, u32 __user *uaddr,
+                                     u32 uval, u32 newval)
 {
-       u32 curval;
+       int ret;
 
        pagefault_disable();
-       curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
+       ret = futex_atomic_cmpxchg_inatomic(curval, uaddr, uval, newval);
        pagefault_enable();
 
-       return curval;
+       return ret;
 }
 
 static int get_futex_value_locked(u32 *dest, u32 __user *from)
@@ -674,7 +675,7 @@ static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb,
                                struct task_struct *task, int set_waiters)
 {
        int lock_taken, ret, ownerdied = 0;
-       u32 uval, newval, curval;
+       u32 uval, newval, curval, vpid = task_pid_vnr(task);
 
 retry:
        ret = lock_taken = 0;
@@ -684,19 +685,17 @@ retry:
         * (by doing a 0 -> TID atomic cmpxchg), while holding all
         * the locks. It will most likely not succeed.
         */
-       newval = task_pid_vnr(task);
+       newval = vpid;
        if (set_waiters)
                newval |= FUTEX_WAITERS;
 
-       curval = cmpxchg_futex_value_locked(uaddr, 0, newval);
-
-       if (unlikely(curval == -EFAULT))
+       if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, 0, newval)))
                return -EFAULT;
 
        /*
         * Detect deadlocks.
         */
-       if ((unlikely((curval & FUTEX_TID_MASK) == task_pid_vnr(task))))
+       if ((unlikely((curval & FUTEX_TID_MASK) == vpid)))
                return -EDEADLK;
 
        /*
@@ -723,14 +722,12 @@ retry:
         */
        if (unlikely(ownerdied || !(curval & FUTEX_TID_MASK))) {
                /* Keep the OWNER_DIED bit */
-               newval = (curval & ~FUTEX_TID_MASK) | task_pid_vnr(task);
+               newval = (curval & ~FUTEX_TID_MASK) | vpid;
                ownerdied = 0;
                lock_taken = 1;
        }
 
-       curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
-
-       if (unlikely(curval == -EFAULT))
+       if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)))
                return -EFAULT;
        if (unlikely(curval != uval))
                goto retry;
@@ -775,6 +772,24 @@ retry:
        return ret;
 }
 
+/**
+ * __unqueue_futex() - Remove the futex_q from its futex_hash_bucket
+ * @q: The futex_q to unqueue
+ *
+ * The q->lock_ptr must not be NULL and must be held by the caller.
+ */
+static void __unqueue_futex(struct futex_q *q)
+{
+       struct futex_hash_bucket *hb;
+
+       if (WARN_ON(!q->lock_ptr || !spin_is_locked(q->lock_ptr)
+                       || plist_node_empty(&q->list)))
+               return;
+
+       hb = container_of(q->lock_ptr, struct futex_hash_bucket, lock);
+       plist_del(&q->list, &hb->chain);
+}
+
 /*
  * The hash bucket lock must be held when this is called.
  * Afterwards, the futex_q must not be accessed.
@@ -792,7 +807,7 @@ static void wake_futex(struct futex_q *q)
         */
        get_task_struct(p);
 
-       plist_del(&q->list, &q->list.plist);
+       __unqueue_futex(q);
        /*
         * The waiting task can free the futex_q as soon as
         * q->lock_ptr = NULL is written, without taking any locks. A
@@ -843,9 +858,7 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
 
                newval = FUTEX_WAITERS | task_pid_vnr(new_owner);
 
-               curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
-
-               if (curval == -EFAULT)
+               if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
                        ret = -EFAULT;
                else if (curval != uval)
                        ret = -EINVAL;
@@ -880,10 +893,8 @@ static int unlock_futex_pi(u32 __user *uaddr, u32 uval)
         * There is no waiter, so we unlock the futex. The owner died
         * bit has not to be preserved here. We are the owner:
         */
-       oldval = cmpxchg_futex_value_locked(uaddr, uval, 0);
-
-       if (oldval == -EFAULT)
-               return oldval;
+       if (cmpxchg_futex_value_locked(&oldval, uaddr, uval, 0))
+               return -EFAULT;
        if (oldval != uval)
                return -EAGAIN;
 
@@ -1071,9 +1082,6 @@ void requeue_futex(struct futex_q *q, struct futex_hash_bucket *hb1,
                plist_del(&q->list, &hb1->chain);
                plist_add(&q->list, &hb2->chain);
                q->lock_ptr = &hb2->lock;
-#ifdef CONFIG_DEBUG_PI_LIST
-               q->list.plist.spinlock = &hb2->lock;
-#endif
        }
        get_futex_key_refs(key2);
        q->key = *key2;
@@ -1100,16 +1108,12 @@ void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key,
        get_futex_key_refs(key);
        q->key = *key;
 
-       WARN_ON(plist_node_empty(&q->list));
-       plist_del(&q->list, &q->list.plist);
+       __unqueue_futex(q);
 
        WARN_ON(!q->rt_waiter);
        q->rt_waiter = NULL;
 
        q->lock_ptr = &hb->lock;
-#ifdef CONFIG_DEBUG_PI_LIST
-       q->list.plist.spinlock = &hb->lock;
-#endif
 
        wake_up_state(q->task, TASK_NORMAL);
 }
@@ -1457,9 +1461,6 @@ static inline void queue_me(struct futex_q *q, struct futex_hash_bucket *hb)
        prio = min(current->normal_prio, MAX_RT_PRIO);
 
        plist_node_init(&q->list, prio);
-#ifdef CONFIG_DEBUG_PI_LIST
-       q->list.plist.spinlock = &hb->lock;
-#endif
        plist_add(&q->list, &hb->chain);
        q->task = current;
        spin_unlock(&hb->lock);
@@ -1504,8 +1505,7 @@ retry:
                        spin_unlock(lock_ptr);
                        goto retry;
                }
-               WARN_ON(plist_node_empty(&q->list));
-               plist_del(&q->list, &q->list.plist);
+               __unqueue_futex(q);
 
                BUG_ON(q->pi_state);
 
@@ -1525,8 +1525,7 @@ retry:
 static void unqueue_me_pi(struct futex_q *q)
        __releases(q->lock_ptr)
 {
-       WARN_ON(plist_node_empty(&q->list));
-       plist_del(&q->list, &q->list.plist);
+       __unqueue_futex(q);
 
        BUG_ON(!q->pi_state);
        free_pi_state(q->pi_state);
@@ -1556,10 +1555,10 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
 
        /*
         * We are here either because we stole the rtmutex from the
-        * pending owner or we are the pending owner which failed to
-        * get the rtmutex. We have to replace the pending owner TID
-        * in the user space variable. This must be atomic as we have
-        * to preserve the owner died bit here.
+        * previous highest priority waiter or we are the highest priority
+        * waiter but failed to get the rtmutex the first time.
+        * We have to replace the newowner TID in the user space variable.
+        * This must be atomic as we have to preserve the owner died bit here.
         *
         * Note: We write the user space value _before_ changing the pi_state
         * because we can fault here. Imagine swapped out pages or a fork
@@ -1578,9 +1577,7 @@ retry:
        while (1) {
                newval = (uval & FUTEX_OWNER_DIED) | newtid;
 
-               curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
-
-               if (curval == -EFAULT)
+               if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
                        goto handle_fault;
                if (curval == uval)
                        break;
@@ -1608,8 +1605,8 @@ retry:
 
        /*
         * To handle the page fault we need to drop the hash bucket
-        * lock here. That gives the other task (either the pending
-        * owner itself or the task which stole the rtmutex) the
+        * lock here. That gives the other task (either the highest priority
+        * waiter itself or the task which stole the rtmutex) the
         * chance to try the fixup of the pi_state. So once we are
         * back from handling the fault we need to check the pi_state
         * after reacquiring the hash bucket lock and before trying to
@@ -1685,18 +1682,20 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
                /*
                 * pi_state is incorrect, some other task did a lock steal and
                 * we returned due to timeout or signal without taking the
-                * rt_mutex. Too late. We can access the rt_mutex_owner without
-                * locking, as the other task is now blocked on the hash bucket
-                * lock. Fix the state up.
+                * rt_mutex. Too late.
                 */
+               raw_spin_lock(&q->pi_state->pi_mutex.wait_lock);
                owner = rt_mutex_owner(&q->pi_state->pi_mutex);
+               if (!owner)
+                       owner = rt_mutex_next_owner(&q->pi_state->pi_mutex);
+               raw_spin_unlock(&q->pi_state->pi_mutex.wait_lock);
                ret = fixup_pi_state_owner(uaddr, q, owner);
                goto out;
        }
 
        /*
         * Paranoia check. If we did not take the lock, then we should not be
-        * the owner, nor the pending owner, of the rt_mutex.
+        * the owner of the rt_mutex.
         */
        if (rt_mutex_owner(&q->pi_state->pi_mutex) == current)
                printk(KERN_ERR "fixup_owner: ret = %d pi-mutex: %p "
@@ -1781,13 +1780,14 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
         *
         * The basic logical guarantee of a futex is that it blocks ONLY
         * if cond(var) is known to be true at the time of blocking, for
-        * any cond.  If we queued after testing *uaddr, that would open
-        * a race condition where we could block indefinitely with
+        * any cond.  If we locked the hash-bucket after testing *uaddr, that
+        * would open a race condition where we could block indefinitely with
         * cond(var) false, which would violate the guarantee.
         *
-        * A consequence is that futex_wait() can return zero and absorb
-        * a wakeup when *uaddr != val on entry to the syscall.  This is
-        * rare, but normal.
+        * On the other hand, we insert q and release the hash-bucket only
+        * after testing *uaddr.  This guarantees that futex_wait() will NOT
+        * absorb a wakeup if *uaddr does not match the desired values
+        * while the syscall executes.
         */
 retry:
        ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q->key);
@@ -2046,9 +2046,9 @@ static int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)
 {
        struct futex_hash_bucket *hb;
        struct futex_q *this, *next;
-       u32 uval;
        struct plist_head *head;
        union futex_key key = FUTEX_KEY_INIT;
+       u32 uval, vpid = task_pid_vnr(current);
        int ret;
 
 retry:
@@ -2057,7 +2057,7 @@ retry:
        /*
         * We release only a lock we actually own:
         */
-       if ((uval & FUTEX_TID_MASK) != task_pid_vnr(current))
+       if ((uval & FUTEX_TID_MASK) != vpid)
                return -EPERM;
 
        ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key);
@@ -2072,17 +2072,14 @@ retry:
         * again. If it succeeds then we can return without waking
         * anyone else up:
         */
-       if (!(uval & FUTEX_OWNER_DIED))
-               uval = cmpxchg_futex_value_locked(uaddr, task_pid_vnr(current), 0);
-
-
-       if (unlikely(uval == -EFAULT))
+       if (!(uval & FUTEX_OWNER_DIED) &&
+           cmpxchg_futex_value_locked(&uval, uaddr, vpid, 0))
                goto pi_faulted;
        /*
         * Rare case: we managed to release the lock atomically,
         * no need to wake anyone else up:
         */
-       if (unlikely(uval == task_pid_vnr(current)))
+       if (unlikely(uval == vpid))
                goto out_unlock;
 
        /*
@@ -2167,7 +2164,7 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
                 * We were woken prior to requeue by a timeout or a signal.
                 * Unqueue the futex_q and determine which it was.
                 */
-               plist_del(&q->list, &q->list.plist);
+               plist_del(&q->list, &hb->chain);
 
                /* Handle spurious wakeups gracefully */
                ret = -EWOULDBLOCK;
@@ -2463,11 +2460,20 @@ retry:
                 * userspace.
                 */
                mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
-               nval = futex_atomic_cmpxchg_inatomic(uaddr, uval, mval);
-
-               if (nval == -EFAULT)
-                       return -1;
-
+               /*
+                * We are not holding a lock here, but we want to have
+                * the pagefault_disable/enable() protection because
+                * we want to handle the fault gracefully. If the
+                * access fails we try to fault in the futex with R/W
+                * verification via get_user_pages. get_user() above
+                * does not guarantee R/W access. If that fails we
+                * give up and leave the futex locked.
+                */
+               if (cmpxchg_futex_value_locked(&nval, uaddr, uval, mval)) {
+                       if (fault_in_user_writeable(uaddr))
+                               return -1;
+                       goto retry;
+               }
                if (nval != uval)
                        goto retry;
 
@@ -2678,8 +2684,7 @@ static int __init futex_init(void)
         * implementation, the non-functional ones will return
         * -ENOSYS.
         */
-       curval = cmpxchg_futex_value_locked(NULL, 0, 0);
-       if (curval == -EFAULT)
+       if (cmpxchg_futex_value_locked(&curval, NULL, 0, 0) == -EFAULT)
                futex_cmpxchg_enabled = 1;
 
        for (i = 0; i < ARRAY_SIZE(futex_queues); i++) {
index 0c8d7c0..9017478 100644 (file)
 /*
  * The timer bases:
  *
- * Note: If we want to add new timer bases, we have to skip the two
- * clock ids captured by the cpu-timers. We do this by holding empty
- * entries rather than doing math adjustment of the clock ids.
- * This ensures that we capture erroneous accesses to these clock ids
- * rather than moving them into the range of valid clock id's.
+ * There are more clockids then hrtimer bases. Thus, we index
+ * into the timer bases by the hrtimer_base_type enum. When trying
+ * to reach a base using a clockid, hrtimer_clockid_to_base()
+ * is used to convert from clockid to the proper hrtimer_base_type.
  */
 DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
 {
@@ -74,30 +73,39 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
                        .get_time = &ktime_get,
                        .resolution = KTIME_LOW_RES,
                },
+               {
+                       .index = CLOCK_BOOTTIME,
+                       .get_time = &ktime_get_boottime,
+                       .resolution = KTIME_LOW_RES,
+               },
        }
 };
 
+static int hrtimer_clock_to_base_table[MAX_CLOCKS];
+
+static inline int hrtimer_clockid_to_base(clockid_t clock_id)
+{
+       return hrtimer_clock_to_base_table[clock_id];
+}
+
+
 /*
  * Get the coarse grained time at the softirq based on xtime and
  * wall_to_monotonic.
  */
 static void hrtimer_get_softirq_time(struct hrtimer_cpu_base *base)
 {
-       ktime_t xtim, tomono;
-       struct timespec xts, tom;
-       unsigned long seq;
+       ktime_t xtim, mono, boot;
+       struct timespec xts, tom, slp;
 
-       do {
-               seq = read_seqbegin(&xtime_lock);
-               xts = __current_kernel_time();
-               tom = __get_wall_to_monotonic();
-       } while (read_seqretry(&xtime_lock, seq));
+       get_xtime_and_monotonic_and_sleep_offset(&xts, &tom, &slp);
 
        xtim = timespec_to_ktime(xts);
-       tomono = timespec_to_ktime(tom);
-       base->clock_base[CLOCK_REALTIME].softirq_time = xtim;
-       base->clock_base[CLOCK_MONOTONIC].softirq_time =
-               ktime_add(xtim, tomono);
+       mono = ktime_add(xtim, timespec_to_ktime(tom));
+       boot = ktime_add(mono, timespec_to_ktime(slp));
+       base->clock_base[HRTIMER_BASE_REALTIME].softirq_time = xtim;
+       base->clock_base[HRTIMER_BASE_MONOTONIC].softirq_time = mono;
+       base->clock_base[HRTIMER_BASE_BOOTTIME].softirq_time = boot;
 }
 
 /*
@@ -184,10 +192,11 @@ switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base,
        struct hrtimer_cpu_base *new_cpu_base;
        int this_cpu = smp_processor_id();
        int cpu = hrtimer_get_target(this_cpu, pinned);
+       int basenum = hrtimer_clockid_to_base(base->index);
 
 again:
        new_cpu_base = &per_cpu(hrtimer_bases, cpu);
-       new_base = &new_cpu_base->clock_base[base->index];
+       new_base = &new_cpu_base->clock_base[basenum];
 
        if (base != new_base) {
                /*
@@ -334,6 +343,11 @@ EXPORT_SYMBOL_GPL(ktime_add_safe);
 
 static struct debug_obj_descr hrtimer_debug_descr;
 
+static void *hrtimer_debug_hint(void *addr)
+{
+       return ((struct hrtimer *) addr)->function;
+}
+
 /*
  * fixup_init is called when:
  * - an active object is initialized
@@ -393,6 +407,7 @@ static int hrtimer_fixup_free(void *addr, enum debug_obj_state state)
 
 static struct debug_obj_descr hrtimer_debug_descr = {
        .name           = "hrtimer",
+       .debug_hint     = hrtimer_debug_hint,
        .fixup_init     = hrtimer_fixup_init,
        .fixup_activate = hrtimer_fixup_activate,
        .fixup_free     = hrtimer_fixup_free,
@@ -611,24 +626,23 @@ static int hrtimer_reprogram(struct hrtimer *timer,
 static void retrigger_next_event(void *arg)
 {
        struct hrtimer_cpu_base *base;
-       struct timespec realtime_offset, wtm;
-       unsigned long seq;
+       struct timespec realtime_offset, wtm, sleep;
 
        if (!hrtimer_hres_active())
                return;
 
-       do {
-               seq = read_seqbegin(&xtime_lock);
-               wtm = __get_wall_to_monotonic();
-       } while (read_seqretry(&xtime_lock, seq));
+       get_xtime_and_monotonic_and_sleep_offset(&realtime_offset, &wtm,
+                                                       &sleep);
        set_normalized_timespec(&realtime_offset, -wtm.tv_sec, -wtm.tv_nsec);
 
        base = &__get_cpu_var(hrtimer_bases);
 
        /* Adjust CLOCK_REALTIME offset */
        raw_spin_lock(&base->lock);
-       base->clock_base[CLOCK_REALTIME].offset =
+       base->clock_base[HRTIMER_BASE_REALTIME].offset =
                timespec_to_ktime(realtime_offset);
+       base->clock_base[HRTIMER_BASE_BOOTTIME].offset =
+               timespec_to_ktime(sleep);
 
        hrtimer_force_reprogram(base, 0);
        raw_spin_unlock(&base->lock);
@@ -672,14 +686,6 @@ static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base)
        base->hres_active = 0;
 }
 
-/*
- * Initialize the high resolution related parts of a hrtimer
- */
-static inline void hrtimer_init_timer_hres(struct hrtimer *timer)
-{
-}
-
-
 /*
  * When High resolution timers are active, try to reprogram. Note, that in case
  * the state has HRTIMER_STATE_CALLBACK set, no reprogramming and no expiry
@@ -725,8 +731,9 @@ static int hrtimer_switch_to_hres(void)
                return 0;
        }
        base->hres_active = 1;
-       base->clock_base[CLOCK_REALTIME].resolution = KTIME_HIGH_RES;
-       base->clock_base[CLOCK_MONOTONIC].resolution = KTIME_HIGH_RES;
+       base->clock_base[HRTIMER_BASE_REALTIME].resolution = KTIME_HIGH_RES;
+       base->clock_base[HRTIMER_BASE_MONOTONIC].resolution = KTIME_HIGH_RES;
+       base->clock_base[HRTIMER_BASE_BOOTTIME].resolution = KTIME_HIGH_RES;
 
        tick_setup_sched_timer();
 
@@ -750,7 +757,6 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
        return 0;
 }
 static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base) { }
-static inline void hrtimer_init_timer_hres(struct hrtimer *timer) { }
 
 #endif /* CONFIG_HIGH_RES_TIMERS */
 
@@ -1121,6 +1127,7 @@ static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
                           enum hrtimer_mode mode)
 {
        struct hrtimer_cpu_base *cpu_base;
+       int base;
 
        memset(timer, 0, sizeof(struct hrtimer));
 
@@ -1129,8 +1136,8 @@ static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
        if (clock_id == CLOCK_REALTIME && mode != HRTIMER_MODE_ABS)
                clock_id = CLOCK_MONOTONIC;
 
-       timer->base = &cpu_base->clock_base[clock_id];
-       hrtimer_init_timer_hres(timer);
+       base = hrtimer_clockid_to_base(clock_id);
+       timer->base = &cpu_base->clock_base[base];
        timerqueue_init(&timer->node);
 
 #ifdef CONFIG_TIMER_STATS
@@ -1165,9 +1172,10 @@ EXPORT_SYMBOL_GPL(hrtimer_init);
 int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp)
 {
        struct hrtimer_cpu_base *cpu_base;
+       int base = hrtimer_clockid_to_base(which_clock);
 
        cpu_base = &__raw_get_cpu_var(hrtimer_bases);
-       *tp = ktime_to_timespec(cpu_base->clock_base[which_clock].resolution);
+       *tp = ktime_to_timespec(cpu_base->clock_base[base].resolution);
 
        return 0;
 }
@@ -1714,6 +1722,10 @@ static struct notifier_block __cpuinitdata hrtimers_nb = {
 
 void __init hrtimers_init(void)
 {
+       hrtimer_clock_to_base_table[CLOCK_REALTIME] = HRTIMER_BASE_REALTIME;
+       hrtimer_clock_to_base_table[CLOCK_MONOTONIC] = HRTIMER_BASE_MONOTONIC;
+       hrtimer_clock_to_base_table[CLOCK_BOOTTIME] = HRTIMER_BASE_BOOTTIME;
+
        hrtimer_cpu_notify(&hrtimers_nb, (unsigned long)CPU_UP_PREPARE,
                          (void *)(long)smp_processor_id());
        register_cpu_notifier(&hrtimers_nb);
index 8e42fec..09bef82 100644 (file)
@@ -1,5 +1,6 @@
+# Select this to activate the generic irq options below
 config HAVE_GENERIC_HARDIRQS
-       def_bool n
+       bool
 
 if HAVE_GENERIC_HARDIRQS
 menu "IRQ subsystem"
@@ -11,26 +12,44 @@ config GENERIC_HARDIRQS
 
 # Select this to disable the deprecated stuff
 config GENERIC_HARDIRQS_NO_DEPRECATED
-       def_bool n
+       bool
+
+config GENERIC_HARDIRQS_NO_COMPAT
+       bool
 
 # Options selectable by the architecture code
+
+# Make sparse irq Kconfig switch below available
 config HAVE_SPARSE_IRQ
-       def_bool n
+       bool
 
+# Enable the generic irq autoprobe mechanism
 config GENERIC_IRQ_PROBE
-       def_bool n
+       bool
+
+# Use the generic /proc/interrupts implementation
+config GENERIC_IRQ_SHOW
+       bool
 
+# Support for delayed migration from interrupt context
 config GENERIC_PENDING_IRQ
-       def_bool n
+       bool
 
+# Alpha specific irq affinity mechanism
 config AUTO_IRQ_AFFINITY
-       def_bool n
-
-config IRQ_PER_CPU
-       def_bool n
+       bool
 
+# Tasklet based software resend for pending interrupts on enable_irq()
 config HARDIRQS_SW_RESEND
-       def_bool n
+       bool
+
+# Preflow handler support for fasteoi (sparc64)
+config IRQ_PREFLOW_FASTEOI
+       bool
+
+# Support forced irq threading
+config IRQ_FORCED_THREADING
+       bool
 
 config SPARSE_IRQ
        bool "Support sparse irq numbering"
index 505798f..394784c 100644 (file)
@@ -17,7 +17,7 @@
 /*
  * Autodetection depends on the fact that any interrupt that
  * comes in on to an unassigned handler will get stuck with
- * "IRQ_WAITING" cleared and the interrupt disabled.
+ * "IRQS_WAITING" cleared and the interrupt disabled.
  */
 static DEFINE_MUTEX(probing_active);
 
@@ -32,7 +32,6 @@ unsigned long probe_irq_on(void)
 {
        struct irq_desc *desc;
        unsigned long mask = 0;
-       unsigned int status;
        int i;
 
        /*
@@ -46,13 +45,7 @@ unsigned long probe_irq_on(void)
         */
        for_each_irq_desc_reverse(i, desc) {
                raw_spin_lock_irq(&desc->lock);
-               if (!desc->action && !(desc->status & IRQ_NOPROBE)) {
-                       /*
-                        * An old-style architecture might still have
-                        * the handle_bad_irq handler there:
-                        */
-                       compat_irq_chip_set_default_handler(desc);
-
+               if (!desc->action && irq_settings_can_probe(desc)) {
                        /*
                         * Some chips need to know about probing in
                         * progress:
@@ -60,7 +53,7 @@ unsigned long probe_irq_on(void)
                        if (desc->irq_data.chip->irq_set_type)
                                desc->irq_data.chip->irq_set_type(&desc->irq_data,
                                                         IRQ_TYPE_PROBE);
-                       desc->irq_data.chip->irq_startup(&desc->irq_data);
+                       irq_startup(desc);
                }
                raw_spin_unlock_irq(&desc->lock);
        }
@@ -75,10 +68,12 @@ unsigned long probe_irq_on(void)
         */
        for_each_irq_desc_reverse(i, desc) {
                raw_spin_lock_irq(&desc->lock);
-               if (!desc->action && !(desc->status & IRQ_NOPROBE)) {
-                       desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
-                       if (desc->irq_data.chip->irq_startup(&desc->irq_data))
-                               desc->status |= IRQ_PENDING;
+               if (!desc->action && irq_settings_can_probe(desc)) {
+                       desc->istate |= IRQS_AUTODETECT | IRQS_WAITING;
+                       if (irq_startup(desc)) {
+                               irq_compat_set_pending(desc);
+                               desc->istate |= IRQS_PENDING;
+                       }
                }
                raw_spin_unlock_irq(&desc->lock);
        }
@@ -93,13 +88,12 @@ unsigned long probe_irq_on(void)
         */
        for_each_irq_desc(i, desc) {
                raw_spin_lock_irq(&desc->lock);
-               status = desc->status;
 
-               if (status & IRQ_AUTODETECT) {
+               if (desc->istate & IRQS_AUTODETECT) {
                        /* It triggered already - consider it spurious. */
-                       if (!(status & IRQ_WAITING)) {
-                               desc->status = status & ~IRQ_AUTODETECT;
-                               desc->irq_data.chip->irq_shutdown(&desc->irq_data);
+                       if (!(desc->istate & IRQS_WAITING)) {
+                               desc->istate &= ~IRQS_AUTODETECT;
+                               irq_shutdown(desc);
                        } else
                                if (i < 32)
                                        mask |= 1 << i;
@@ -125,20 +119,18 @@ EXPORT_SYMBOL(probe_irq_on);
  */
 unsigned int probe_irq_mask(unsigned long val)
 {
-       unsigned int status, mask = 0;
+       unsigned int mask = 0;
        struct irq_desc *desc;
        int i;
 
        for_each_irq_desc(i, desc) {
                raw_spin_lock_irq(&desc->lock);
-               status = desc->status;
-
-               if (status & IRQ_AUTODETECT) {
-                       if (i < 16 && !(status & IRQ_WAITING))
+               if (desc->istate & IRQS_AUTODETECT) {
+                       if (i < 16 && !(desc->istate & IRQS_WAITING))
                                mask |= 1 << i;
 
-                       desc->status = status & ~IRQ_AUTODETECT;
-                       desc->irq_data.chip->irq_shutdown(&desc->irq_data);
+                       desc->istate &= ~IRQS_AUTODETECT;
+                       irq_shutdown(desc);
                }
                raw_spin_unlock_irq(&desc->lock);
        }
@@ -169,20 +161,18 @@ int probe_irq_off(unsigned long val)
 {
        int i, irq_found = 0, nr_of_irqs = 0;
        struct irq_desc *desc;
-       unsigned int status;
 
        for_each_irq_desc(i, desc) {
                raw_spin_lock_irq(&desc->lock);
-               status = desc->status;
 
-               if (status & IRQ_AUTODETECT) {
-                       if (!(status & IRQ_WAITING)) {
+               if (desc->istate & IRQS_AUTODETECT) {
+                       if (!(desc->istate & IRQS_WAITING)) {
                                if (!nr_of_irqs)
                                        irq_found = i;
                                nr_of_irqs++;
                        }
-                       desc->status = status & ~IRQ_AUTODETECT;
-                       desc->irq_data.chip->irq_shutdown(&desc->irq_data);
+                       desc->istate &= ~IRQS_AUTODETECT;
+                       irq_shutdown(desc);
                }
                raw_spin_unlock_irq(&desc->lock);
        }
index baa5c4a..c9c0601 100644 (file)
 #include "internals.h"
 
 /**
- *     set_irq_chip - set the irq chip for an irq
+ *     irq_set_chip - set the irq chip for an irq
  *     @irq:   irq number
  *     @chip:  pointer to irq chip description structure
  */
-int set_irq_chip(unsigned int irq, struct irq_chip *chip)
+int irq_set_chip(unsigned int irq, struct irq_chip *chip)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;
+       struct irq_desc *desc = irq_get_desc_lock(irq, &flags);
 
-       if (!desc) {
-               WARN(1, KERN_ERR "Trying to install chip for IRQ%d\n", irq);
+       if (!desc)
                return -EINVAL;
-       }
 
        if (!chip)
                chip = &no_irq_chip;
 
-       raw_spin_lock_irqsave(&desc->lock, flags);
        irq_chip_set_defaults(chip);
        desc->irq_data.chip = chip;
-       raw_spin_unlock_irqrestore(&desc->lock, flags);
-
+       irq_put_desc_unlock(desc, flags);
        return 0;
 }
-EXPORT_SYMBOL(set_irq_chip);
+EXPORT_SYMBOL(irq_set_chip);
 
 /**
- *     set_irq_type - set the irq trigger type for an irq
+ *     irq_set_type - set the irq trigger type for an irq
  *     @irq:   irq number
  *     @type:  IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h
  */
-int set_irq_type(unsigned int irq, unsigned int type)
+int irq_set_irq_type(unsigned int irq, unsigned int type)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;
-       int ret = -ENXIO;
+       struct irq_desc *desc = irq_get_desc_buslock(irq, &flags);
+       int ret = 0;
 
-       if (!desc) {
-               printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq);
-               return -ENODEV;
-       }
+       if (!desc)
+               return -EINVAL;
 
        type &= IRQ_TYPE_SENSE_MASK;
-       if (type == IRQ_TYPE_NONE)
-               return 0;
-
-       raw_spin_lock_irqsave(&desc->lock, flags);
-       ret = __irq_set_trigger(desc, irq, type);
-       raw_spin_unlock_irqrestore(&desc->lock, flags);
+       if (type != IRQ_TYPE_NONE)
+               ret = __irq_set_trigger(desc, irq, type);
+       irq_put_desc_busunlock(desc, flags);
        return ret;
 }
-EXPORT_SYMBOL(set_irq_type);
+EXPORT_SYMBOL(irq_set_irq_type);
 
 /**
- *     set_irq_data - set irq type data for an irq
+ *     irq_set_handler_data - set irq handler data for an irq
  *     @irq:   Interrupt number
  *     @data:  Pointer to interrupt specific data
  *
  *     Set the hardware irq controller data for an irq
  */
-int set_irq_data(unsigned int irq, void *data)
+int irq_set_handler_data(unsigned int irq, void *data)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;
+       struct irq_desc *desc = irq_get_desc_lock(irq, &flags);
 
-       if (!desc) {
-               printk(KERN_ERR
-                      "Trying to install controller data for IRQ%d\n", irq);
+       if (!desc)
                return -EINVAL;
-       }
-
-       raw_spin_lock_irqsave(&desc->lock, flags);
        desc->irq_data.handler_data = data;
-       raw_spin_unlock_irqrestore(&desc->lock, flags);
+       irq_put_desc_unlock(desc, flags);
        return 0;
 }
-EXPORT_SYMBOL(set_irq_data);
+EXPORT_SYMBOL(irq_set_handler_data);
 
 /**
- *     set_irq_msi - set MSI descriptor data for an irq
+ *     irq_set_msi_desc - set MSI descriptor data for an irq
  *     @irq:   Interrupt number
  *     @entry: Pointer to MSI descriptor data
  *
  *     Set the MSI descriptor entry for an irq
  */
-int set_irq_msi(unsigned int irq, struct msi_desc *entry)
+int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;
+       struct irq_desc *desc = irq_get_desc_lock(irq, &flags);
 
-       if (!desc) {
-               printk(KERN_ERR
-                      "Trying to install msi data for IRQ%d\n", irq);
+       if (!desc)
                return -EINVAL;
-       }
-
-       raw_spin_lock_irqsave(&desc->lock, flags);
        desc->irq_data.msi_desc = entry;
        if (entry)
                entry->irq = irq;
-       raw_spin_unlock_irqrestore(&desc->lock, flags);
+       irq_put_desc_unlock(desc, flags);
        return 0;
 }
 
 /**
- *     set_irq_chip_data - set irq chip data for an irq
+ *     irq_set_chip_data - set irq chip data for an irq
  *     @irq:   Interrupt number
  *     @data:  Pointer to chip specific data
  *
  *     Set the hardware irq chip data for an irq
  */
-int set_irq_chip_data(unsigned int irq, void *data)
+int irq_set_chip_data(unsigned int irq, void *data)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;
+       struct irq_desc *desc = irq_get_desc_lock(irq, &flags);
 
-       if (!desc) {
-               printk(KERN_ERR
-                      "Trying to install chip data for IRQ%d\n", irq);
-               return -EINVAL;
-       }
-
-       if (!desc->irq_data.chip) {
-               printk(KERN_ERR "BUG: bad set_irq_chip_data(IRQ#%d)\n", irq);
+       if (!desc)
                return -EINVAL;
-       }
-
-       raw_spin_lock_irqsave(&desc->lock, flags);
        desc->irq_data.chip_data = data;
-       raw_spin_unlock_irqrestore(&desc->lock, flags);
-
+       irq_put_desc_unlock(desc, flags);
        return 0;
 }
-EXPORT_SYMBOL(set_irq_chip_data);
+EXPORT_SYMBOL(irq_set_chip_data);
 
 struct irq_data *irq_get_irq_data(unsigned int irq)
 {
@@ -162,72 +132,75 @@ struct irq_data *irq_get_irq_data(unsigned int irq)
 }
 EXPORT_SYMBOL_GPL(irq_get_irq_data);
 
-/**
- *     set_irq_nested_thread - Set/Reset the IRQ_NESTED_THREAD flag of an irq
- *
- *     @irq:   Interrupt number
- *     @nest:  0 to clear / 1 to set the IRQ_NESTED_THREAD flag
- *
- *     The IRQ_NESTED_THREAD flag indicates that on
- *     request_threaded_irq() no separate interrupt thread should be
- *     created for the irq as the handler are called nested in the
- *     context of a demultiplexing interrupt handler thread.
- */
-void set_irq_nested_thread(unsigned int irq, int nest)
+static void irq_state_clr_disabled(struct irq_desc *desc)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-       unsigned long flags;
-
-       if (!desc)
-               return;
-
-       raw_spin_lock_irqsave(&desc->lock, flags);
-       if (nest)
-               desc->status |= IRQ_NESTED_THREAD;
-       else
-               desc->status &= ~IRQ_NESTED_THREAD;
-       raw_spin_unlock_irqrestore(&desc->lock, flags);
+       desc->istate &= ~IRQS_DISABLED;
+       irq_compat_clr_disabled(desc);
 }
-EXPORT_SYMBOL_GPL(set_irq_nested_thread);
 
-/*
- * default enable function
- */
-static void default_enable(struct irq_data *data)
+static void irq_state_set_disabled(struct irq_desc *desc)
 {
-       struct irq_desc *desc = irq_data_to_desc(data);
+       desc->istate |= IRQS_DISABLED;
+       irq_compat_set_disabled(desc);
+}
 
-       desc->irq_data.chip->irq_unmask(&desc->irq_data);
-       desc->status &= ~IRQ_MASKED;
+static void irq_state_clr_masked(struct irq_desc *desc)
+{
+       desc->istate &= ~IRQS_MASKED;
+       irq_compat_clr_masked(desc);
 }
 
-/*
- * default disable function
- */
-static void default_disable(struct irq_data *data)
+static void irq_state_set_masked(struct irq_desc *desc)
 {
+       desc->istate |= IRQS_MASKED;
+       irq_compat_set_masked(desc);
 }
 
-/*
- * default startup function
- */
-static unsigned int default_startup(struct irq_data *data)
+int irq_startup(struct irq_desc *desc)
 {
-       struct irq_desc *desc = irq_data_to_desc(data);
+       irq_state_clr_disabled(desc);
+       desc->depth = 0;
+
+       if (desc->irq_data.chip->irq_startup) {
+               int ret = desc->irq_data.chip->irq_startup(&desc->irq_data);
+               irq_state_clr_masked(desc);
+               return ret;
+       }
 
-       desc->irq_data.chip->irq_enable(data);
+       irq_enable(desc);
        return 0;
 }
 
-/*
- * default shutdown function
- */
-static void default_shutdown(struct irq_data *data)
+void irq_shutdown(struct irq_desc *desc)
 {
-       struct irq_desc *desc = irq_data_to_desc(data);
+       irq_state_set_disabled(desc);
+       desc->depth = 1;
+       if (desc->irq_data.chip->irq_shutdown)
+               desc->irq_data.chip->irq_shutdown(&desc->irq_data);
+       if (desc->irq_data.chip->irq_disable)
+               desc->irq_data.chip->irq_disable(&desc->irq_data);
+       else
+               desc->irq_data.chip->irq_mask(&desc->irq_data);
+       irq_state_set_masked(desc);
+}
 
-       desc->irq_data.chip->irq_mask(&desc->irq_data);
-       desc->status |= IRQ_MASKED;
+void irq_enable(struct irq_desc *desc)
+{
+       irq_state_clr_disabled(desc);
+       if (desc->irq_data.chip->irq_enable)
+               desc->irq_data.chip->irq_enable(&desc->irq_data);
+       else
+               desc->irq_data.chip->irq_unmask(&desc->irq_data);
+       irq_state_clr_masked(desc);
+}
+
+void irq_disable(struct irq_desc *desc)
+{
+       irq_state_set_disabled(desc);
+       if (desc->irq_data.chip->irq_disable) {
+               desc->irq_data.chip->irq_disable(&desc->irq_data);
+               irq_state_set_masked(desc);
+       }
 }
 
 #ifndef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED
@@ -315,10 +288,6 @@ static void compat_bus_sync_unlock(struct irq_data *data)
 void irq_chip_set_defaults(struct irq_chip *chip)
 {
 #ifndef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED
-       /*
-        * Compat fixup functions need to be before we set the
-        * defaults for enable/disable/startup/shutdown
-        */
        if (chip->enable)
                chip->irq_enable = compat_irq_enable;
        if (chip->disable)
@@ -327,33 +296,8 @@ void irq_chip_set_defaults(struct irq_chip *chip)
                chip->irq_shutdown = compat_irq_shutdown;
        if (chip->startup)
                chip->irq_startup = compat_irq_startup;
-#endif
-       /*
-        * The real defaults
-        */
-       if (!chip->irq_enable)
-               chip->irq_enable = default_enable;
-       if (!chip->irq_disable)
-               chip->irq_disable = default_disable;
-       if (!chip->irq_startup)
-               chip->irq_startup = default_startup;
-       /*
-        * We use chip->irq_disable, when the user provided its own. When
-        * we have default_disable set for chip->irq_disable, then we need
-        * to use default_shutdown, otherwise the irq line is not
-        * disabled on free_irq():
-        */
-       if (!chip->irq_shutdown)
-               chip->irq_shutdown = chip->irq_disable != default_disable ?
-                       chip->irq_disable : default_shutdown;
-
-#ifndef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED
        if (!chip->end)
                chip->end = dummy_irq_chip.end;
-
-       /*
-        * Now fix up the remaining compat handlers
-        */
        if (chip->bus_lock)
                chip->irq_bus_lock = compat_bus_lock;
        if (chip->bus_sync_unlock)
@@ -388,22 +332,22 @@ static inline void mask_ack_irq(struct irq_desc *desc)
                if (desc->irq_data.chip->irq_ack)
                        desc->irq_data.chip->irq_ack(&desc->irq_data);
        }
-       desc->status |= IRQ_MASKED;
+       irq_state_set_masked(desc);
 }
 
-static inline void mask_irq(struct irq_desc *desc)
+void mask_irq(struct irq_desc *desc)
 {
        if (desc->irq_data.chip->irq_mask) {
                desc->irq_data.chip->irq_mask(&desc->irq_data);
-               desc->status |= IRQ_MASKED;
+               irq_state_set_masked(desc);
        }
 }
 
-static inline void unmask_irq(struct irq_desc *desc)
+void unmask_irq(struct irq_desc *desc)
 {
        if (desc->irq_data.chip->irq_unmask) {
                desc->irq_data.chip->irq_unmask(&desc->irq_data);
-               desc->status &= ~IRQ_MASKED;
+               irq_state_clr_masked(desc);
        }
 }
 
@@ -428,10 +372,11 @@ void handle_nested_irq(unsigned int irq)
        kstat_incr_irqs_this_cpu(irq, desc);
 
        action = desc->action;
-       if (unlikely(!action || (desc->status & IRQ_DISABLED)))
+       if (unlikely(!action || (desc->istate & IRQS_DISABLED)))
                goto out_unlock;
 
-       desc->status |= IRQ_INPROGRESS;
+       irq_compat_set_progress(desc);
+       desc->istate |= IRQS_INPROGRESS;
        raw_spin_unlock_irq(&desc->lock);
 
        action_ret = action->thread_fn(action->irq, action->dev_id);
@@ -439,13 +384,21 @@ void handle_nested_irq(unsigned int irq)
                note_interrupt(irq, desc, action_ret);
 
        raw_spin_lock_irq(&desc->lock);
-       desc->status &= ~IRQ_INPROGRESS;
+       desc->istate &= ~IRQS_INPROGRESS;
+       irq_compat_clr_progress(desc);
 
 out_unlock:
        raw_spin_unlock_irq(&desc->lock);
 }
 EXPORT_SYMBOL_GPL(handle_nested_irq);
 
+static bool irq_check_poll(struct irq_desc *desc)
+{
+       if (!(desc->istate & IRQS_POLL_INPROGRESS))
+               return false;
+       return irq_wait_for_poll(desc);
+}
+
 /**
  *     handle_simple_irq - Simple and software-decoded IRQs.
  *     @irq:   the interrupt number
@@ -461,29 +414,20 @@ EXPORT_SYMBOL_GPL(handle_nested_irq);
 void
 handle_simple_irq(unsigned int irq, struct irq_desc *desc)
 {
-       struct irqaction *action;
-       irqreturn_t action_ret;
-
        raw_spin_lock(&desc->lock);
 
-       if (unlikely(desc->status & IRQ_INPROGRESS))
-               goto out_unlock;
-       desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
+       if (unlikely(desc->istate & IRQS_INPROGRESS))
+               if (!irq_check_poll(desc))
+                       goto out_unlock;
+
+       desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
        kstat_incr_irqs_this_cpu(irq, desc);
 
-       action = desc->action;
-       if (unlikely(!action || (desc->status & IRQ_DISABLED)))
+       if (unlikely(!desc->action || (desc->istate & IRQS_DISABLED)))
                goto out_unlock;
 
-       desc->status |= IRQ_INPROGRESS;
-       raw_spin_unlock(&desc->lock);
+       handle_irq_event(desc);
 
-       action_ret = handle_IRQ_event(irq, action);
-       if (!noirqdebug)
-               note_interrupt(irq, desc, action_ret);
-
-       raw_spin_lock(&desc->lock);
-       desc->status &= ~IRQ_INPROGRESS;
 out_unlock:
        raw_spin_unlock(&desc->lock);
 }
@@ -501,42 +445,42 @@ out_unlock:
 void
 handle_level_irq(unsigned int irq, struct irq_desc *desc)
 {
-       struct irqaction *action;
-       irqreturn_t action_ret;
-
        raw_spin_lock(&desc->lock);
        mask_ack_irq(desc);
 
-       if (unlikely(desc->status & IRQ_INPROGRESS))
-               goto out_unlock;
-       desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
+       if (unlikely(desc->istate & IRQS_INPROGRESS))
+               if (!irq_check_poll(desc))
+                       goto out_unlock;
+
+       desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
        kstat_incr_irqs_this_cpu(irq, desc);
 
        /*
         * If its disabled or no action available
         * keep it masked and get out of here
         */
-       action = desc->action;
-       if (unlikely(!action || (desc->status & IRQ_DISABLED)))
+       if (unlikely(!desc->action || (desc->istate & IRQS_DISABLED)))
                goto out_unlock;
 
-       desc->status |= IRQ_INPROGRESS;
-       raw_spin_unlock(&desc->lock);
-
-       action_ret = handle_IRQ_event(irq, action);
-       if (!noirqdebug)
-               note_interrupt(irq, desc, action_ret);
+       handle_irq_event(desc);
 
-       raw_spin_lock(&desc->lock);
-       desc->status &= ~IRQ_INPROGRESS;
-
-       if (!(desc->status & (IRQ_DISABLED | IRQ_ONESHOT)))
+       if (!(desc->istate & (IRQS_DISABLED | IRQS_ONESHOT)))
                unmask_irq(desc);
 out_unlock:
        raw_spin_unlock(&desc->lock);
 }
 EXPORT_SYMBOL_GPL(handle_level_irq);
 
+#ifdef CONFIG_IRQ_PREFLOW_FASTEOI
+static inline void preflow_handler(struct irq_desc *desc)
+{
+       if (desc->preflow_handler)
+               desc->preflow_handler(&desc->irq_data);
+}
+#else
+static inline void preflow_handler(struct irq_desc *desc) { }
+#endif
+
 /**
  *     handle_fasteoi_irq - irq handler for transparent controllers
  *     @irq:   the interrupt number
@@ -550,42 +494,41 @@ EXPORT_SYMBOL_GPL(handle_level_irq);
 void
 handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
 {
-       struct irqaction *action;
-       irqreturn_t action_ret;
-
        raw_spin_lock(&desc->lock);
 
-       if (unlikely(desc->status & IRQ_INPROGRESS))
-               goto out;
+       if (unlikely(desc->istate & IRQS_INPROGRESS))
+               if (!irq_check_poll(desc))
+                       goto out;
 
-       desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
+       desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
        kstat_incr_irqs_this_cpu(irq, desc);
 
        /*
         * If its disabled or no action available
         * then mask it and get out of here:
         */
-       action = desc->action;
-       if (unlikely(!action || (desc->status & IRQ_DISABLED))) {
-               desc->status |= IRQ_PENDING;
+       if (unlikely(!desc->action || (desc->istate & IRQS_DISABLED))) {
+               irq_compat_set_pending(desc);
+               desc->istate |= IRQS_PENDING;
                mask_irq(desc);
                goto out;
        }
 
-       desc->status |= IRQ_INPROGRESS;
-       desc->status &= ~IRQ_PENDING;
-       raw_spin_unlock(&desc->lock);
+       if (desc->istate & IRQS_ONESHOT)
+               mask_irq(desc);
 
-       action_ret = handle_IRQ_event(irq, action);
-       if (!noirqdebug)
-               note_interrupt(irq, desc, action_ret);
+       preflow_handler(desc);
+       handle_irq_event(desc);
 
-       raw_spin_lock(&desc->lock);
-       desc->status &= ~IRQ_INPROGRESS;
-out:
+out_eoi:
        desc->irq_data.chip->irq_eoi(&desc->irq_data);
-
+out_unlock:
        raw_spin_unlock(&desc->lock);
+       return;
+out:
+       if (!(desc->irq_data.chip->flags & IRQCHIP_EOI_IF_HANDLED))
+               goto out_eoi;
+       goto out_unlock;
 }
 
 /**
@@ -609,32 +552,28 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc)
 {
        raw_spin_lock(&desc->lock);
 
-       desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
-
+       desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
        /*
         * If we're currently running this IRQ, or its disabled,
         * we shouldn't process the IRQ. Mark it pending, handle
         * the necessary masking and go out
         */
-       if (unlikely((desc->status & (IRQ_INPROGRESS | IRQ_DISABLED)) ||
-                   !desc->action)) {
-               desc->status |= (IRQ_PENDING | IRQ_MASKED);
-               mask_ack_irq(desc);
-               goto out_unlock;
+       if (unlikely((desc->istate & (IRQS_DISABLED | IRQS_INPROGRESS) ||
+                     !desc->action))) {
+               if (!irq_check_poll(desc)) {
+                       irq_compat_set_pending(desc);
+                       desc->istate |= IRQS_PENDING;
+                       mask_ack_irq(desc);
+                       goto out_unlock;
+               }
        }
        kstat_incr_irqs_this_cpu(irq, desc);
 
        /* Start handling the irq */
        desc->irq_data.chip->irq_ack(&desc->irq_data);
 
-       /* Mark the IRQ currently in progress.*/
-       desc->status |= IRQ_INPROGRESS;
-
        do {
-               struct irqaction *action = desc->action;
-               irqreturn_t action_ret;
-
-               if (unlikely(!action)) {
+               if (unlikely(!desc->action)) {
                        mask_irq(desc);
                        goto out_unlock;
                }
@@ -644,22 +583,17 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc)
                 * one, we could have masked the irq.
                 * Renable it, if it was not disabled in meantime.
                 */
-               if (unlikely((desc->status &
-                              (IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) ==
-                             (IRQ_PENDING | IRQ_MASKED))) {
-                       unmask_irq(desc);
+               if (unlikely(desc->istate & IRQS_PENDING)) {
+                       if (!(desc->istate & IRQS_DISABLED) &&
+                           (desc->istate & IRQS_MASKED))
+                               unmask_irq(desc);
                }
 
-               desc->status &= ~IRQ_PENDING;
-               raw_spin_unlock(&desc->lock);
-               action_ret = handle_IRQ_event(irq, action);
-               if (!noirqdebug)
-                       note_interrupt(irq, desc, action_ret);
-               raw_spin_lock(&desc->lock);
+               handle_irq_event(desc);
 
-       } while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING);
+       } while ((desc->istate & IRQS_PENDING) &&
+                !(desc->istate & IRQS_DISABLED));
 
-       desc->status &= ~IRQ_INPROGRESS;
 out_unlock:
        raw_spin_unlock(&desc->lock);
 }
@@ -674,103 +608,84 @@ out_unlock:
 void
 handle_percpu_irq(unsigned int irq, struct irq_desc *desc)
 {
-       irqreturn_t action_ret;
+       struct irq_chip *chip = irq_desc_get_chip(desc);
 
        kstat_incr_irqs_this_cpu(irq, desc);
 
-       if (desc->irq_data.chip->irq_ack)
-               desc->irq_data.chip->irq_ack(&desc->irq_data);
+       if (chip->irq_ack)
+               chip->irq_ack(&desc->irq_data);
 
-       action_ret = handle_IRQ_event(irq, desc->action);
-       if (!noirqdebug)
-               note_interrupt(irq, desc, action_ret);
+       handle_irq_event_percpu(desc, desc->action);
 
-       if (desc->irq_data.chip->irq_eoi)
-               desc->irq_data.chip->irq_eoi(&desc->irq_data);
+       if (chip->irq_eoi)
+               chip->irq_eoi(&desc->irq_data);
 }
 
 void
-__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
+__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
                  const char *name)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;
+       struct irq_desc *desc = irq_get_desc_buslock(irq, &flags);
 
-       if (!desc) {
-               printk(KERN_ERR
-                      "Trying to install type control for IRQ%d\n", irq);
+       if (!desc)
                return;
-       }
 
-       if (!handle)
+       if (!handle) {
                handle = handle_bad_irq;
-       else if (desc->irq_data.chip == &no_irq_chip) {
-               printk(KERN_WARNING "Trying to install %sinterrupt handler "
-                      "for IRQ%d\n", is_chained ? "chained " : "", irq);
-               /*
-                * Some ARM implementations install a handler for really dumb
-                * interrupt hardware without setting an irq_chip. This worked
-                * with the ARM no_irq_chip but the check in setup_irq would
-                * prevent us to setup the interrupt at all. Switch it to
-                * dummy_irq_chip for easy transition.
-                */
-               desc->irq_data.chip = &dummy_irq_chip;
+       } else {
+               if (WARN_ON(desc->irq_data.chip == &no_irq_chip))
+                       goto out;
        }
 
-       chip_bus_lock(desc);
-       raw_spin_lock_irqsave(&desc->lock, flags);
-
        /* Uninstall? */
        if (handle == handle_bad_irq) {
                if (desc->irq_data.chip != &no_irq_chip)
                        mask_ack_irq(desc);
-               desc->status |= IRQ_DISABLED;
+               irq_compat_set_disabled(desc);
+               desc->istate |= IRQS_DISABLED;
                desc->depth = 1;
        }
        desc->handle_irq = handle;
        desc->name = name;
 
        if (handle != handle_bad_irq && is_chained) {
-               desc->status &= ~IRQ_DISABLED;
-               desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE;
-               desc->depth = 0;
-               desc->irq_data.chip->irq_startup(&desc->irq_data);
+               irq_settings_set_noprobe(desc);
+               irq_settings_set_norequest(desc);
+               irq_startup(desc);
        }
-       raw_spin_unlock_irqrestore(&desc->lock, flags);
-       chip_bus_sync_unlock(desc);
-}
-EXPORT_SYMBOL_GPL(__set_irq_handler);
-
-void
-set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip,
-                        irq_flow_handler_t handle)
-{
-       set_irq_chip(irq, chip);
-       __set_irq_handler(irq, handle, 0, NULL);
+out:
+       irq_put_desc_busunlock(desc, flags);
 }
+EXPORT_SYMBOL_GPL(__irq_set_handler);
 
 void
-set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
+irq_set_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
                              irq_flow_handler_t handle, const char *name)
 {
-       set_irq_chip(irq, chip);
-       __set_irq_handler(irq, handle, 0, name);
+       irq_set_chip(irq, chip);
+       __irq_set_handler(irq, handle, 0, name);
 }
 
 void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;
+       struct irq_desc *desc = irq_get_desc_lock(irq, &flags);
 
        if (!desc)
                return;
+       irq_settings_clr_and_set(desc, clr, set);
+
+       irqd_clear(&desc->irq_data, IRQD_NO_BALANCING | IRQD_PER_CPU |
+                  IRQD_TRIGGER_MASK | IRQD_LEVEL | IRQD_MOVE_PCNTXT);
+       if (irq_settings_has_no_balance_set(desc))
+               irqd_set(&desc->irq_data, IRQD_NO_BALANCING);
+       if (irq_settings_is_per_cpu(desc))
+               irqd_set(&desc->irq_data, IRQD_PER_CPU);
+       if (irq_settings_can_move_pcntxt(desc))
+               irqd_set(&desc->irq_data, IRQD_MOVE_PCNTXT);
 
-       /* Sanitize flags */
-       set &= IRQF_MODIFY_MASK;
-       clr &= IRQF_MODIFY_MASK;
+       irqd_set(&desc->irq_data, irq_settings_get_trigger_mask(desc));
 
-       raw_spin_lock_irqsave(&desc->lock, flags);
-       desc->status &= ~clr;
-       desc->status |= set;
-       raw_spin_unlock_irqrestore(&desc->lock, flags);
+       irq_put_desc_unlock(desc, flags);
 }
diff --git a/kernel/irq/compat.h b/kernel/irq/compat.h
new file mode 100644 (file)
index 0000000..6bbaf66
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Compat layer for transition period
+ */
+#ifndef CONFIG_GENERIC_HARDIRQS_NO_COMPAT
+static inline void irq_compat_set_progress(struct irq_desc *desc)
+{
+       desc->status |= IRQ_INPROGRESS;
+}
+
+static inline void irq_compat_clr_progress(struct irq_desc *desc)
+{
+       desc->status &= ~IRQ_INPROGRESS;
+}
+static inline void irq_compat_set_disabled(struct irq_desc *desc)
+{
+       desc->status |= IRQ_DISABLED;
+}
+static inline void irq_compat_clr_disabled(struct irq_desc *desc)
+{
+       desc->status &= ~IRQ_DISABLED;
+}
+static inline void irq_compat_set_pending(struct irq_desc *desc)
+{
+       desc->status |= IRQ_PENDING;
+}
+
+static inline void irq_compat_clr_pending(struct irq_desc *desc)
+{
+       desc->status &= ~IRQ_PENDING;
+}
+static inline void irq_compat_set_masked(struct irq_desc *desc)
+{
+       desc->status |= IRQ_MASKED;
+}
+
+static inline void irq_compat_clr_masked(struct irq_desc *desc)
+{
+       desc->status &= ~IRQ_MASKED;
+}
+static inline void irq_compat_set_move_pending(struct irq_desc *desc)
+{
+       desc->status |= IRQ_MOVE_PENDING;
+}
+
+static inline void irq_compat_clr_move_pending(struct irq_desc *desc)
+{
+       desc->status &= ~IRQ_MOVE_PENDING;
+}
+static inline void irq_compat_set_affinity(struct irq_desc *desc)
+{
+       desc->status |= IRQ_AFFINITY_SET;
+}
+
+static inline void irq_compat_clr_affinity(struct irq_desc *desc)
+{
+       desc->status &= ~IRQ_AFFINITY_SET;
+}
+#else
+static inline void irq_compat_set_progress(struct irq_desc *desc) { }
+static inline void irq_compat_clr_progress(struct irq_desc *desc) { }
+static inline void irq_compat_set_disabled(struct irq_desc *desc) { }
+static inline void irq_compat_clr_disabled(struct irq_desc *desc) { }
+static inline void irq_compat_set_pending(struct irq_desc *desc) { }
+static inline void irq_compat_clr_pending(struct irq_desc *desc) { }
+static inline void irq_compat_set_masked(struct irq_desc *desc) { }
+static inline void irq_compat_clr_masked(struct irq_desc *desc) { }
+static inline void irq_compat_set_move_pending(struct irq_desc *desc) { }
+static inline void irq_compat_clr_move_pending(struct irq_desc *desc) { }
+static inline void irq_compat_set_affinity(struct irq_desc *desc) { }
+static inline void irq_compat_clr_affinity(struct irq_desc *desc) { }
+#endif
+
diff --git a/kernel/irq/debug.h b/kernel/irq/debug.h
new file mode 100644 (file)
index 0000000..d1a33b7
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Debugging printout:
+ */
+
+#include <linux/kallsyms.h>
+
+#define P(f) if (desc->status & f) printk("%14s set\n", #f)
+#define PS(f) if (desc->istate & f) printk("%14s set\n", #f)
+
+static inline void print_irq_desc(unsigned int irq, struct irq_desc *desc)
+{
+       printk("irq %d, desc: %p, depth: %d, count: %d, unhandled: %d\n",
+               irq, desc, desc->depth, desc->irq_count, desc->irqs_unhandled);
+       printk("->handle_irq():  %p, ", desc->handle_irq);
+       print_symbol("%s\n", (unsigned long)desc->handle_irq);
+       printk("->irq_data.chip(): %p, ", desc->irq_data.chip);
+       print_symbol("%s\n", (unsigned long)desc->irq_data.chip);
+       printk("->action(): %p\n", desc->action);
+       if (desc->action) {
+               printk("->action->handler(): %p, ", desc->action->handler);
+               print_symbol("%s\n", (unsigned long)desc->action->handler);
+       }
+
+       P(IRQ_LEVEL);
+       P(IRQ_PER_CPU);
+       P(IRQ_NOPROBE);
+       P(IRQ_NOREQUEST);
+       P(IRQ_NOAUTOEN);
+
+       PS(IRQS_AUTODETECT);
+       PS(IRQS_INPROGRESS);
+       PS(IRQS_REPLAY);
+       PS(IRQS_WAITING);
+       PS(IRQS_DISABLED);
+       PS(IRQS_PENDING);
+       PS(IRQS_MASKED);
+}
+
+#undef P
+#undef PS
index 3540a71..517561f 100644 (file)
@@ -51,30 +51,92 @@ static void warn_no_thread(unsigned int irq, struct irqaction *action)
               "but no thread function available.", irq, action->name);
 }
 
-/**
- * handle_IRQ_event - irq action chain handler
- * @irq:       the interrupt number
- * @action:    the interrupt action chain for this irq
- *
- * Handles the action chain of an irq event
- */
-irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
+static void irq_wake_thread(struct irq_desc *desc, struct irqaction *action)
+{
+       /*
+        * Wake up the handler thread for this action. In case the
+        * thread crashed and was killed we just pretend that we
+        * handled the interrupt. The hardirq handler has disabled the
+        * device interrupt, so no irq storm is lurking. If the
+        * RUNTHREAD bit is already set, nothing to do.
+        */
+       if (test_bit(IRQTF_DIED, &action->thread_flags) ||
+           test_and_set_bit(IRQTF_RUNTHREAD, &action->thread_flags))
+               return;
+
+       /*
+        * It's safe to OR the mask lockless here. We have only two
+        * places which write to threads_oneshot: This code and the
+        * irq thread.
+        *
+        * This code is the hard irq context and can never run on two
+        * cpus in parallel. If it ever does we have more serious
+        * problems than this bitmask.
+        *
+        * The irq threads of this irq which clear their "running" bit
+        * in threads_oneshot are serialized via desc->lock against
+        * each other and they are serialized against this code by
+        * IRQS_INPROGRESS.
+        *
+        * Hard irq handler:
+        *
+        *      spin_lock(desc->lock);
+        *      desc->state |= IRQS_INPROGRESS;
+        *      spin_unlock(desc->lock);
+        *      set_bit(IRQTF_RUNTHREAD, &action->thread_flags);
+        *      desc->threads_oneshot |= mask;
+        *      spin_lock(desc->lock);
+        *      desc->state &= ~IRQS_INPROGRESS;
+        *      spin_unlock(desc->lock);
+        *
+        * irq thread:
+        *
+        * again:
+        *      spin_lock(desc->lock);
+        *      if (desc->state & IRQS_INPROGRESS) {
+        *              spin_unlock(desc->lock);
+        *              while(desc->state & IRQS_INPROGRESS)
+        *                      cpu_relax();
+        *              goto again;
+        *      }
+        *      if (!test_bit(IRQTF_RUNTHREAD, &action->thread_flags))
+        *              desc->threads_oneshot &= ~mask;
+        *      spin_unlock(desc->lock);
+        *
+        * So either the thread waits for us to clear IRQS_INPROGRESS
+        * or we are waiting in the flow handler for desc->lock to be
+        * released before we reach this point. The thread also checks
+        * IRQTF_RUNTHREAD under desc->lock. If set it leaves
+        * threads_oneshot untouched and runs the thread another time.
+        */
+       desc->threads_oneshot |= action->thread_mask;
+       wake_up_process(action->thread);
+}
+
+irqreturn_t
+handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
 {
-       irqreturn_t ret, retval = IRQ_NONE;
-       unsigned int status = 0;
+       irqreturn_t retval = IRQ_NONE;
+       unsigned int random = 0, irq = desc->irq_data.irq;
 
        do {
+               irqreturn_t res;
+
                trace_irq_handler_entry(irq, action);
-               ret = action->handler(irq, action->dev_id);
-               trace_irq_handler_exit(irq, action, ret);
+               res = action->handler(irq, action->dev_id);
+               trace_irq_handler_exit(irq, action, res);
 
-               switch (ret) {
+               if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pF enabled interrupts\n",
+                             irq, action->handler))
+                       local_irq_disable();
+
+               switch (res) {
                case IRQ_WAKE_THREAD:
                        /*
                         * Set result to handled so the spurious check
                         * does not trigger.
                         */
-                       ret = IRQ_HANDLED;
+                       res = IRQ_HANDLED;
 
                        /*
                         * Catch drivers which return WAKE_THREAD but
@@ -85,36 +147,56 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
                                break;
                        }
 
-                       /*
-                        * Wake up the handler thread for this
-                        * action. In case the thread crashed and was
-                        * killed we just pretend that we handled the
-                        * interrupt. The hardirq handler above has
-                        * disabled the device interrupt, so no irq
-                        * storm is lurking.
-                        */
-                       if (likely(!test_bit(IRQTF_DIED,
-                                            &action->thread_flags))) {
-                               set_bit(IRQTF_RUNTHREAD, &action->thread_flags);
-                               wake_up_process(action->thread);
-                       }
+                       irq_wake_thread(desc, action);
 
                        /* Fall through to add to randomness */
                case IRQ_HANDLED:
-                       status |= action->flags;
+                       random |= action->flags;
                        break;
 
                default:
                        break;
                }
 
-               retval |= ret;
+               retval |= res;
                action = action->next;
        } while (action);
 
-       if (status & IRQF_SAMPLE_RANDOM)
+       if (random & IRQF_SAMPLE_RANDOM)
                add_interrupt_randomness(irq);
-       local_irq_disable();
 
+       if (!noirqdebug)
+               note_interrupt(irq, desc, retval);
        return retval;
 }
+
+irqreturn_t handle_irq_event(struct irq_desc *desc)
+{
+       struct irqaction *action = desc->action;
+       irqreturn_t ret;
+
+       irq_compat_clr_pending(desc);
+       desc->istate &= ~IRQS_PENDING;
+       irq_compat_set_progress(desc);
+       desc->istate |= IRQS_INPROGRESS;
+       raw_spin_unlock(&desc->lock);
+
+       ret = handle_irq_event_percpu(desc, action);
+
+       raw_spin_lock(&desc->lock);
+       desc->istate &= ~IRQS_INPROGRESS;
+       irq_compat_clr_progress(desc);
+       return ret;
+}
+
+/**
+ * handle_IRQ_event - irq action chain handler
+ * @irq:       the interrupt number
+ * @action:    the interrupt action chain for this irq
+ *
+ * Handles the action chain of an irq event
+ */
+irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
+{
+       return handle_irq_event_percpu(irq_to_desc(irq), action);
+}
index 4571ae7..6c6ec9a 100644 (file)
 /*
  * IRQ subsystem internal functions and variables:
+ *
+ * Do not ever include this file from anything else than
+ * kernel/irq/. Do not even think about using any information outside
+ * of this file for your non core code.
  */
 #include <linux/irqdesc.h>
 
+#ifdef CONFIG_SPARSE_IRQ
+# define IRQ_BITMAP_BITS       (NR_IRQS + 8196)
+#else
+# define IRQ_BITMAP_BITS       NR_IRQS
+#endif
+
+#define istate core_internal_state__do_not_mess_with_it
+
+#ifdef CONFIG_GENERIC_HARDIRQS_NO_COMPAT
+# define status status_use_accessors
+#endif
+
 extern int noirqdebug;
 
+/*
+ * Bits used by threaded handlers:
+ * IRQTF_RUNTHREAD - signals that the interrupt handler thread should run
+ * IRQTF_DIED      - handler thread died
+ * IRQTF_WARNED    - warning "IRQ_WAKE_THREAD w/o thread_fn" has been printed
+ * IRQTF_AFFINITY  - irq thread is requested to adjust affinity
+ * IRQTF_FORCED_THREAD  - irq action is force threaded
+ */
+enum {
+       IRQTF_RUNTHREAD,
+       IRQTF_DIED,
+       IRQTF_WARNED,
+       IRQTF_AFFINITY,
+       IRQTF_FORCED_THREAD,
+};
+
+/*
+ * Bit masks for desc->state
+ *
+ * IRQS_AUTODETECT             - autodetection in progress
+ * IRQS_SPURIOUS_DISABLED      - was disabled due to spurious interrupt
+ *                               detection
+ * IRQS_POLL_INPROGRESS                - polling in progress
+ * IRQS_INPROGRESS             - Interrupt in progress
+ * IRQS_ONESHOT                        - irq is not unmasked in primary handler
+ * IRQS_REPLAY                 - irq is replayed
+ * IRQS_WAITING                        - irq is waiting
+ * IRQS_DISABLED               - irq is disabled
+ * IRQS_PENDING                        - irq is pending and replayed later
+ * IRQS_MASKED                 - irq is masked
+ * IRQS_SUSPENDED              - irq is suspended
+ */
+enum {
+       IRQS_AUTODETECT         = 0x00000001,
+       IRQS_SPURIOUS_DISABLED  = 0x00000002,
+       IRQS_POLL_INPROGRESS    = 0x00000008,
+       IRQS_INPROGRESS         = 0x00000010,
+       IRQS_ONESHOT            = 0x00000020,
+       IRQS_REPLAY             = 0x00000040,
+       IRQS_WAITING            = 0x00000080,
+       IRQS_DISABLED           = 0x00000100,
+       IRQS_PENDING            = 0x00000200,
+       IRQS_MASKED             = 0x00000400,
+       IRQS_SUSPENDED          = 0x00000800,
+};
+
+#include "compat.h"
+#include "debug.h"
+#include "settings.h"
+
 #define irq_data_to_desc(data) container_of(data, struct irq_desc, irq_data)
 
 /* Set default functions for irq_chip structures: */
 extern void irq_chip_set_defaults(struct irq_chip *chip);
 
-/* Set default handler: */
-extern void compat_irq_chip_set_default_handler(struct irq_desc *desc);
-
 extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
                unsigned long flags);
 extern void __disable_irq(struct irq_desc *desc, unsigned int irq, bool susp);
 extern void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume);
 
+extern int irq_startup(struct irq_desc *desc);
+extern void irq_shutdown(struct irq_desc *desc);
+extern void irq_enable(struct irq_desc *desc);
+extern void irq_disable(struct irq_desc *desc);
+extern void mask_irq(struct irq_desc *desc);
+extern void unmask_irq(struct irq_desc *desc);
+
 extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);
 
+irqreturn_t handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action);
+irqreturn_t handle_irq_event(struct irq_desc *desc);
+
 /* Resending of interrupts :*/
 void check_irq_resend(struct irq_desc *desc, unsigned int irq);
+bool irq_wait_for_poll(struct irq_desc *desc);
 
 #ifdef CONFIG_PROC_FS
 extern void register_irq_proc(unsigned int irq, struct irq_desc *desc);
@@ -37,20 +111,10 @@ static inline void unregister_handler_proc(unsigned int irq,
                                           struct irqaction *action) { }
 #endif
 
-extern int irq_select_affinity_usr(unsigned int irq);
+extern int irq_select_affinity_usr(unsigned int irq, struct cpumask *mask);
 
 extern void irq_set_thread_affinity(struct irq_desc *desc);
 
-#ifndef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED
-static inline void irq_end(unsigned int irq, struct irq_desc *desc)
-{
-       if (desc->irq_data.chip && desc->irq_data.chip->end)
-               desc->irq_data.chip->end(irq);
-}
-#else
-static inline void irq_end(unsigned int irq, struct irq_desc *desc) { }
-#endif
-
 /* Inline functions for support of irq chips on slow busses */
 static inline void chip_bus_lock(struct irq_desc *desc)
 {
@@ -64,43 +128,60 @@ static inline void chip_bus_sync_unlock(struct irq_desc *desc)
                desc->irq_data.chip->irq_bus_sync_unlock(&desc->irq_data);
 }
 
+struct irq_desc *
+__irq_get_desc_lock(unsigned int irq, unsigned long *flags, bool bus);
+void __irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags, bool bus);
+
+static inline struct irq_desc *
+irq_get_desc_buslock(unsigned int irq, unsigned long *flags)
+{
+       return __irq_get_desc_lock(irq, flags, true);
+}
+
+static inline void
+irq_put_desc_busunlock(struct irq_desc *desc, unsigned long flags)
+{
+       __irq_put_desc_unlock(desc, flags, true);
+}
+
+static inline struct irq_desc *
+irq_get_desc_lock(unsigned int irq, unsigned long *flags)
+{
+       return __irq_get_desc_lock(irq, flags, false);
+}
+
+static inline void
+irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags)
+{
+       __irq_put_desc_unlock(desc, flags, false);
+}
+
 /*
- * Debugging printout:
+ * Manipulation functions for irq_data.state
  */
+static inline void irqd_set_move_pending(struct irq_data *d)
+{
+       d->state_use_accessors |= IRQD_SETAFFINITY_PENDING;
+       irq_compat_set_move_pending(irq_data_to_desc(d));
+}
 
-#include <linux/kallsyms.h>
-
-#define P(f) if (desc->status & f) printk("%14s set\n", #f)
+static inline void irqd_clr_move_pending(struct irq_data *d)
+{
+       d->state_use_accessors &= ~IRQD_SETAFFINITY_PENDING;
+       irq_compat_clr_move_pending(irq_data_to_desc(d));
+}
 
-static inline void print_irq_desc(unsigned int irq, struct irq_desc *desc)
+static inline void irqd_clear(struct irq_data *d, unsigned int mask)
 {
-       printk("irq %d, desc: %p, depth: %d, count: %d, unhandled: %d\n",
-               irq, desc, desc->depth, desc->irq_count, desc->irqs_unhandled);
-       printk("->handle_irq():  %p, ", desc->handle_irq);
-       print_symbol("%s\n", (unsigned long)desc->handle_irq);
-       printk("->irq_data.chip(): %p, ", desc->irq_data.chip);
-       print_symbol("%s\n", (unsigned long)desc->irq_data.chip);
-       printk("->action(): %p\n", desc->action);
-       if (desc->action) {
-               printk("->action->handler(): %p, ", desc->action->handler);
-               print_symbol("%s\n", (unsigned long)desc->action->handler);
-       }
-
-       P(IRQ_INPROGRESS);
-       P(IRQ_DISABLED);
-       P(IRQ_PENDING);
-       P(IRQ_REPLAY);
-       P(IRQ_AUTODETECT);
-       P(IRQ_WAITING);
-       P(IRQ_LEVEL);
-       P(IRQ_MASKED);
-#ifdef CONFIG_IRQ_PER_CPU
-       P(IRQ_PER_CPU);
-#endif
-       P(IRQ_NOPROBE);
-       P(IRQ_NOREQUEST);
-       P(IRQ_NOAUTOEN);
+       d->state_use_accessors &= ~mask;
 }
 
-#undef P
+static inline void irqd_set(struct irq_data *d, unsigned int mask)
+{
+       d->state_use_accessors |= mask;
+}
 
+static inline bool irqd_has_set(struct irq_data *d, unsigned int mask)
+{
+       return d->state_use_accessors & mask;
+}
index 282f202..dbccc79 100644 (file)
@@ -79,7 +79,8 @@ static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node)
        desc->irq_data.chip_data = NULL;
        desc->irq_data.handler_data = NULL;
        desc->irq_data.msi_desc = NULL;
-       desc->status = IRQ_DEFAULT_INIT_FLAGS;
+       irq_settings_clr_and_set(desc, ~0, _IRQ_DEFAULT_INIT_FLAGS);
+       desc->istate = IRQS_DISABLED;
        desc->handle_irq = handle_bad_irq;
        desc->depth = 1;
        desc->irq_count = 0;
@@ -94,7 +95,7 @@ int nr_irqs = NR_IRQS;
 EXPORT_SYMBOL_GPL(nr_irqs);
 
 static DEFINE_MUTEX(sparse_irq_lock);
-static DECLARE_BITMAP(allocated_irqs, NR_IRQS);
+static DECLARE_BITMAP(allocated_irqs, IRQ_BITMAP_BITS);
 
 #ifdef CONFIG_SPARSE_IRQ
 
@@ -206,6 +207,14 @@ struct irq_desc * __ref irq_to_desc_alloc_node(unsigned int irq, int node)
        return NULL;
 }
 
+static int irq_expand_nr_irqs(unsigned int nr)
+{
+       if (nr > IRQ_BITMAP_BITS)
+               return -ENOMEM;
+       nr_irqs = nr;
+       return 0;
+}
+
 int __init early_irq_init(void)
 {
        int i, initcnt, node = first_online_node;
@@ -217,6 +226,15 @@ int __init early_irq_init(void)
        initcnt = arch_probe_nr_irqs();
        printk(KERN_INFO "NR_IRQS:%d nr_irqs:%d %d\n", NR_IRQS, nr_irqs, initcnt);
 
+       if (WARN_ON(nr_irqs > IRQ_BITMAP_BITS))
+               nr_irqs = IRQ_BITMAP_BITS;
+
+       if (WARN_ON(initcnt > IRQ_BITMAP_BITS))
+               initcnt = IRQ_BITMAP_BITS;
+
+       if (initcnt > nr_irqs)
+               nr_irqs = initcnt;
+
        for (i = 0; i < initcnt; i++) {
                desc = alloc_desc(i, node);
                set_bit(i, allocated_irqs);
@@ -229,7 +247,7 @@ int __init early_irq_init(void)
 
 struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
        [0 ... NR_IRQS-1] = {
-               .status         = IRQ_DEFAULT_INIT_FLAGS,
+               .istate         = IRQS_DISABLED,
                .handle_irq     = handle_bad_irq,
                .depth          = 1,
                .lock           = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),
@@ -251,8 +269,8 @@ int __init early_irq_init(void)
        for (i = 0; i < count; i++) {
                desc[i].irq_data.irq = i;
                desc[i].irq_data.chip = &no_irq_chip;
-               /* TODO : do this allocation on-demand ... */
                desc[i].kstat_irqs = alloc_percpu(unsigned int);
+               irq_settings_clr_and_set(desc, ~0, _IRQ_DEFAULT_INIT_FLAGS);
                alloc_masks(desc + i, GFP_KERNEL, node);
                desc_smp_init(desc + i, node);
                lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);
@@ -277,24 +295,14 @@ static void free_desc(unsigned int irq)
 
 static inline int alloc_descs(unsigned int start, unsigned int cnt, int node)
 {
-#if defined(CONFIG_KSTAT_IRQS_ONDEMAND)
-       struct irq_desc *desc;
-       unsigned int i;
-
-       for (i = 0; i < cnt; i++) {
-               desc = irq_to_desc(start + i);
-               if (desc && !desc->kstat_irqs) {
-                       unsigned int __percpu *stats = alloc_percpu(unsigned int);
-
-                       if (!stats)
-                               return -1;
-                       if (cmpxchg(&desc->kstat_irqs, NULL, stats) != NULL)
-                               free_percpu(stats);
-               }
-       }
-#endif
        return start;
 }
+
+static int irq_expand_nr_irqs(unsigned int nr)
+{
+       return -ENOMEM;
+}
+
 #endif /* !CONFIG_SPARSE_IRQ */
 
 /* Dynamic interrupt handling */
@@ -338,14 +346,17 @@ irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node)
 
        mutex_lock(&sparse_irq_lock);
 
-       start = bitmap_find_next_zero_area(allocated_irqs, nr_irqs, from, cnt, 0);
+       start = bitmap_find_next_zero_area(allocated_irqs, IRQ_BITMAP_BITS,
+                                          from, cnt, 0);
        ret = -EEXIST;
        if (irq >=0 && start != irq)
                goto err;
 
-       ret = -ENOMEM;
-       if (start >= nr_irqs)
-               goto err;
+       if (start + cnt > nr_irqs) {
+               ret = irq_expand_nr_irqs(start + cnt);
+               if (ret)
+                       goto err;
+       }
 
        bitmap_set(allocated_irqs, start, cnt);
        mutex_unlock(&sparse_irq_lock);
@@ -392,6 +403,26 @@ unsigned int irq_get_next_irq(unsigned int offset)
        return find_next_bit(allocated_irqs, nr_irqs, offset);
 }
 
+struct irq_desc *
+__irq_get_desc_lock(unsigned int irq, unsigned long *flags, bool bus)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+
+       if (desc) {
+               if (bus)
+                       chip_bus_lock(desc);
+               raw_spin_lock_irqsave(&desc->lock, *flags);
+       }
+       return desc;
+}
+
+void __irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags, bool bus)
+{
+       raw_spin_unlock_irqrestore(&desc->lock, flags);
+       if (bus)
+               chip_bus_sync_unlock(desc);
+}
+
 /**
  * dynamic_irq_cleanup - cleanup a dynamically allocated irq
  * @irq:       irq number to initialize
index 0caa59f..acd599a 100644 (file)
 
 #include "internals.h"
 
+#ifdef CONFIG_IRQ_FORCED_THREADING
+__read_mostly bool force_irqthreads;
+
+static int __init setup_forced_irqthreads(char *arg)
+{
+       force_irqthreads = true;
+       return 0;
+}
+early_param("threadirqs", setup_forced_irqthreads);
+#endif
+
 /**
  *     synchronize_irq - wait for pending IRQ handlers (on other CPUs)
  *     @irq: interrupt number to wait for
@@ -30,7 +41,7 @@
 void synchronize_irq(unsigned int irq)
 {
        struct irq_desc *desc = irq_to_desc(irq);
-       unsigned int status;
+       unsigned int state;
 
        if (!desc)
                return;
@@ -42,16 +53,16 @@ void synchronize_irq(unsigned int irq)
                 * Wait until we're out of the critical section.  This might
                 * give the wrong answer due to the lack of memory barriers.
                 */
-               while (desc->status & IRQ_INPROGRESS)
+               while (desc->istate & IRQS_INPROGRESS)
                        cpu_relax();
 
                /* Ok, that indicated we're done: double-check carefully. */
                raw_spin_lock_irqsave(&desc->lock, flags);
-               status = desc->status;
+               state = desc->istate;
                raw_spin_unlock_irqrestore(&desc->lock, flags);
 
                /* Oops, that failed? */
-       } while (status & IRQ_INPROGRESS);
+       } while (state & IRQS_INPROGRESS);
 
        /*
         * We made sure that no hardirq handler is running. Now verify
@@ -73,8 +84,8 @@ int irq_can_set_affinity(unsigned int irq)
 {
        struct irq_desc *desc = irq_to_desc(irq);
 
-       if (CHECK_IRQ_PER_CPU(desc->status) || !desc->irq_data.chip ||
-           !desc->irq_data.chip->irq_set_affinity)
+       if (!desc || !irqd_can_balance(&desc->irq_data) ||
+           !desc->irq_data.chip || !desc->irq_data.chip->irq_set_affinity)
                return 0;
 
        return 1;
@@ -100,67 +111,169 @@ void irq_set_thread_affinity(struct irq_desc *desc)
        }
 }
 
+#ifdef CONFIG_GENERIC_PENDING_IRQ
+static inline bool irq_can_move_pcntxt(struct irq_desc *desc)
+{
+       return irq_settings_can_move_pcntxt(desc);
+}
+static inline bool irq_move_pending(struct irq_desc *desc)
+{
+       return irqd_is_setaffinity_pending(&desc->irq_data);
+}
+static inline void
+irq_copy_pending(struct irq_desc *desc, const struct cpumask *mask)
+{
+       cpumask_copy(desc->pending_mask, mask);
+}
+static inline void
+irq_get_pending(struct cpumask *mask, struct irq_desc *desc)
+{
+       cpumask_copy(mask, desc->pending_mask);
+}
+#else
+static inline bool irq_can_move_pcntxt(struct irq_desc *desc) { return true; }
+static inline bool irq_move_pending(struct irq_desc *desc) { return false; }
+static inline void
+irq_copy_pending(struct irq_desc *desc, const struct cpumask *mask) { }
+static inline void
+irq_get_pending(struct cpumask *mask, struct irq_desc *desc) { }
+#endif
+
 /**
  *     irq_set_affinity - Set the irq affinity of a given irq
  *     @irq:           Interrupt to set affinity
  *     @cpumask:       cpumask
  *
  */
-int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask)
+int irq_set_affinity(unsigned int irq, const struct cpumask *mask)
 {
        struct irq_desc *desc = irq_to_desc(irq);
        struct irq_chip *chip = desc->irq_data.chip;
        unsigned long flags;
+       int ret = 0;
 
        if (!chip->irq_set_affinity)
                return -EINVAL;
 
        raw_spin_lock_irqsave(&desc->lock, flags);
 
-#ifdef CONFIG_GENERIC_PENDING_IRQ
-       if (desc->status & IRQ_MOVE_PCNTXT) {
-               if (!chip->irq_set_affinity(&desc->irq_data, cpumask, false)) {
-                       cpumask_copy(desc->irq_data.affinity, cpumask);
+       if (irq_can_move_pcntxt(desc)) {
+               ret = chip->irq_set_affinity(&desc->irq_data, mask, false);
+               switch (ret) {
+               case IRQ_SET_MASK_OK:
+                       cpumask_copy(desc->irq_data.affinity, mask);
+               case IRQ_SET_MASK_OK_NOCOPY:
                        irq_set_thread_affinity(desc);
+                       ret = 0;
                }
+       } else {
+               irqd_set_move_pending(&desc->irq_data);
+               irq_copy_pending(desc, mask);
        }
-       else {
-               desc->status |= IRQ_MOVE_PENDING;
-               cpumask_copy(desc->pending_mask, cpumask);
-       }
-#else
-       if (!chip->irq_set_affinity(&desc->irq_data, cpumask, false)) {
-               cpumask_copy(desc->irq_data.affinity, cpumask);
-               irq_set_thread_affinity(desc);
+
+       if (desc->affinity_notify) {
+               kref_get(&desc->affinity_notify->kref);
+               schedule_work(&desc->affinity_notify->work);
        }
-#endif
-       desc->status |= IRQ_AFFINITY_SET;
+       irq_compat_set_affinity(desc);
+       irqd_set(&desc->irq_data, IRQD_AFFINITY_SET);
        raw_spin_unlock_irqrestore(&desc->lock, flags);
-       return 0;
+       return ret;
 }
 
 int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m)
+{
+       unsigned long flags;
+       struct irq_desc *desc = irq_get_desc_lock(irq, &flags);
+
+       if (!desc)
+               return -EINVAL;
+       desc->affinity_hint = m;
+       irq_put_desc_unlock(desc, flags);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(irq_set_affinity_hint);
+
+static void irq_affinity_notify(struct work_struct *work)
+{
+       struct irq_affinity_notify *notify =
+               container_of(work, struct irq_affinity_notify, work);
+       struct irq_desc *desc = irq_to_desc(notify->irq);
+       cpumask_var_t cpumask;
+       unsigned long flags;
+
+       if (!desc || !alloc_cpumask_var(&cpumask, GFP_KERNEL))
+               goto out;
+
+       raw_spin_lock_irqsave(&desc->lock, flags);
+       if (irq_move_pending(desc))
+               irq_get_pending(cpumask, desc);
+       else
+               cpumask_copy(cpumask, desc->irq_data.affinity);
+       raw_spin_unlock_irqrestore(&desc->lock, flags);
+
+       notify->notify(notify, cpumask);
+
+       free_cpumask_var(cpumask);
+out:
+       kref_put(&notify->kref, notify->release);
+}
+
+/**
+ *     irq_set_affinity_notifier - control notification of IRQ affinity changes
+ *     @irq:           Interrupt for which to enable/disable notification
+ *     @notify:        Context for notification, or %NULL to disable
+ *                     notification.  Function pointers must be initialised;
+ *                     the other fields will be initialised by this function.
+ *
+ *     Must be called in process context.  Notification may only be enabled
+ *     after the IRQ is allocated and must be disabled before the IRQ is
+ *     freed using free_irq().
+ */
+int
+irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify)
 {
        struct irq_desc *desc = irq_to_desc(irq);
+       struct irq_affinity_notify *old_notify;
        unsigned long flags;
 
+       /* The release function is promised process context */
+       might_sleep();
+
        if (!desc)
                return -EINVAL;
 
+       /* Complete initialisation of *notify */
+       if (notify) {
+               notify->irq = irq;
+               kref_init(&notify->kref);
+               INIT_WORK(&notify->work, irq_affinity_notify);
+       }
+
        raw_spin_lock_irqsave(&desc->lock, flags);
-       desc->affinity_hint = m;
+       old_notify = desc->affinity_notify;
+       desc->affinity_notify = notify;
        raw_spin_unlock_irqrestore(&desc->lock, flags);
 
+       if (old_notify)
+               kref_put(&old_notify->kref, old_notify->release);
+
        return 0;
 }
-EXPORT_SYMBOL_GPL(irq_set_affinity_hint);
+EXPORT_SYMBOL_GPL(irq_set_affinity_notifier);
 
 #ifndef CONFIG_AUTO_IRQ_AFFINITY
 /*
  * Generic version of the affinity autoselector.
  */
-static int setup_affinity(unsigned int irq, struct irq_desc *desc)
+static int
+setup_affinity(unsigned int irq, struct irq_desc *desc, struct cpumask *mask)
 {
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       struct cpumask *set = irq_default_affinity;
+       int ret;
+
+       /* Excludes PER_CPU and NO_BALANCE interrupts */
        if (!irq_can_set_affinity(irq))
                return 0;
 
@@ -168,22 +281,29 @@ static int setup_affinity(unsigned int irq, struct irq_desc *desc)
         * Preserve an userspace affinity setup, but make sure that
         * one of the targets is online.
         */
-       if (desc->status & (IRQ_AFFINITY_SET | IRQ_NO_BALANCING)) {
-               if (cpumask_any_and(desc->irq_data.affinity, cpu_online_mask)
-                   < nr_cpu_ids)
-                       goto set_affinity;
-               else
-                       desc->status &= ~IRQ_AFFINITY_SET;
+       if (irqd_has_set(&desc->irq_data, IRQD_AFFINITY_SET)) {
+               if (cpumask_intersects(desc->irq_data.affinity,
+                                      cpu_online_mask))
+                       set = desc->irq_data.affinity;
+               else {
+                       irq_compat_clr_affinity(desc);
+                       irqd_clear(&desc->irq_data, IRQD_AFFINITY_SET);
+               }
        }
 
-       cpumask_and(desc->irq_data.affinity, cpu_online_mask, irq_default_affinity);
-set_affinity:
-       desc->irq_data.chip->irq_set_affinity(&desc->irq_data, desc->irq_data.affinity, false);
-
+       cpumask_and(mask, cpu_online_mask, set);
+       ret = chip->irq_set_affinity(&desc->irq_data, mask, false);
+       switch (ret) {
+       case IRQ_SET_MASK_OK:
+               cpumask_copy(desc->irq_data.affinity, mask);
+       case IRQ_SET_MASK_OK_NOCOPY:
+               irq_set_thread_affinity(desc);
+       }
        return 0;
 }
 #else
-static inline int setup_affinity(unsigned int irq, struct irq_desc *d)
+static inline int
+setup_affinity(unsigned int irq, struct irq_desc *d, struct cpumask *mask)
 {
        return irq_select_affinity(irq);
 }
@@ -192,23 +312,21 @@ static inline int setup_affinity(unsigned int irq, struct irq_desc *d)
 /*
  * Called when affinity is set via /proc/irq
  */
-int irq_select_affinity_usr(unsigned int irq)
+int irq_select_affinity_usr(unsigned int irq, struct cpumask *mask)
 {
        struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;
        int ret;
 
        raw_spin_lock_irqsave(&desc->lock, flags);
-       ret = setup_affinity(irq, desc);
-       if (!ret)
-               irq_set_thread_affinity(desc);
+       ret = setup_affinity(irq, desc, mask);
        raw_spin_unlock_irqrestore(&desc->lock, flags);
-
        return ret;
 }
 
 #else
-static inline int setup_affinity(unsigned int irq, struct irq_desc *desc)
+static inline int
+setup_affinity(unsigned int irq, struct irq_desc *desc, struct cpumask *mask)
 {
        return 0;
 }
@@ -219,13 +337,23 @@ void __disable_irq(struct irq_desc *desc, unsigned int irq, bool suspend)
        if (suspend) {
                if (!desc->action || (desc->action->flags & IRQF_NO_SUSPEND))
                        return;
-               desc->status |= IRQ_SUSPENDED;
+               desc->istate |= IRQS_SUSPENDED;
        }
 
-       if (!desc->depth++) {
-               desc->status |= IRQ_DISABLED;
-               desc->irq_data.chip->irq_disable(&desc->irq_data);
-       }
+       if (!desc->depth++)
+               irq_disable(desc);
+}
+
+static int __disable_irq_nosync(unsigned int irq)
+{
+       unsigned long flags;
+       struct irq_desc *desc = irq_get_desc_buslock(irq, &flags);
+
+       if (!desc)
+               return -EINVAL;
+       __disable_irq(desc, irq, false);
+       irq_put_desc_busunlock(desc, flags);
+       return 0;
 }
 
 /**
@@ -241,17 +369,7 @@ void __disable_irq(struct irq_desc *desc, unsigned int irq, bool suspend)
  */
 void disable_irq_nosync(unsigned int irq)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-       unsigned long flags;
-
-       if (!desc)
-               return;
-
-       chip_bus_lock(desc);
-       raw_spin_lock_irqsave(&desc->lock, flags);
-       __disable_irq(desc, irq, false);
-       raw_spin_unlock_irqrestore(&desc->lock, flags);
-       chip_bus_sync_unlock(desc);
+       __disable_irq_nosync(irq);
 }
 EXPORT_SYMBOL(disable_irq_nosync);
 
@@ -269,21 +387,24 @@ EXPORT_SYMBOL(disable_irq_nosync);
  */
 void disable_irq(unsigned int irq)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-
-       if (!desc)
-               return;
-
-       disable_irq_nosync(irq);
-       if (desc->action)
+       if (!__disable_irq_nosync(irq))
                synchronize_irq(irq);
 }
 EXPORT_SYMBOL(disable_irq);
 
 void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume)
 {
-       if (resume)
-               desc->status &= ~IRQ_SUSPENDED;
+       if (resume) {
+               if (!(desc->istate & IRQS_SUSPENDED)) {
+                       if (!desc->action)
+                               return;
+                       if (!(desc->action->flags & IRQF_FORCE_RESUME))
+                               return;
+                       /* Pretend that it got disabled ! */
+                       desc->depth++;
+               }
+               desc->istate &= ~IRQS_SUSPENDED;
+       }
 
        switch (desc->depth) {
        case 0:
@@ -291,12 +412,11 @@ void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume)
                WARN(1, KERN_WARNING "Unbalanced enable for IRQ %d\n", irq);
                break;
        case 1: {
-               unsigned int status = desc->status & ~IRQ_DISABLED;
-
-               if (desc->status & IRQ_SUSPENDED)
+               if (desc->istate & IRQS_SUSPENDED)
                        goto err_out;
                /* Prevent probing on this irq: */
-               desc->status = status | IRQ_NOPROBE;
+               irq_settings_set_noprobe(desc);
+               irq_enable(desc);
                check_irq_resend(desc, irq);
                /* fall-through */
        }
@@ -318,21 +438,18 @@ void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume)
  */
 void enable_irq(unsigned int irq)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;
+       struct irq_desc *desc = irq_get_desc_buslock(irq, &flags);
 
        if (!desc)
                return;
+       if (WARN(!desc->irq_data.chip,
+                KERN_ERR "enable_irq before setup/request_irq: irq %u\n", irq))
+               goto out;
 
-       if (WARN(!desc->irq_data.chip || !desc->irq_data.chip->irq_enable,
-           KERN_ERR "enable_irq before setup/request_irq: irq %u\n", irq))
-               return;
-
-       chip_bus_lock(desc);
-       raw_spin_lock_irqsave(&desc->lock, flags);
        __enable_irq(desc, irq, false);
-       raw_spin_unlock_irqrestore(&desc->lock, flags);
-       chip_bus_sync_unlock(desc);
+out:
+       irq_put_desc_busunlock(desc, flags);
 }
 EXPORT_SYMBOL(enable_irq);
 
@@ -348,7 +465,7 @@ static int set_irq_wake_real(unsigned int irq, unsigned int on)
 }
 
 /**
- *     set_irq_wake - control irq power management wakeup
+ *     irq_set_irq_wake - control irq power management wakeup
  *     @irq:   interrupt to control
  *     @on:    enable/disable power management wakeup
  *
@@ -359,23 +476,22 @@ static int set_irq_wake_real(unsigned int irq, unsigned int on)
  *     Wakeup mode lets this IRQ wake the system from sleep
  *     states like "suspend to RAM".
  */
-int set_irq_wake(unsigned int irq, unsigned int on)
+int irq_set_irq_wake(unsigned int irq, unsigned int on)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;
+       struct irq_desc *desc = irq_get_desc_buslock(irq, &flags);
        int ret = 0;
 
        /* wakeup-capable irqs can be shared between drivers that
         * don't need to have the same sleep mode behaviors.
         */
-       raw_spin_lock_irqsave(&desc->lock, flags);
        if (on) {
                if (desc->wake_depth++ == 0) {
                        ret = set_irq_wake_real(irq, on);
                        if (ret)
                                desc->wake_depth = 0;
                        else
-                               desc->status |= IRQ_WAKEUP;
+                               irqd_set(&desc->irq_data, IRQD_WAKEUP_STATE);
                }
        } else {
                if (desc->wake_depth == 0) {
@@ -385,14 +501,13 @@ int set_irq_wake(unsigned int irq, unsigned int on)
                        if (ret)
                                desc->wake_depth = 1;
                        else
-                               desc->status &= ~IRQ_WAKEUP;
+                               irqd_clear(&desc->irq_data, IRQD_WAKEUP_STATE);
                }
        }
-
-       raw_spin_unlock_irqrestore(&desc->lock, flags);
+       irq_put_desc_busunlock(desc, flags);
        return ret;
 }
-EXPORT_SYMBOL(set_irq_wake);
+EXPORT_SYMBOL(irq_set_irq_wake);
 
 /*
  * Internal function that tells the architecture code whether a
@@ -401,43 +516,27 @@ EXPORT_SYMBOL(set_irq_wake);
  */
 int can_request_irq(unsigned int irq, unsigned long irqflags)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-       struct irqaction *action;
        unsigned long flags;
+       struct irq_desc *desc = irq_get_desc_lock(irq, &flags);
+       int canrequest = 0;
 
        if (!desc)
                return 0;
 
-       if (desc->status & IRQ_NOREQUEST)
-               return 0;
-
-       raw_spin_lock_irqsave(&desc->lock, flags);
-       action = desc->action;
-       if (action)
-               if (irqflags & action->flags & IRQF_SHARED)
-                       action = NULL;
-
-       raw_spin_unlock_irqrestore(&desc->lock, flags);
-
-       return !action;
-}
-
-void compat_irq_chip_set_default_handler(struct irq_desc *desc)
-{
-       /*
-        * If the architecture still has not overriden
-        * the flow handler then zap the default. This
-        * should catch incorrect flow-type setting.
-        */
-       if (desc->handle_irq == &handle_bad_irq)
-               desc->handle_irq = NULL;
+       if (irq_settings_can_request(desc)) {
+               if (desc->action)
+                       if (irqflags & desc->action->flags & IRQF_SHARED)
+                               canrequest =1;
+       }
+       irq_put_desc_unlock(desc, flags);
+       return canrequest;
 }
 
 int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
                      unsigned long flags)
 {
-       int ret;
        struct irq_chip *chip = desc->irq_data.chip;
+       int ret, unmask = 0;
 
        if (!chip || !chip->irq_set_type) {
                /*
@@ -449,23 +548,43 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
                return 0;
        }
 
+       flags &= IRQ_TYPE_SENSE_MASK;
+
+       if (chip->flags & IRQCHIP_SET_TYPE_MASKED) {
+               if (!(desc->istate & IRQS_MASKED))
+                       mask_irq(desc);
+               if (!(desc->istate & IRQS_DISABLED))
+                       unmask = 1;
+       }
+
        /* caller masked out all except trigger mode flags */
        ret = chip->irq_set_type(&desc->irq_data, flags);
 
-       if (ret)
-               pr_err("setting trigger mode %lu for irq %u failed (%pF)\n",
-                      flags, irq, chip->irq_set_type);
-       else {
-               if (flags & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
-                       flags |= IRQ_LEVEL;
-               /* note that IRQF_TRIGGER_MASK == IRQ_TYPE_SENSE_MASK */
-               desc->status &= ~(IRQ_LEVEL | IRQ_TYPE_SENSE_MASK);
-               desc->status |= flags;
+       switch (ret) {
+       case IRQ_SET_MASK_OK:
+               irqd_clear(&desc->irq_data, IRQD_TRIGGER_MASK);
+               irqd_set(&desc->irq_data, flags);
+
+       case IRQ_SET_MASK_OK_NOCOPY:
+               flags = irqd_get_trigger_type(&desc->irq_data);
+               irq_settings_set_trigger_mask(desc, flags);
+               irqd_clear(&desc->irq_data, IRQD_LEVEL);
+               irq_settings_clr_level(desc);
+               if (flags & IRQ_TYPE_LEVEL_MASK) {
+                       irq_settings_set_level(desc);
+                       irqd_set(&desc->irq_data, IRQD_LEVEL);
+               }
 
                if (chip != desc->irq_data.chip)
                        irq_chip_set_defaults(desc->irq_data.chip);
+               ret = 0;
+               break;
+       default:
+               pr_err("setting trigger mode %lu for irq %u failed (%pF)\n",
+                      flags, irq, chip->irq_set_type);
        }
-
+       if (unmask)
+               unmask_irq(desc);
        return ret;
 }
 
@@ -509,8 +628,11 @@ static int irq_wait_for_interrupt(struct irqaction *action)
  * handler finished. unmask if the interrupt has not been disabled and
  * is marked MASKED.
  */
-static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc)
+static void irq_finalize_oneshot(struct irq_desc *desc,
+                                struct irqaction *action, bool force)
 {
+       if (!(desc->istate & IRQS_ONESHOT))
+               return;
 again:
        chip_bus_lock(desc);
        raw_spin_lock_irq(&desc->lock);
@@ -522,26 +644,44 @@ again:
         * The thread is faster done than the hard interrupt handler
         * on the other CPU. If we unmask the irq line then the
         * interrupt can come in again and masks the line, leaves due
-        * to IRQ_INPROGRESS and the irq line is masked forever.
+        * to IRQS_INPROGRESS and the irq line is masked forever.
+        *
+        * This also serializes the state of shared oneshot handlers
+        * versus "desc->threads_onehsot |= action->thread_mask;" in
+        * irq_wake_thread(). See the comment there which explains the
+        * serialization.
         */
-       if (unlikely(desc->status & IRQ_INPROGRESS)) {
+       if (unlikely(desc->istate & IRQS_INPROGRESS)) {
                raw_spin_unlock_irq(&desc->lock);
                chip_bus_sync_unlock(desc);
                cpu_relax();
                goto again;
        }
 
-       if (!(desc->status & IRQ_DISABLED) && (desc->status & IRQ_MASKED)) {
-               desc->status &= ~IRQ_MASKED;
+       /*
+        * Now check again, whether the thread should run. Otherwise
+        * we would clear the threads_oneshot bit of this thread which
+        * was just set.
+        */
+       if (!force && test_bit(IRQTF_RUNTHREAD, &action->thread_flags))
+               goto out_unlock;
+
+       desc->threads_oneshot &= ~action->thread_mask;
+
+       if (!desc->threads_oneshot && !(desc->istate & IRQS_DISABLED) &&
+           (desc->istate & IRQS_MASKED)) {
+               irq_compat_clr_masked(desc);
+               desc->istate &= ~IRQS_MASKED;
                desc->irq_data.chip->irq_unmask(&desc->irq_data);
        }
+out_unlock:
        raw_spin_unlock_irq(&desc->lock);
        chip_bus_sync_unlock(desc);
 }
 
 #ifdef CONFIG_SMP
 /*
- * Check whether we need to change the affinity of the interrupt thread.
+ * Check whether we need to chasnge the affinity of the interrupt thread.
  */
 static void
 irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action)
@@ -572,6 +712,32 @@ static inline void
 irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action) { }
 #endif
 
+/*
+ * Interrupts which are not explicitely requested as threaded
+ * interrupts rely on the implicit bh/preempt disable of the hard irq
+ * context. So we need to disable bh here to avoid deadlocks and other
+ * side effects.
+ */
+static void
+irq_forced_thread_fn(struct irq_desc *desc, struct irqaction *action)
+{
+       local_bh_disable();
+       action->thread_fn(action->irq, action->dev_id);
+       irq_finalize_oneshot(desc, action, false);
+       local_bh_enable();
+}
+
+/*
+ * Interrupts explicitely requested as threaded interupts want to be
+ * preemtible - many of them need to sleep and wait for slow busses to
+ * complete.
+ */
+static void irq_thread_fn(struct irq_desc *desc, struct irqaction *action)
+{
+       action->thread_fn(action->irq, action->dev_id);
+       irq_finalize_oneshot(desc, action, false);
+}
+
 /*
  * Interrupt handler thread
  */
@@ -582,7 +748,14 @@ static int irq_thread(void *data)
        };
        struct irqaction *action = data;
        struct irq_desc *desc = irq_to_desc(action->irq);
-       int wake, oneshot = desc->status & IRQ_ONESHOT;
+       void (*handler_fn)(struct irq_desc *desc, struct irqaction *action);
+       int wake;
+
+       if (force_irqthreads & test_bit(IRQTF_FORCED_THREAD,
+                                       &action->thread_flags))
+               handler_fn = irq_forced_thread_fn;
+       else
+               handler_fn = irq_thread_fn;
 
        sched_setscheduler(current, SCHED_FIFO, &param);
        current->irqaction = action;
@@ -594,23 +767,20 @@ static int irq_thread(void *data)
                atomic_inc(&desc->threads_active);
 
                raw_spin_lock_irq(&desc->lock);
-               if (unlikely(desc->status & IRQ_DISABLED)) {
+               if (unlikely(desc->istate & IRQS_DISABLED)) {
                        /*
                         * CHECKME: We might need a dedicated
                         * IRQ_THREAD_PENDING flag here, which
                         * retriggers the thread in check_irq_resend()
-                        * but AFAICT IRQ_PENDING should be fine as it
+                        * but AFAICT IRQS_PENDING should be fine as it
                         * retriggers the interrupt itself --- tglx
                         */
-                       desc->status |= IRQ_PENDING;
+                       irq_compat_set_pending(desc);
+                       desc->istate |= IRQS_PENDING;
                        raw_spin_unlock_irq(&desc->lock);
                } else {
                        raw_spin_unlock_irq(&desc->lock);
-
-                       action->thread_fn(action->irq, action->dev_id);
-
-                       if (oneshot)
-                               irq_finalize_oneshot(action->irq, desc);
+                       handler_fn(desc, action);
                }
 
                wake = atomic_dec_and_test(&desc->threads_active);
@@ -619,6 +789,9 @@ static int irq_thread(void *data)
                        wake_up(&desc->wait_for_threads);
        }
 
+       /* Prevent a stale desc->threads_oneshot */
+       irq_finalize_oneshot(desc, action, true);
+
        /*
         * Clear irqaction. Otherwise exit_irq_thread() would make
         * fuzz about an active irq thread going into nirvana.
@@ -633,6 +806,7 @@ static int irq_thread(void *data)
 void exit_irq_thread(void)
 {
        struct task_struct *tsk = current;
+       struct irq_desc *desc;
 
        if (!tsk->irqaction)
                return;
@@ -641,6 +815,14 @@ void exit_irq_thread(void)
               "exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n",
               tsk->comm ? tsk->comm : "", tsk->pid, tsk->irqaction->irq);
 
+       desc = irq_to_desc(tsk->irqaction->irq);
+
+       /*
+        * Prevent a stale desc->threads_oneshot. Must be called
+        * before setting the IRQTF_DIED flag.
+        */
+       irq_finalize_oneshot(desc, tsk->irqaction, true);
+
        /*
         * Set the THREAD DIED flag to prevent further wakeups of the
         * soon to be gone threaded handler.
@@ -648,6 +830,22 @@ void exit_irq_thread(void)
        set_bit(IRQTF_DIED, &tsk->irqaction->flags);
 }
 
+static void irq_setup_forced_threading(struct irqaction *new)
+{
+       if (!force_irqthreads)
+               return;
+       if (new->flags & (IRQF_NO_THREAD | IRQF_PERCPU | IRQF_ONESHOT))
+               return;
+
+       new->flags |= IRQF_ONESHOT;
+
+       if (!new->thread_fn) {
+               set_bit(IRQTF_FORCED_THREAD, &new->thread_flags);
+               new->thread_fn = new->handler;
+               new->handler = irq_default_primary_handler;
+       }
+}
+
 /*
  * Internal function to register an irqaction - typically used to
  * allocate special interrupts that are part of the architecture.
@@ -657,9 +855,9 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
 {
        struct irqaction *old, **old_ptr;
        const char *old_name = NULL;
-       unsigned long flags;
-       int nested, shared = 0;
-       int ret;
+       unsigned long flags, thread_mask = 0;
+       int ret, nested, shared = 0;
+       cpumask_var_t mask;
 
        if (!desc)
                return -EINVAL;
@@ -683,15 +881,11 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
                rand_initialize_irq(irq);
        }
 
-       /* Oneshot interrupts are not allowed with shared */
-       if ((new->flags & IRQF_ONESHOT) && (new->flags & IRQF_SHARED))
-               return -EINVAL;
-
        /*
         * Check whether the interrupt nests into another interrupt
         * thread.
         */
-       nested = desc->status & IRQ_NESTED_THREAD;
+       nested = irq_settings_is_nested_thread(desc);
        if (nested) {
                if (!new->thread_fn)
                        return -EINVAL;
@@ -701,6 +895,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
                 * dummy function which warns when called.
                 */
                new->handler = irq_nested_primary_handler;
+       } else {
+               irq_setup_forced_threading(new);
        }
 
        /*
@@ -724,6 +920,11 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
                new->thread = t;
        }
 
+       if (!alloc_cpumask_var(&mask, GFP_KERNEL)) {
+               ret = -ENOMEM;
+               goto out_thread;
+       }
+
        /*
         * The following block of code has to be executed atomically
         */
@@ -735,29 +936,40 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
                 * Can't share interrupts unless both agree to and are
                 * the same type (level, edge, polarity). So both flag
                 * fields must have IRQF_SHARED set and the bits which
-                * set the trigger type must match.
+                * set the trigger type must match. Also all must
+                * agree on ONESHOT.
                 */
                if (!((old->flags & new->flags) & IRQF_SHARED) ||
-                   ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK)) {
+                   ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK) ||
+                   ((old->flags ^ new->flags) & IRQF_ONESHOT)) {
                        old_name = old->name;
                        goto mismatch;
                }
 
-#if defined(CONFIG_IRQ_PER_CPU)
                /* All handlers must agree on per-cpuness */
                if ((old->flags & IRQF_PERCPU) !=
                    (new->flags & IRQF_PERCPU))
                        goto mismatch;
-#endif
 
                /* add new interrupt at end of irq queue */
                do {
+                       thread_mask |= old->thread_mask;
                        old_ptr = &old->next;
                        old = *old_ptr;
                } while (old);
                shared = 1;
        }
 
+       /*
+        * Setup the thread mask for this irqaction. Unlikely to have
+        * 32 resp 64 irqs sharing one line, but who knows.
+        */
+       if (new->flags & IRQF_ONESHOT && thread_mask == ~0UL) {
+               ret = -EBUSY;
+               goto out_mask;
+       }
+       new->thread_mask = 1 << ffz(thread_mask);
+
        if (!shared) {
                irq_chip_set_defaults(desc->irq_data.chip);
 
@@ -769,42 +981,44 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
                                        new->flags & IRQF_TRIGGER_MASK);
 
                        if (ret)
-                               goto out_thread;
-               } else
-                       compat_irq_chip_set_default_handler(desc);
-#if defined(CONFIG_IRQ_PER_CPU)
-               if (new->flags & IRQF_PERCPU)
-                       desc->status |= IRQ_PER_CPU;
-#endif
+                               goto out_mask;
+               }
 
-               desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | IRQ_ONESHOT |
-                                 IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED);
+               desc->istate &= ~(IRQS_AUTODETECT | IRQS_SPURIOUS_DISABLED | \
+                                 IRQS_INPROGRESS | IRQS_ONESHOT | \
+                                 IRQS_WAITING);
+
+               if (new->flags & IRQF_PERCPU) {
+                       irqd_set(&desc->irq_data, IRQD_PER_CPU);
+                       irq_settings_set_per_cpu(desc);
+               }
 
                if (new->flags & IRQF_ONESHOT)
-                       desc->status |= IRQ_ONESHOT;
+                       desc->istate |= IRQS_ONESHOT;
 
-               if (!(desc->status & IRQ_NOAUTOEN)) {
-                       desc->depth = 0;
-                       desc->status &= ~IRQ_DISABLED;
-                       desc->irq_data.chip->irq_startup(&desc->irq_data);
-               } else
+               if (irq_settings_can_autoenable(desc))
+                       irq_startup(desc);
+               else
                        /* Undo nested disables: */
                        desc->depth = 1;
 
                /* Exclude IRQ from balancing if requested */
-               if (new->flags & IRQF_NOBALANCING)
-                       desc->status |= IRQ_NO_BALANCING;
+               if (new->flags & IRQF_NOBALANCING) {
+                       irq_settings_set_no_balancing(desc);
+                       irqd_set(&desc->irq_data, IRQD_NO_BALANCING);
+               }
 
                /* Set default affinity mask once everything is setup */
-               setup_affinity(irq, desc);
-
-       } else if ((new->flags & IRQF_TRIGGER_MASK)
-                       && (new->flags & IRQF_TRIGGER_MASK)
-                               != (desc->status & IRQ_TYPE_SENSE_MASK)) {
-               /* hope the handler works with the actual trigger mode... */
-               pr_warning("IRQ %d uses trigger mode %d; requested %d\n",
-                               irq, (int)(desc->status & IRQ_TYPE_SENSE_MASK),
-                               (int)(new->flags & IRQF_TRIGGER_MASK));
+               setup_affinity(irq, desc, mask);
+
+       } else if (new->flags & IRQF_TRIGGER_MASK) {
+               unsigned int nmsk = new->flags & IRQF_TRIGGER_MASK;
+               unsigned int omsk = irq_settings_get_trigger_mask(desc);
+
+               if (nmsk != omsk)
+                       /* hope the handler works with current  trigger mode */
+                       pr_warning("IRQ %d uses trigger mode %u; requested %u\n",
+                                  irq, nmsk, omsk);
        }
 
        new->irq = irq;
@@ -818,8 +1032,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
         * Check whether we disabled the irq via the spurious handler
         * before. Reenable it and give it another chance.
         */
-       if (shared && (desc->status & IRQ_SPURIOUS_DISABLED)) {
-               desc->status &= ~IRQ_SPURIOUS_DISABLED;
+       if (shared && (desc->istate & IRQS_SPURIOUS_DISABLED)) {
+               desc->istate &= ~IRQS_SPURIOUS_DISABLED;
                __enable_irq(desc, irq, false);
        }
 
@@ -849,6 +1063,9 @@ mismatch:
 #endif
        ret = -EBUSY;
 
+out_mask:
+       free_cpumask_var(mask);
+
 out_thread:
        raw_spin_unlock_irqrestore(&desc->lock, flags);
        if (new->thread) {
@@ -871,9 +1088,14 @@ out_thread:
  */
 int setup_irq(unsigned int irq, struct irqaction *act)
 {
+       int retval;
        struct irq_desc *desc = irq_to_desc(irq);
 
-       return __setup_irq(irq, desc, act);
+       chip_bus_lock(desc);
+       retval = __setup_irq(irq, desc, act);
+       chip_bus_sync_unlock(desc);
+
+       return retval;
 }
 EXPORT_SYMBOL_GPL(setup_irq);
 
@@ -924,13 +1146,8 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
 #endif
 
        /* If this was the last handler, shut down the IRQ line: */
-       if (!desc->action) {
-               desc->status |= IRQ_DISABLED;
-               if (desc->irq_data.chip->irq_shutdown)
-                       desc->irq_data.chip->irq_shutdown(&desc->irq_data);
-               else
-                       desc->irq_data.chip->irq_disable(&desc->irq_data);
-       }
+       if (!desc->action)
+               irq_shutdown(desc);
 
 #ifdef CONFIG_SMP
        /* make sure affinity_hint is cleaned up */
@@ -1004,6 +1221,11 @@ void free_irq(unsigned int irq, void *dev_id)
        if (!desc)
                return;
 
+#ifdef CONFIG_SMP
+       if (WARN_ON(desc->affinity_notify))
+               desc->affinity_notify = NULL;
+#endif
+
        chip_bus_lock(desc);
        kfree(__free_irq(irq, dev_id));
        chip_bus_sync_unlock(desc);
@@ -1074,7 +1296,7 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler,
        if (!desc)
                return -EINVAL;
 
-       if (desc->status & IRQ_NOREQUEST)
+       if (!irq_settings_can_request(desc))
                return -EINVAL;
 
        if (!handler) {
@@ -1100,7 +1322,7 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler,
        if (retval)
                kfree(action);
 
-#ifdef CONFIG_DEBUG_SHIRQ
+#ifdef CONFIG_DEBUG_SHIRQ_FIXME
        if (!retval && (irqflags & IRQF_SHARED)) {
                /*
                 * It's a shared IRQ -- the driver ought to be prepared for it
@@ -1149,7 +1371,7 @@ int request_any_context_irq(unsigned int irq, irq_handler_t handler,
        if (!desc)
                return -EINVAL;
 
-       if (desc->status & IRQ_NESTED_THREAD) {
+       if (irq_settings_is_nested_thread(desc)) {
                ret = request_threaded_irq(irq, NULL, handler,
                                           flags, name, dev_id);
                return !ret ? IRQC_IS_NESTED : ret;
index 1d25419..ec4806d 100644 (file)
@@ -4,23 +4,23 @@
 
 #include "internals.h"
 
-void move_masked_irq(int irq)
+void irq_move_masked_irq(struct irq_data *idata)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-       struct irq_chip *chip = desc->irq_data.chip;
+       struct irq_desc *desc = irq_data_to_desc(idata);
+       struct irq_chip *chip = idata->chip;
 
-       if (likely(!(desc->status & IRQ_MOVE_PENDING)))
+       if (likely(!irqd_is_setaffinity_pending(&desc->irq_data)))
                return;
 
        /*
         * Paranoia: cpu-local interrupts shouldn't be calling in here anyway.
         */
-       if (CHECK_IRQ_PER_CPU(desc->status)) {
+       if (!irqd_can_balance(&desc->irq_data)) {
                WARN_ON(1);
                return;
        }
 
-       desc->status &= ~IRQ_MOVE_PENDING;
+       irqd_clr_move_pending(&desc->irq_data);
 
        if (unlikely(cpumask_empty(desc->pending_mask)))
                return;
@@ -53,18 +53,36 @@ void move_masked_irq(int irq)
        cpumask_clear(desc->pending_mask);
 }
 
-void move_native_irq(int irq)
+void move_masked_irq(int irq)
+{
+       irq_move_masked_irq(irq_get_irq_data(irq));
+}
+
+void irq_move_irq(struct irq_data *idata)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
+       struct irq_desc *desc = irq_data_to_desc(idata);
+       bool masked;
 
-       if (likely(!(desc->status & IRQ_MOVE_PENDING)))
+       if (likely(!irqd_is_setaffinity_pending(idata)))
                return;
 
-       if (unlikely(desc->status & IRQ_DISABLED))
+       if (unlikely(desc->istate & IRQS_DISABLED))
                return;
 
-       desc->irq_data.chip->irq_mask(&desc->irq_data);
-       move_masked_irq(irq);
-       desc->irq_data.chip->irq_unmask(&desc->irq_data);
+       /*
+        * Be careful vs. already masked interrupts. If this is a
+        * threaded interrupt with ONESHOT set, we can end up with an
+        * interrupt storm.
+        */
+       masked = desc->istate & IRQS_MASKED;
+       if (!masked)
+               idata->chip->irq_mask(idata);
+       irq_move_masked_irq(idata);
+       if (!masked)
+               idata->chip->irq_unmask(idata);
 }
 
+void move_native_irq(int irq)
+{
+       irq_move_irq(irq_get_irq_data(irq));
+}
index 0d4005d..f76fc00 100644 (file)
@@ -18,7 +18,7 @@
  * During system-wide suspend or hibernation device drivers need to be prevented
  * from receiving interrupts and this function is provided for this purpose.
  * It marks all interrupt lines in use, except for the timer ones, as disabled
- * and sets the IRQ_SUSPENDED flag for each of them.
+ * and sets the IRQS_SUSPENDED flag for each of them.
  */
 void suspend_device_irqs(void)
 {
@@ -34,7 +34,7 @@ void suspend_device_irqs(void)
        }
 
        for_each_irq_desc(irq, desc)
-               if (desc->status & IRQ_SUSPENDED)
+               if (desc->istate & IRQS_SUSPENDED)
                        synchronize_irq(irq);
 }
 EXPORT_SYMBOL_GPL(suspend_device_irqs);
@@ -43,7 +43,7 @@ EXPORT_SYMBOL_GPL(suspend_device_irqs);
  * resume_device_irqs - enable interrupt lines disabled by suspend_device_irqs()
  *
  * Enable all interrupt lines previously disabled by suspend_device_irqs() that
- * have the IRQ_SUSPENDED flag set.
+ * have the IRQS_SUSPENDED flag set.
  */
 void resume_device_irqs(void)
 {
@@ -53,9 +53,6 @@ void resume_device_irqs(void)
        for_each_irq_desc(irq, desc) {
                unsigned long flags;
 
-               if (!(desc->status & IRQ_SUSPENDED))
-                       continue;
-
                raw_spin_lock_irqsave(&desc->lock, flags);
                __enable_irq(desc, irq, true);
                raw_spin_unlock_irqrestore(&desc->lock, flags);
@@ -71,9 +68,24 @@ int check_wakeup_irqs(void)
        struct irq_desc *desc;
        int irq;
 
-       for_each_irq_desc(irq, desc)
-               if ((desc->status & IRQ_WAKEUP) && (desc->status & IRQ_PENDING))
-                       return -EBUSY;
+       for_each_irq_desc(irq, desc) {
+               if (irqd_is_wakeup_set(&desc->irq_data)) {
+                       if (desc->istate & IRQS_PENDING)
+                               return -EBUSY;
+                       continue;
+               }
+               /*
+                * Check the non wakeup interrupts whether they need
+                * to be masked before finally going into suspend
+                * state. That's for hardware which has no wakeup
+                * source configuration facility. The chip
+                * implementation indicates that with
+                * IRQCHIP_MASK_ON_SUSPEND.
+                */
+               if (desc->istate & IRQS_SUSPENDED &&
+                   irq_desc_get_chip(desc)->flags & IRQCHIP_MASK_ON_SUSPEND)
+                       mask_irq(desc);
+       }
 
        return 0;
 }
index 6c8a2a9..4cc2e5e 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
 
 #include "internals.h"
 
@@ -24,7 +25,7 @@ static int irq_affinity_proc_show(struct seq_file *m, void *v)
        const struct cpumask *mask = desc->irq_data.affinity;
 
 #ifdef CONFIG_GENERIC_PENDING_IRQ
-       if (desc->status & IRQ_MOVE_PENDING)
+       if (irqd_is_setaffinity_pending(&desc->irq_data))
                mask = desc->pending_mask;
 #endif
        seq_cpumask(m, mask);
@@ -65,8 +66,7 @@ static ssize_t irq_affinity_proc_write(struct file *file,
        cpumask_var_t new_value;
        int err;
 
-       if (!irq_to_desc(irq)->irq_data.chip->irq_set_affinity || no_irq_affinity ||
-           irq_balancing_disabled(irq))
+       if (!irq_can_set_affinity(irq) || no_irq_affinity)
                return -EIO;
 
        if (!alloc_cpumask_var(&new_value, GFP_KERNEL))
@@ -89,7 +89,7 @@ static ssize_t irq_affinity_proc_write(struct file *file,
        if (!cpumask_intersects(new_value, cpu_online_mask)) {
                /* Special case for empty set - allow the architecture
                   code to set default SMP affinity. */
-               err = irq_select_affinity_usr(irq) ? -EINVAL : count;
+               err = irq_select_affinity_usr(irq, new_value) ? -EINVAL : count;
        } else {
                irq_set_affinity(irq, new_value);
                err = count;
@@ -357,3 +357,65 @@ void init_irq_proc(void)
        }
 }
 
+#ifdef CONFIG_GENERIC_IRQ_SHOW
+
+int __weak arch_show_interrupts(struct seq_file *p, int prec)
+{
+       return 0;
+}
+
+int show_interrupts(struct seq_file *p, void *v)
+{
+       static int prec;
+
+       unsigned long flags, any_count = 0;
+       int i = *(loff_t *) v, j;
+       struct irqaction *action;
+       struct irq_desc *desc;
+
+       if (i > nr_irqs)
+               return 0;
+
+       if (i == nr_irqs)
+               return arch_show_interrupts(p, prec);
+
+       /* print header and calculate the width of the first column */
+       if (i == 0) {
+               for (prec = 3, j = 1000; prec < 10 && j <= nr_irqs; ++prec)
+                       j *= 10;
+
+               seq_printf(p, "%*s", prec + 8, "");
+               for_each_online_cpu(j)
+                       seq_printf(p, "CPU%-8d", j);
+               seq_putc(p, '\n');
+       }
+
+       desc = irq_to_desc(i);
+       if (!desc)
+               return 0;
+
+       raw_spin_lock_irqsave(&desc->lock, flags);
+       for_each_online_cpu(j)
+               any_count |= kstat_irqs_cpu(i, j);
+       action = desc->action;
+       if (!action && !any_count)
+               goto out;
+
+       seq_printf(p, "%*d: ", prec, i);
+       for_each_online_cpu(j)
+               seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
+       seq_printf(p, " %8s", desc->irq_data.chip->name);
+       seq_printf(p, "-%-8s", desc->name);
+
+       if (action) {
+               seq_printf(p, "  %s", action->name);
+               while ((action = action->next) != NULL)
+                       seq_printf(p, ", %s", action->name);
+       }
+
+       seq_putc(p, '\n');
+out:
+       raw_spin_unlock_irqrestore(&desc->lock, flags);
+       return 0;
+}
+#endif
index 891115a..ad683a9 100644 (file)
@@ -23,7 +23,7 @@
 #ifdef CONFIG_HARDIRQS_SW_RESEND
 
 /* Bitmap to handle software resend of interrupts: */
-static DECLARE_BITMAP(irqs_resend, NR_IRQS);
+static DECLARE_BITMAP(irqs_resend, IRQ_BITMAP_BITS);
 
 /*
  * Run software resends of IRQ's
@@ -55,20 +55,19 @@ static DECLARE_TASKLET(resend_tasklet, resend_irqs, 0);
  */
 void check_irq_resend(struct irq_desc *desc, unsigned int irq)
 {
-       unsigned int status = desc->status;
-
-       /*
-        * Make sure the interrupt is enabled, before resending it:
-        */
-       desc->irq_data.chip->irq_enable(&desc->irq_data);
-
        /*
         * We do not resend level type interrupts. Level type
         * interrupts are resent by hardware when they are still
         * active.
         */
-       if ((status & (IRQ_LEVEL | IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
-               desc->status = (status & ~IRQ_PENDING) | IRQ_REPLAY;
+       if (irq_settings_is_level(desc))
+               return;
+       if (desc->istate & IRQS_REPLAY)
+               return;
+       if (desc->istate & IRQS_PENDING) {
+               irq_compat_clr_pending(desc);
+               desc->istate &= ~IRQS_PENDING;
+               desc->istate |= IRQS_REPLAY;
 
                if (!desc->irq_data.chip->irq_retrigger ||
                    !desc->irq_data.chip->irq_retrigger(&desc->irq_data)) {
diff --git a/kernel/irq/settings.h b/kernel/irq/settings.h
new file mode 100644 (file)
index 0000000..0227ad3
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Internal header to deal with irq_desc->status which will be renamed
+ * to irq_desc->settings.
+ */
+enum {
+       _IRQ_DEFAULT_INIT_FLAGS = IRQ_DEFAULT_INIT_FLAGS,
+       _IRQ_PER_CPU            = IRQ_PER_CPU,
+       _IRQ_LEVEL              = IRQ_LEVEL,
+       _IRQ_NOPROBE            = IRQ_NOPROBE,
+       _IRQ_NOREQUEST          = IRQ_NOREQUEST,
+       _IRQ_NOAUTOEN           = IRQ_NOAUTOEN,
+       _IRQ_MOVE_PCNTXT        = IRQ_MOVE_PCNTXT,
+       _IRQ_NO_BALANCING       = IRQ_NO_BALANCING,
+       _IRQ_NESTED_THREAD      = IRQ_NESTED_THREAD,
+       _IRQF_MODIFY_MASK       = IRQF_MODIFY_MASK,
+};
+
+#define IRQ_INPROGRESS         GOT_YOU_MORON
+#define IRQ_REPLAY             GOT_YOU_MORON
+#define IRQ_WAITING            GOT_YOU_MORON
+#define IRQ_DISABLED           GOT_YOU_MORON
+#define IRQ_PENDING            GOT_YOU_MORON
+#define IRQ_MASKED             GOT_YOU_MORON
+#define IRQ_WAKEUP             GOT_YOU_MORON
+#define IRQ_MOVE_PENDING       GOT_YOU_MORON
+#define IRQ_PER_CPU            GOT_YOU_MORON
+#define IRQ_NO_BALANCING       GOT_YOU_MORON
+#define IRQ_AFFINITY_SET       GOT_YOU_MORON
+#define IRQ_LEVEL              GOT_YOU_MORON
+#define IRQ_NOPROBE            GOT_YOU_MORON
+#define IRQ_NOREQUEST          GOT_YOU_MORON
+#define IRQ_NOAUTOEN           GOT_YOU_MORON
+#define IRQ_NESTED_THREAD      GOT_YOU_MORON
+#undef IRQF_MODIFY_MASK
+#define IRQF_MODIFY_MASK       GOT_YOU_MORON
+
+static inline void
+irq_settings_clr_and_set(struct irq_desc *desc, u32 clr, u32 set)
+{
+       desc->status &= ~(clr & _IRQF_MODIFY_MASK);
+       desc->status |= (set & _IRQF_MODIFY_MASK);
+}
+
+static inline bool irq_settings_is_per_cpu(struct irq_desc *desc)
+{
+       return desc->status & _IRQ_PER_CPU;
+}
+
+static inline void irq_settings_set_per_cpu(struct irq_desc *desc)
+{
+       desc->status |= _IRQ_PER_CPU;
+}
+
+static inline void irq_settings_set_no_balancing(struct irq_desc *desc)
+{
+       desc->status |= _IRQ_NO_BALANCING;
+}
+
+static inline bool irq_settings_has_no_balance_set(struct irq_desc *desc)
+{
+       return desc->status & _IRQ_NO_BALANCING;
+}
+
+static inline u32 irq_settings_get_trigger_mask(struct irq_desc *desc)
+{
+       return desc->status & IRQ_TYPE_SENSE_MASK;
+}
+
+static inline void
+irq_settings_set_trigger_mask(struct irq_desc *desc, u32 mask)
+{
+       desc->status &= ~IRQ_TYPE_SENSE_MASK;
+       desc->status |= mask & IRQ_TYPE_SENSE_MASK;
+}
+
+static inline bool irq_settings_is_level(struct irq_desc *desc)
+{
+       return desc->status & _IRQ_LEVEL;
+}
+
+static inline void irq_settings_clr_level(struct irq_desc *desc)
+{
+       desc->status &= ~_IRQ_LEVEL;
+}
+
+static inline void irq_settings_set_level(struct irq_desc *desc)
+{
+       desc->status |= _IRQ_LEVEL;
+}
+
+static inline bool irq_settings_can_request(struct irq_desc *desc)
+{
+       return !(desc->status & _IRQ_NOREQUEST);
+}
+
+static inline void irq_settings_clr_norequest(struct irq_desc *desc)
+{
+       desc->status &= ~_IRQ_NOREQUEST;
+}
+
+static inline void irq_settings_set_norequest(struct irq_desc *desc)
+{
+       desc->status |= _IRQ_NOREQUEST;
+}
+
+static inline bool irq_settings_can_probe(struct irq_desc *desc)
+{
+       return !(desc->status & _IRQ_NOPROBE);
+}
+
+static inline void irq_settings_clr_noprobe(struct irq_desc *desc)
+{
+       desc->status &= ~_IRQ_NOPROBE;
+}
+
+static inline void irq_settings_set_noprobe(struct irq_desc *desc)
+{
+       desc->status |= _IRQ_NOPROBE;
+}
+
+static inline bool irq_settings_can_move_pcntxt(struct irq_desc *desc)
+{
+       return desc->status & _IRQ_MOVE_PCNTXT;
+}
+
+static inline bool irq_settings_can_autoenable(struct irq_desc *desc)
+{
+       return !(desc->status & _IRQ_NOAUTOEN);
+}
+
+static inline bool irq_settings_is_nested_thread(struct irq_desc *desc)
+{
+       return desc->status & _IRQ_NESTED_THREAD;
+}
+
+/* Nothing should touch desc->status from now on */
+#undef status
+#define status         USE_THE_PROPER_WRAPPERS_YOU_MORON
index 3089d3b..dd586eb 100644 (file)
@@ -21,70 +21,94 @@ static int irqfixup __read_mostly;
 #define POLL_SPURIOUS_IRQ_INTERVAL (HZ/10)
 static void poll_spurious_irqs(unsigned long dummy);
 static DEFINE_TIMER(poll_spurious_irq_timer, poll_spurious_irqs, 0, 0);
+static int irq_poll_cpu;
+static atomic_t irq_poll_active;
+
+/*
+ * We wait here for a poller to finish.
+ *
+ * If the poll runs on this CPU, then we yell loudly and return
+ * false. That will leave the interrupt line disabled in the worst
+ * case, but it should never happen.
+ *
+ * We wait until the poller is done and then recheck disabled and
+ * action (about to be disabled). Only if it's still active, we return
+ * true and let the handler run.
+ */
+bool irq_wait_for_poll(struct irq_desc *desc)
+{
+       if (WARN_ONCE(irq_poll_cpu == smp_processor_id(),
+                     "irq poll in progress on cpu %d for irq %d\n",
+                     smp_processor_id(), desc->irq_data.irq))
+               return false;
+
+#ifdef CONFIG_SMP
+       do {
+               raw_spin_unlock(&desc->lock);
+               while (desc->istate & IRQS_INPROGRESS)
+                       cpu_relax();
+               raw_spin_lock(&desc->lock);
+       } while (desc->istate & IRQS_INPROGRESS);
+       /* Might have been disabled in meantime */
+       return !(desc->istate & IRQS_DISABLED) && desc->action;
+#else
+       return false;
+#endif
+}
+
 
 /*
  * Recovery handler for misrouted interrupts.
  */
-static int try_one_irq(int irq, struct irq_desc *desc)
+static int try_one_irq(int irq, struct irq_desc *desc, bool force)
 {
+       irqreturn_t ret = IRQ_NONE;
        struct irqaction *action;
-       int ok = 0, work = 0;
 
        raw_spin_lock(&desc->lock);
-       /* Already running on another processor */
-       if (desc->status & IRQ_INPROGRESS) {
-               /*
-                * Already running: If it is shared get the other
-                * CPU to go looking for our mystery interrupt too
-                */
-               if (desc->action && (desc->action->flags & IRQF_SHARED))
-                       desc->status |= IRQ_PENDING;
-               raw_spin_unlock(&desc->lock);
-               return ok;
-       }
-       /* Honour the normal IRQ locking */
-       desc->status |= IRQ_INPROGRESS;
-       action = desc->action;
-       raw_spin_unlock(&desc->lock);
 
-       while (action) {
-               /* Only shared IRQ handlers are safe to call */
-               if (action->flags & IRQF_SHARED) {
-                       if (action->handler(irq, action->dev_id) ==
-                               IRQ_HANDLED)
-                               ok = 1;
-               }
-               action = action->next;
-       }
-       local_irq_disable();
-       /* Now clean up the flags */
-       raw_spin_lock(&desc->lock);
-       action = desc->action;
+       /* PER_CPU and nested thread interrupts are never polled */
+       if (irq_settings_is_per_cpu(desc) || irq_settings_is_nested_thread(desc))
+               goto out;
 
        /*
-        * While we were looking for a fixup someone queued a real
-        * IRQ clashing with our walk:
+        * Do not poll disabled interrupts unless the spurious
+        * disabled poller asks explicitely.
         */
-       while ((desc->status & IRQ_PENDING) && action) {
+       if ((desc->istate & IRQS_DISABLED) && !force)
+               goto out;
+
+       /*
+        * All handlers must agree on IRQF_SHARED, so we test just the
+        * first. Check for action->next as well.
+        */
+       action = desc->action;
+       if (!action || !(action->flags & IRQF_SHARED) ||
+           (action->flags & __IRQF_TIMER) || !action->next)
+               goto out;
+
+       /* Already running on another processor */
+       if (desc->istate & IRQS_INPROGRESS) {
                /*
-                * Perform real IRQ processing for the IRQ we deferred
+                * Already running: If it is shared get the other
+                * CPU to go looking for our mystery interrupt too
                 */
-               work = 1;
-               raw_spin_unlock(&desc->lock);
-               handle_IRQ_event(irq, action);
-               raw_spin_lock(&desc->lock);
-               desc->status &= ~IRQ_PENDING;
+               irq_compat_set_pending(desc);
+               desc->istate |= IRQS_PENDING;
+               goto out;
        }
-       desc->status &= ~IRQ_INPROGRESS;
-       /*
-        * If we did actual work for the real IRQ line we must let the
-        * IRQ controller clean up too
-        */
-       if (work)
-               irq_end(irq, desc);
-       raw_spin_unlock(&desc->lock);
 
-       return ok;
+       /* Mark it poll in progress */
+       desc->istate |= IRQS_POLL_INPROGRESS;
+       do {
+               if (handle_irq_event(desc) == IRQ_HANDLED)
+                       ret = IRQ_HANDLED;
+               action = desc->action;
+       } while ((desc->istate & IRQS_PENDING) && action);
+       desc->istate &= ~IRQS_POLL_INPROGRESS;
+out:
+       raw_spin_unlock(&desc->lock);
+       return ret == IRQ_HANDLED;
 }
 
 static int misrouted_irq(int irq)
@@ -92,6 +116,11 @@ static int misrouted_irq(int irq)
        struct irq_desc *desc;
        int i, ok = 0;
 
+       if (atomic_inc_return(&irq_poll_active) == 1)
+               goto out;
+
+       irq_poll_cpu = smp_processor_id();
+
        for_each_irq_desc(i, desc) {
                if (!i)
                         continue;
@@ -99,9 +128,11 @@ static int misrouted_irq(int irq)
                if (i == irq)   /* Already tried */
                        continue;
 
-               if (try_one_irq(i, desc))
+               if (try_one_irq(i, desc, false))
                        ok = 1;
        }
+out:
+       atomic_dec(&irq_poll_active);
        /* So the caller can adjust the irq error counts */
        return ok;
 }
@@ -111,23 +142,28 @@ static void poll_spurious_irqs(unsigned long dummy)
        struct irq_desc *desc;
        int i;
 
+       if (atomic_inc_return(&irq_poll_active) != 1)
+               goto out;
+       irq_poll_cpu = smp_processor_id();
+
        for_each_irq_desc(i, desc) {
-               unsigned int status;
+               unsigned int state;
 
                if (!i)
                         continue;
 
                /* Racy but it doesn't matter */
-               status = desc->status;
+               state = desc->istate;
                barrier();
-               if (!(status & IRQ_SPURIOUS_DISABLED))
+               if (!(state & IRQS_SPURIOUS_DISABLED))
                        continue;
 
                local_irq_disable();
-               try_one_irq(i, desc);
+               try_one_irq(i, desc, true);
                local_irq_enable();
        }
-
+out:
+       atomic_dec(&irq_poll_active);
        mod_timer(&poll_spurious_irq_timer,
                  jiffies + POLL_SPURIOUS_IRQ_INTERVAL);
 }
@@ -139,15 +175,13 @@ static void poll_spurious_irqs(unsigned long dummy)
  *
  * (The other 100-of-100,000 interrupts may have been a correctly
  *  functioning device sharing an IRQ with the failing one)
- *
- * Called under desc->lock
  */
-
 static void
 __report_bad_irq(unsigned int irq, struct irq_desc *desc,
                 irqreturn_t action_ret)
 {
        struct irqaction *action;
+       unsigned long flags;
 
        if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) {
                printk(KERN_ERR "irq event %d: bogus return value %x\n",
@@ -159,6 +193,13 @@ __report_bad_irq(unsigned int irq, struct irq_desc *desc,
        dump_stack();
        printk(KERN_ERR "handlers:\n");
 
+       /*
+        * We need to take desc->lock here. note_interrupt() is called
+        * w/o desc->lock held, but IRQ_PROGRESS set. We might race
+        * with something else removing an action. It's ok to take
+        * desc->lock here. See synchronize_irq().
+        */
+       raw_spin_lock_irqsave(&desc->lock, flags);
        action = desc->action;
        while (action) {
                printk(KERN_ERR "[<%p>]", action->handler);
@@ -167,6 +208,7 @@ __report_bad_irq(unsigned int irq, struct irq_desc *desc,
                printk("\n");
                action = action->next;
        }
+       raw_spin_unlock_irqrestore(&desc->lock, flags);
 }
 
 static void
@@ -218,6 +260,9 @@ try_misrouted_irq(unsigned int irq, struct irq_desc *desc,
 void note_interrupt(unsigned int irq, struct irq_desc *desc,
                    irqreturn_t action_ret)
 {
+       if (desc->istate & IRQS_POLL_INPROGRESS)
+               return;
+
        if (unlikely(action_ret != IRQ_HANDLED)) {
                /*
                 * If we are seeing only the odd spurious IRQ caused by
@@ -254,9 +299,9 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc,
                 * Now kill the IRQ
                 */
                printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
-               desc->status |= IRQ_DISABLED | IRQ_SPURIOUS_DISABLED;
+               desc->istate |= IRQS_SPURIOUS_DISABLED;
                desc->depth++;
-               desc->irq_data.chip->irq_disable(&desc->irq_data);
+               irq_disable(desc);
 
                mod_timer(&poll_spurious_irq_timer,
                          jiffies + POLL_SPURIOUS_IRQ_INTERVAL);
index 34e00b7..efa290e 100644 (file)
@@ -2460,9 +2460,9 @@ static void find_module_sections(struct module *mod, struct load_info *info)
 #endif
 
 #ifdef CONFIG_TRACEPOINTS
-       mod->tracepoints = section_objs(info, "__tracepoints",
-                                       sizeof(*mod->tracepoints),
-                                       &mod->num_tracepoints);
+       mod->tracepoints_ptrs = section_objs(info, "__tracepoints_ptrs",
+                                            sizeof(*mod->tracepoints_ptrs),
+                                            &mod->num_tracepoints);
 #endif
 #ifdef HAVE_JUMP_LABEL
        mod->jump_entries = section_objs(info, "__jump_table",
@@ -3393,7 +3393,7 @@ void module_layout(struct module *mod,
                   struct modversion_info *ver,
                   struct kernel_param *kp,
                   struct kernel_symbol *ks,
-                  struct tracepoint *tp)
+                  struct tracepoint * const *tp)
 {
 }
 EXPORT_SYMBOL(module_layout);
@@ -3407,8 +3407,8 @@ void module_update_tracepoints(void)
        mutex_lock(&module_mutex);
        list_for_each_entry(mod, &modules, list)
                if (!mod->taints)
-                       tracepoint_update_probe_range(mod->tracepoints,
-                               mod->tracepoints + mod->num_tracepoints);
+                       tracepoint_update_probe_range(mod->tracepoints_ptrs,
+                               mod->tracepoints_ptrs + mod->num_tracepoints);
        mutex_unlock(&module_mutex);
 }
 
@@ -3432,8 +3432,8 @@ int module_get_iter_tracepoints(struct tracepoint_iter *iter)
                        else if (iter_mod > iter->module)
                                iter->tracepoint = NULL;
                        found = tracepoint_get_iter_range(&iter->tracepoint,
-                               iter_mod->tracepoints,
-                               iter_mod->tracepoints
+                               iter_mod->tracepoints_ptrs,
+                               iter_mod->tracepoints_ptrs
                                        + iter_mod->num_tracepoints);
                        if (found) {
                                iter->module = iter_mod;
index 126a302..ed253aa 100644 (file)
 
 #include <asm/irq_regs.h>
 
+struct remote_function_call {
+       struct task_struct *p;
+       int (*func)(void *info);
+       void *info;
+       int ret;
+};
+
+static void remote_function(void *data)
+{
+       struct remote_function_call *tfc = data;
+       struct task_struct *p = tfc->p;
+
+       if (p) {
+               tfc->ret = -EAGAIN;
+               if (task_cpu(p) != smp_processor_id() || !task_curr(p))
+                       return;
+       }
+
+       tfc->ret = tfc->func(tfc->info);
+}
+
+/**
+ * task_function_call - call a function on the cpu on which a task runs
+ * @p:         the task to evaluate
+ * @func:      the function to be called
+ * @info:      the function call argument
+ *
+ * Calls the function @func when the task is currently running. This might
+ * be on the current CPU, which just calls the function directly
+ *
+ * returns: @func return value, or
+ *         -ESRCH  - when the process isn't running
+ *         -EAGAIN - when the process moved away
+ */
+static int
+task_function_call(struct task_struct *p, int (*func) (void *info), void *info)
+{
+       struct remote_function_call data = {
+               .p = p,
+               .func = func,
+               .info = info,
+               .ret = -ESRCH, /* No such (running) process */
+       };
+
+       if (task_curr(p))
+               smp_call_function_single(task_cpu(p), remote_function, &data, 1);
+
+       return data.ret;
+}
+
+/**
+ * cpu_function_call - call a function on the cpu
+ * @func:      the function to be called
+ * @info:      the function call argument
+ *
+ * Calls the function @func on the remote cpu.
+ *
+ * returns: @func return value or -ENXIO when the cpu is offline
+ */
+static int cpu_function_call(int cpu, int (*func) (void *info), void *info)
+{
+       struct remote_function_call data = {
+               .p = NULL,
+               .func = func,
+               .info = info,
+               .ret = -ENXIO, /* No such CPU */
+       };
+
+       smp_call_function_single(cpu, remote_function, &data, 1);
+
+       return data.ret;
+}
+
+#define PERF_FLAG_ALL (PERF_FLAG_FD_NO_GROUP |\
+                      PERF_FLAG_FD_OUTPUT  |\
+                      PERF_FLAG_PID_CGROUP)
+
 enum event_type_t {
        EVENT_FLEXIBLE = 0x1,
        EVENT_PINNED = 0x2,
        EVENT_ALL = EVENT_FLEXIBLE | EVENT_PINNED,
 };
 
-atomic_t perf_task_events __read_mostly;
+/*
+ * perf_sched_events : >0 events exist
+ * perf_cgroup_events: >0 per-cpu cgroup events exist on this cpu
+ */
+atomic_t perf_sched_events __read_mostly;
+static DEFINE_PER_CPU(atomic_t, perf_cgroup_events);
+
 static atomic_t nr_mmap_events __read_mostly;
 static atomic_t nr_comm_events __read_mostly;
 static atomic_t nr_task_events __read_mostly;
@@ -67,7 +150,24 @@ int sysctl_perf_event_mlock __read_mostly = 512; /* 'free' kb per user */
 /*
  * max perf event sample rate
  */
-int sysctl_perf_event_sample_rate __read_mostly = 100000;
+#define DEFAULT_MAX_SAMPLE_RATE 100000
+int sysctl_perf_event_sample_rate __read_mostly = DEFAULT_MAX_SAMPLE_RATE;
+static int max_samples_per_tick __read_mostly =
+       DIV_ROUND_UP(DEFAULT_MAX_SAMPLE_RATE, HZ);
+
+int perf_proc_update_handler(struct ctl_table *table, int write,
+               void __user *buffer, size_t *lenp,
+               loff_t *ppos)
+{
+       int ret = proc_dointvec(table, write, buffer, lenp, ppos);
+
+       if (ret || !write)
+               return ret;
+
+       max_samples_per_tick = DIV_ROUND_UP(sysctl_perf_event_sample_rate, HZ);
+
+       return 0;
+}
 
 static atomic64_t perf_event_id;
 
@@ -75,7 +175,11 @@ static void cpu_ctx_sched_out(struct perf_cpu_context *cpuctx,
                              enum event_type_t event_type);
 
 static void cpu_ctx_sched_in(struct perf_cpu_context *cpuctx,
-                            enum event_type_t event_type);
+                            enum event_type_t event_type,
+                            struct task_struct *task);
+
+static void update_context_time(struct perf_event_context *ctx);
+static u64 perf_event_time(struct perf_event *event);
 
 void __weak perf_event_print_debug(void)       { }
 
@@ -89,6 +193,360 @@ static inline u64 perf_clock(void)
        return local_clock();
 }
 
+static inline struct perf_cpu_context *
+__get_cpu_context(struct perf_event_context *ctx)
+{
+       return this_cpu_ptr(ctx->pmu->pmu_cpu_context);
+}
+
+#ifdef CONFIG_CGROUP_PERF
+
+/*
+ * Must ensure cgroup is pinned (css_get) before calling
+ * this function. In other words, we cannot call this function
+ * if there is no cgroup event for the current CPU context.
+ */
+static inline struct perf_cgroup *
+perf_cgroup_from_task(struct task_struct *task)
+{
+       return container_of(task_subsys_state(task, perf_subsys_id),
+                       struct perf_cgroup, css);
+}
+
+static inline bool
+perf_cgroup_match(struct perf_event *event)
+{
+       struct perf_event_context *ctx = event->ctx;
+       struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
+
+       return !event->cgrp || event->cgrp == cpuctx->cgrp;
+}
+
+static inline void perf_get_cgroup(struct perf_event *event)
+{
+       css_get(&event->cgrp->css);
+}
+
+static inline void perf_put_cgroup(struct perf_event *event)
+{
+       css_put(&event->cgrp->css);
+}
+
+static inline void perf_detach_cgroup(struct perf_event *event)
+{
+       perf_put_cgroup(event);
+       event->cgrp = NULL;
+}
+
+static inline int is_cgroup_event(struct perf_event *event)
+{
+       return event->cgrp != NULL;
+}
+
+static inline u64 perf_cgroup_event_time(struct perf_event *event)
+{
+       struct perf_cgroup_info *t;
+
+       t = per_cpu_ptr(event->cgrp->info, event->cpu);
+       return t->time;
+}
+
+static inline void __update_cgrp_time(struct perf_cgroup *cgrp)
+{
+       struct perf_cgroup_info *info;
+       u64 now;
+
+       now = perf_clock();
+
+       info = this_cpu_ptr(cgrp->info);
+
+       info->time += now - info->timestamp;
+       info->timestamp = now;
+}
+
+static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx)
+{
+       struct perf_cgroup *cgrp_out = cpuctx->cgrp;
+       if (cgrp_out)
+               __update_cgrp_time(cgrp_out);
+}
+
+static inline void update_cgrp_time_from_event(struct perf_event *event)
+{
+       struct perf_cgroup *cgrp;
+
+       /*
+        * ensure we access cgroup data only when needed and
+        * when we know the cgroup is pinned (css_get)
+        */
+       if (!is_cgroup_event(event))
+               return;
+
+       cgrp = perf_cgroup_from_task(current);
+       /*
+        * Do not update time when cgroup is not active
+        */
+       if (cgrp == event->cgrp)
+               __update_cgrp_time(event->cgrp);
+}
+
+static inline void
+perf_cgroup_set_timestamp(struct task_struct *task,
+                         struct perf_event_context *ctx)
+{
+       struct perf_cgroup *cgrp;
+       struct perf_cgroup_info *info;
+
+       /*
+        * ctx->lock held by caller
+        * ensure we do not access cgroup data
+        * unless we have the cgroup pinned (css_get)
+        */
+       if (!task || !ctx->nr_cgroups)
+               return;
+
+       cgrp = perf_cgroup_from_task(task);
+       info = this_cpu_ptr(cgrp->info);
+       info->timestamp = ctx->timestamp;
+}
+
+#define PERF_CGROUP_SWOUT      0x1 /* cgroup switch out every event */
+#define PERF_CGROUP_SWIN       0x2 /* cgroup switch in events based on task */
+
+/*
+ * reschedule events based on the cgroup constraint of task.
+ *
+ * mode SWOUT : schedule out everything
+ * mode SWIN : schedule in based on cgroup for next
+ */
+void perf_cgroup_switch(struct task_struct *task, int mode)
+{
+       struct perf_cpu_context *cpuctx;
+       struct pmu *pmu;
+       unsigned long flags;
+
+       /*
+        * disable interrupts to avoid geting nr_cgroup
+        * changes via __perf_event_disable(). Also
+        * avoids preemption.
+        */
+       local_irq_save(flags);
+
+       /*
+        * we reschedule only in the presence of cgroup
+        * constrained events.
+        */
+       rcu_read_lock();
+
+       list_for_each_entry_rcu(pmu, &pmus, entry) {
+
+               cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
+
+               perf_pmu_disable(cpuctx->ctx.pmu);
+
+               /*
+                * perf_cgroup_events says at least one
+                * context on this CPU has cgroup events.
+                *
+                * ctx->nr_cgroups reports the number of cgroup
+                * events for a context.
+                */
+               if (cpuctx->ctx.nr_cgroups > 0) {
+
+                       if (mode & PERF_CGROUP_SWOUT) {
+                               cpu_ctx_sched_out(cpuctx, EVENT_ALL);
+                               /*
+                                * must not be done before ctxswout due
+                                * to event_filter_match() in event_sched_out()
+                                */
+                               cpuctx->cgrp = NULL;
+                       }
+
+                       if (mode & PERF_CGROUP_SWIN) {
+                               /* set cgrp before ctxsw in to
+                                * allow event_filter_match() to not
+                                * have to pass task around
+                                */
+                               cpuctx->cgrp = perf_cgroup_from_task(task);
+                               cpu_ctx_sched_in(cpuctx, EVENT_ALL, task);
+                       }
+               }
+
+               perf_pmu_enable(cpuctx->ctx.pmu);
+       }
+
+       rcu_read_unlock();
+
+       local_irq_restore(flags);
+}
+
+static inline void perf_cgroup_sched_out(struct task_struct *task)
+{
+       perf_cgroup_switch(task, PERF_CGROUP_SWOUT);
+}
+
+static inline void perf_cgroup_sched_in(struct task_struct *task)
+{
+       perf_cgroup_switch(task, PERF_CGROUP_SWIN);
+}
+
+static inline int perf_cgroup_connect(int fd, struct perf_event *event,
+                                     struct perf_event_attr *attr,
+                                     struct perf_event *group_leader)
+{
+       struct perf_cgroup *cgrp;
+       struct cgroup_subsys_state *css;
+       struct file *file;
+       int ret = 0, fput_needed;
+
+       file = fget_light(fd, &fput_needed);
+       if (!file)
+               return -EBADF;
+
+       css = cgroup_css_from_dir(file, perf_subsys_id);
+       if (IS_ERR(css)) {
+               ret = PTR_ERR(css);
+               goto out;
+       }
+
+       cgrp = container_of(css, struct perf_cgroup, css);
+       event->cgrp = cgrp;
+
+       /* must be done before we fput() the file */
+       perf_get_cgroup(event);
+
+       /*
+        * all events in a group must monitor
+        * the same cgroup because a task belongs
+        * to only one perf cgroup at a time
+        */
+       if (group_leader && group_leader->cgrp != cgrp) {
+               perf_detach_cgroup(event);
+               ret = -EINVAL;
+       }
+out:
+       fput_light(file, fput_needed);
+       return ret;
+}
+
+static inline void
+perf_cgroup_set_shadow_time(struct perf_event *event, u64 now)
+{
+       struct perf_cgroup_info *t;
+       t = per_cpu_ptr(event->cgrp->info, event->cpu);
+       event->shadow_ctx_time = now - t->timestamp;
+}
+
+static inline void
+perf_cgroup_defer_enabled(struct perf_event *event)
+{
+       /*
+        * when the current task's perf cgroup does not match
+        * the event's, we need to remember to call the
+        * perf_mark_enable() function the first time a task with
+        * a matching perf cgroup is scheduled in.
+        */
+       if (is_cgroup_event(event) && !perf_cgroup_match(event))
+               event->cgrp_defer_enabled = 1;
+}
+
+static inline void
+perf_cgroup_mark_enabled(struct perf_event *event,
+                        struct perf_event_context *ctx)
+{
+       struct perf_event *sub;
+       u64 tstamp = perf_event_time(event);
+
+       if (!event->cgrp_defer_enabled)
+               return;
+
+       event->cgrp_defer_enabled = 0;
+
+       event->tstamp_enabled = tstamp - event->total_time_enabled;
+       list_for_each_entry(sub, &event->sibling_list, group_entry) {
+               if (sub->state >= PERF_EVENT_STATE_INACTIVE) {
+                       sub->tstamp_enabled = tstamp - sub->total_time_enabled;
+                       sub->cgrp_defer_enabled = 0;
+               }
+       }
+}
+#else /* !CONFIG_CGROUP_PERF */
+
+static inline bool
+perf_cgroup_match(struct perf_event *event)
+{
+       return true;
+}
+
+static inline void perf_detach_cgroup(struct perf_event *event)
+{}
+
+static inline int is_cgroup_event(struct perf_event *event)
+{
+       return 0;
+}
+
+static inline u64 perf_cgroup_event_cgrp_time(struct perf_event *event)
+{
+       return 0;
+}
+
+static inline void update_cgrp_time_from_event(struct perf_event *event)
+{
+}
+
+static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx)
+{
+}
+
+static inline void perf_cgroup_sched_out(struct task_struct *task)
+{
+}
+
+static inline void perf_cgroup_sched_in(struct task_struct *task)
+{
+}
+
+static inline int perf_cgroup_connect(pid_t pid, struct perf_event *event,
+                                     struct perf_event_attr *attr,
+                                     struct perf_event *group_leader)
+{
+       return -EINVAL;
+}
+
+static inline void
+perf_cgroup_set_timestamp(struct task_struct *task,
+                         struct perf_event_context *ctx)
+{
+}
+
+void
+perf_cgroup_switch(struct task_struct *task, struct task_struct *next)
+{
+}
+
+static inline void
+perf_cgroup_set_shadow_time(struct perf_event *event, u64 now)
+{
+}
+
+static inline u64 perf_cgroup_event_time(struct perf_event *event)
+{
+       return 0;
+}
+
+static inline void
+perf_cgroup_defer_enabled(struct perf_event *event)
+{
+}
+
+static inline void
+perf_cgroup_mark_enabled(struct perf_event *event,
+                        struct perf_event_context *ctx)
+{
+}
+#endif
+
 void perf_pmu_disable(struct pmu *pmu)
 {
        int *count = this_cpu_ptr(pmu->pmu_disable_count);
@@ -254,7 +712,6 @@ static void perf_unpin_context(struct perf_event_context *ctx)
        raw_spin_lock_irqsave(&ctx->lock, flags);
        --ctx->pin_count;
        raw_spin_unlock_irqrestore(&ctx->lock, flags);
-       put_ctx(ctx);
 }
 
 /*
@@ -271,6 +728,10 @@ static void update_context_time(struct perf_event_context *ctx)
 static u64 perf_event_time(struct perf_event *event)
 {
        struct perf_event_context *ctx = event->ctx;
+
+       if (is_cgroup_event(event))
+               return perf_cgroup_event_time(event);
+
        return ctx ? ctx->time : 0;
 }
 
@@ -285,9 +746,20 @@ static void update_event_times(struct perf_event *event)
        if (event->state < PERF_EVENT_STATE_INACTIVE ||
            event->group_leader->state < PERF_EVENT_STATE_INACTIVE)
                return;
-
-       if (ctx->is_active)
+       /*
+        * in cgroup mode, time_enabled represents
+        * the time the event was enabled AND active
+        * tasks were in the monitored cgroup. This is
+        * independent of the activity of the context as
+        * there may be a mix of cgroup and non-cgroup events.
+        *
+        * That is why we treat cgroup events differently
+        * here.
+        */
+       if (is_cgroup_event(event))
                run_end = perf_event_time(event);
+       else if (ctx->is_active)
+               run_end = ctx->time;
        else
                run_end = event->tstamp_stopped;
 
@@ -299,6 +771,7 @@ static void update_event_times(struct perf_event *event)
                run_end = perf_event_time(event);
 
        event->total_time_running = run_end - event->tstamp_running;
+
 }
 
 /*
@@ -347,6 +820,9 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx)
                list_add_tail(&event->group_entry, list);
        }
 
+       if (is_cgroup_event(event))
+               ctx->nr_cgroups++;
+
        list_add_rcu(&event->event_entry, &ctx->event_list);
        if (!ctx->nr_events)
                perf_pmu_rotate_start(ctx->pmu);
@@ -473,6 +949,9 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx)
 
        event->attach_state &= ~PERF_ATTACH_CONTEXT;
 
+       if (is_cgroup_event(event))
+               ctx->nr_cgroups--;
+
        ctx->nr_events--;
        if (event->attr.inherit_stat)
                ctx->nr_stat--;
@@ -544,7 +1023,8 @@ out:
 static inline int
 event_filter_match(struct perf_event *event)
 {
-       return event->cpu == -1 || event->cpu == smp_processor_id();
+       return (event->cpu == -1 || event->cpu == smp_processor_id())
+           && perf_cgroup_match(event);
 }
 
 static void
@@ -562,7 +1042,7 @@ event_sched_out(struct perf_event *event,
         */
        if (event->state == PERF_EVENT_STATE_INACTIVE
            && !event_filter_match(event)) {
-               delta = ctx->time - event->tstamp_stopped;
+               delta = tstamp - event->tstamp_stopped;
                event->tstamp_running += delta;
                event->tstamp_stopped = tstamp;
        }
@@ -606,47 +1086,30 @@ group_sched_out(struct perf_event *group_event,
                cpuctx->exclusive = 0;
 }
 
-static inline struct perf_cpu_context *
-__get_cpu_context(struct perf_event_context *ctx)
-{
-       return this_cpu_ptr(ctx->pmu->pmu_cpu_context);
-}
-
 /*
  * Cross CPU call to remove a performance event
  *
  * We disable the event on the hardware level first. After that we
  * remove it from the context list.
  */
-static void __perf_event_remove_from_context(void *info)
+static int __perf_remove_from_context(void *info)
 {
        struct perf_event *event = info;
        struct perf_event_context *ctx = event->ctx;
        struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
 
-       /*
-        * If this is a task context, we need to check whether it is
-        * the current task context of this cpu. If not it has been
-        * scheduled out before the smp call arrived.
-        */
-       if (ctx->task && cpuctx->task_ctx != ctx)
-               return;
-
        raw_spin_lock(&ctx->lock);
-
        event_sched_out(event, cpuctx, ctx);
-
        list_del_event(event, ctx);
-
        raw_spin_unlock(&ctx->lock);
+
+       return 0;
 }
 
 
 /*
  * Remove the event from a task's (or a CPU's) list of events.
  *
- * Must be called with ctx->mutex held.
- *
  * CPU events are removed with a smp call. For task events we only
  * call when the task is on a CPU.
  *
@@ -657,49 +1120,48 @@ static void __perf_event_remove_from_context(void *info)
  * When called from perf_event_exit_task, it's OK because the
  * context has been detached from its task.
  */
-static void perf_event_remove_from_context(struct perf_event *event)
+static void perf_remove_from_context(struct perf_event *event)
 {
        struct perf_event_context *ctx = event->ctx;
        struct task_struct *task = ctx->task;
 
+       lockdep_assert_held(&ctx->mutex);
+
        if (!task) {
                /*
                 * Per cpu events are removed via an smp call and
                 * the removal is always successful.
                 */
-               smp_call_function_single(event->cpu,
-                                        __perf_event_remove_from_context,
-                                        event, 1);
+               cpu_function_call(event->cpu, __perf_remove_from_context, event);
                return;
        }
 
 retry:
-       task_oncpu_function_call(task, __perf_event_remove_from_context,
-                                event);
+       if (!task_function_call(task, __perf_remove_from_context, event))
+               return;
 
        raw_spin_lock_irq(&ctx->lock);
        /*
-        * If the context is active we need to retry the smp call.
+        * If we failed to find a running task, but find the context active now
+        * that we've acquired the ctx->lock, retry.
         */
-       if (ctx->nr_active && !list_empty(&event->group_entry)) {
+       if (ctx->is_active) {
                raw_spin_unlock_irq(&ctx->lock);
                goto retry;
        }
 
        /*
-        * The lock prevents that this context is scheduled in so we
-        * can remove the event safely, if the call above did not
-        * succeed.
+        * Since the task isn't running, its safe to remove the event, us
+        * holding the ctx->lock ensures the task won't get scheduled in.
         */
-       if (!list_empty(&event->group_entry))
-               list_del_event(event, ctx);
+       list_del_event(event, ctx);
        raw_spin_unlock_irq(&ctx->lock);
 }
 
 /*
  * Cross CPU call to disable a performance event
  */
-static void __perf_event_disable(void *info)
+static int __perf_event_disable(void *info)
 {
        struct perf_event *event = info;
        struct perf_event_context *ctx = event->ctx;
@@ -708,9 +1170,12 @@ static void __perf_event_disable(void *info)
        /*
         * If this is a per-task event, need to check whether this
         * event's task is the current task on this cpu.
+        *
+        * Can trigger due to concurrent perf_event_context_sched_out()
+        * flipping contexts around.
         */
        if (ctx->task && cpuctx->task_ctx != ctx)
-               return;
+               return -EINVAL;
 
        raw_spin_lock(&ctx->lock);
 
@@ -720,6 +1185,7 @@ static void __perf_event_disable(void *info)
         */
        if (event->state >= PERF_EVENT_STATE_INACTIVE) {
                update_context_time(ctx);
+               update_cgrp_time_from_event(event);
                update_group_times(event);
                if (event == event->group_leader)
                        group_sched_out(event, cpuctx, ctx);
@@ -729,6 +1195,8 @@ static void __perf_event_disable(void *info)
        }
 
        raw_spin_unlock(&ctx->lock);
+
+       return 0;
 }
 
 /*
@@ -753,13 +1221,13 @@ void perf_event_disable(struct perf_event *event)
                /*
                 * Disable the event on the cpu that it's on
                 */
-               smp_call_function_single(event->cpu, __perf_event_disable,
-                                        event, 1);
+               cpu_function_call(event->cpu, __perf_event_disable, event);
                return;
        }
 
 retry:
-       task_oncpu_function_call(task, __perf_event_disable, event);
+       if (!task_function_call(task, __perf_event_disable, event))
+               return;
 
        raw_spin_lock_irq(&ctx->lock);
        /*
@@ -767,6 +1235,11 @@ retry:
         */
        if (event->state == PERF_EVENT_STATE_ACTIVE) {
                raw_spin_unlock_irq(&ctx->lock);
+               /*
+                * Reload the task pointer, it might have been changed by
+                * a concurrent perf_event_context_sched_out().
+                */
+               task = ctx->task;
                goto retry;
        }
 
@@ -778,10 +1251,48 @@ retry:
                update_group_times(event);
                event->state = PERF_EVENT_STATE_OFF;
        }
-
        raw_spin_unlock_irq(&ctx->lock);
 }
 
+static void perf_set_shadow_time(struct perf_event *event,
+                                struct perf_event_context *ctx,
+                                u64 tstamp)
+{
+       /*
+        * use the correct time source for the time snapshot
+        *
+        * We could get by without this by leveraging the
+        * fact that to get to this function, the caller
+        * has most likely already called update_context_time()
+        * and update_cgrp_time_xx() and thus both timestamp
+        * are identical (or very close). Given that tstamp is,
+        * already adjusted for cgroup, we could say that:
+        *    tstamp - ctx->timestamp
+        * is equivalent to
+        *    tstamp - cgrp->timestamp.
+        *
+        * Then, in perf_output_read(), the calculation would
+        * work with no changes because:
+        * - event is guaranteed scheduled in
+        * - no scheduled out in between
+        * - thus the timestamp would be the same
+        *
+        * But this is a bit hairy.
+        *
+        * So instead, we have an explicit cgroup call to remain
+        * within the time time source all along. We believe it
+        * is cleaner and simpler to understand.
+        */
+       if (is_cgroup_event(event))
+               perf_cgroup_set_shadow_time(event, tstamp);
+       else
+               event->shadow_ctx_time = tstamp - ctx->timestamp;
+}
+
+#define MAX_INTERRUPTS (~0ULL)
+
+static void perf_log_throttle(struct perf_event *event, int enable);
+
 static int
 event_sched_in(struct perf_event *event,
                 struct perf_cpu_context *cpuctx,
@@ -794,6 +1305,17 @@ event_sched_in(struct perf_event *event,
 
        event->state = PERF_EVENT_STATE_ACTIVE;
        event->oncpu = smp_processor_id();
+
+       /*
+        * Unthrottle events, since we scheduled we might have missed several
+        * ticks already, also for a heavily scheduling task there is little
+        * guarantee it'll get a tick in a timely manner.
+        */
+       if (unlikely(event->hw.interrupts == MAX_INTERRUPTS)) {
+               perf_log_throttle(event, 1);
+               event->hw.interrupts = 0;
+       }
+
        /*
         * The new state must be visible before we turn it on in the hardware:
         */
@@ -807,7 +1329,7 @@ event_sched_in(struct perf_event *event,
 
        event->tstamp_running += tstamp - event->tstamp_stopped;
 
-       event->shadow_ctx_time = tstamp - ctx->timestamp;
+       perf_set_shadow_time(event, ctx, tstamp);
 
        if (!is_software_event(event))
                cpuctx->active_oncpu++;
@@ -928,12 +1450,15 @@ static void add_event_to_ctx(struct perf_event *event,
        event->tstamp_stopped = tstamp;
 }
 
+static void perf_event_context_sched_in(struct perf_event_context *ctx,
+                                       struct task_struct *tsk);
+
 /*
  * Cross CPU call to install and enable a performance event
  *
  * Must be called with ctx->mutex held
  */
-static void __perf_install_in_context(void *info)
+static int  __perf_install_in_context(void *info)
 {
        struct perf_event *event = info;
        struct perf_event_context *ctx = event->ctx;
@@ -942,21 +1467,22 @@ static void __perf_install_in_context(void *info)
        int err;
 
        /*
-        * If this is a task context, we need to check whether it is
-        * the current task context of this cpu. If not it has been
-        * scheduled out before the smp call arrived.
-        * Or possibly this is the right context but it isn't
-        * on this cpu because it had no events.
+        * In case we're installing a new context to an already running task,
+        * could also happen before perf_event_task_sched_in() on architectures
+        * which do context switches with IRQs enabled.
         */
-       if (ctx->task && cpuctx->task_ctx != ctx) {
-               if (cpuctx->task_ctx || ctx->task != current)
-                       return;
-               cpuctx->task_ctx = ctx;
-       }
+       if (ctx->task && !cpuctx->task_ctx)
+               perf_event_context_sched_in(ctx, ctx->task);
 
        raw_spin_lock(&ctx->lock);
        ctx->is_active = 1;
        update_context_time(ctx);
+       /*
+        * update cgrp time only if current cgrp
+        * matches event->cgrp. Must be done before
+        * calling add_event_to_ctx()
+        */
+       update_cgrp_time_from_event(event);
 
        add_event_to_ctx(event, ctx);
 
@@ -997,6 +1523,8 @@ static void __perf_install_in_context(void *info)
 
 unlock:
        raw_spin_unlock(&ctx->lock);
+
+       return 0;
 }
 
 /*
@@ -1008,8 +1536,6 @@ unlock:
  * If the event is attached to a task which is on a CPU we use a smp
  * call to enable it in the task context. The task might have been
  * scheduled away, but we check this in the smp call again.
- *
- * Must be called with ctx->mutex held.
  */
 static void
 perf_install_in_context(struct perf_event_context *ctx,
@@ -1018,6 +1544,8 @@ perf_install_in_context(struct perf_event_context *ctx,
 {
        struct task_struct *task = ctx->task;
 
+       lockdep_assert_held(&ctx->mutex);
+
        event->ctx = ctx;
 
        if (!task) {
@@ -1025,31 +1553,29 @@ perf_install_in_context(struct perf_event_context *ctx,
                 * Per cpu events are installed via an smp call and
                 * the install is always successful.
                 */
-               smp_call_function_single(cpu, __perf_install_in_context,
-                                        event, 1);
+               cpu_function_call(cpu, __perf_install_in_context, event);
                return;
        }
 
 retry:
-       task_oncpu_function_call(task, __perf_install_in_context,
-                                event);
+       if (!task_function_call(task, __perf_install_in_context, event))
+               return;
 
        raw_spin_lock_irq(&ctx->lock);
        /*
-        * we need to retry the smp call.
+        * If we failed to find a running task, but find the context active now
+        * that we've acquired the ctx->lock, retry.
         */
-       if (ctx->is_active && list_empty(&event->group_entry)) {
+       if (ctx->is_active) {
                raw_spin_unlock_irq(&ctx->lock);
                goto retry;
        }
 
        /*
-        * The lock prevents that this context is scheduled in so we
-        * can add the event safely, if it the call above did not
-        * succeed.
+        * Since the task isn't running, its safe to add the event, us holding
+        * the ctx->lock ensures the task won't get scheduled in.
         */
-       if (list_empty(&event->group_entry))
-               add_event_to_ctx(event, ctx);
+       add_event_to_ctx(event, ctx);
        raw_spin_unlock_irq(&ctx->lock);
 }
 
@@ -1078,7 +1604,7 @@ static void __perf_event_mark_enabled(struct perf_event *event,
 /*
  * Cross CPU call to enable a performance event
  */
-static void __perf_event_enable(void *info)
+static int __perf_event_enable(void *info)
 {
        struct perf_event *event = info;
        struct perf_event_context *ctx = event->ctx;
@@ -1086,26 +1612,27 @@ static void __perf_event_enable(void *info)
        struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
        int err;
 
-       /*
-        * If this is a per-task event, need to check whether this
-        * event's task is the current task on this cpu.
-        */
-       if (ctx->task && cpuctx->task_ctx != ctx) {
-               if (cpuctx->task_ctx || ctx->task != current)
-                       return;
-               cpuctx->task_ctx = ctx;
-       }
+       if (WARN_ON_ONCE(!ctx->is_active))
+               return -EINVAL;
 
        raw_spin_lock(&ctx->lock);
-       ctx->is_active = 1;
        update_context_time(ctx);
 
        if (event->state >= PERF_EVENT_STATE_INACTIVE)
                goto unlock;
+
+       /*
+        * set current task's cgroup time reference point
+        */
+       perf_cgroup_set_timestamp(current, ctx);
+
        __perf_event_mark_enabled(event, ctx);
 
-       if (!event_filter_match(event))
+       if (!event_filter_match(event)) {
+               if (is_cgroup_event(event))
+                       perf_cgroup_defer_enabled(event);
                goto unlock;
+       }
 
        /*
         * If the event is in a group and isn't the group leader,
@@ -1138,6 +1665,8 @@ static void __perf_event_enable(void *info)
 
 unlock:
        raw_spin_unlock(&ctx->lock);
+
+       return 0;
 }
 
 /*
@@ -1158,8 +1687,7 @@ void perf_event_enable(struct perf_event *event)
                /*
                 * Enable the event on the cpu that it's on
                 */
-               smp_call_function_single(event->cpu, __perf_event_enable,
-                                        event, 1);
+               cpu_function_call(event->cpu, __perf_event_enable, event);
                return;
        }
 
@@ -1178,8 +1706,15 @@ void perf_event_enable(struct perf_event *event)
                event->state = PERF_EVENT_STATE_OFF;
 
 retry:
+       if (!ctx->is_active) {
+               __perf_event_mark_enabled(event, ctx);
+               goto out;
+       }
+
        raw_spin_unlock_irq(&ctx->lock);
-       task_oncpu_function_call(task, __perf_event_enable, event);
+
+       if (!task_function_call(task, __perf_event_enable, event))
+               return;
 
        raw_spin_lock_irq(&ctx->lock);
 
@@ -1187,15 +1722,14 @@ retry:
         * If the context is active and the event is still off,
         * we need to retry the cross-call.
         */
-       if (ctx->is_active && event->state == PERF_EVENT_STATE_OFF)
+       if (ctx->is_active && event->state == PERF_EVENT_STATE_OFF) {
+               /*
+                * task could have been flipped by a concurrent
+                * perf_event_context_sched_out()
+                */
+               task = ctx->task;
                goto retry;
-
-       /*
-        * Since we have the lock this context can't be scheduled
-        * in, so we can change the state safely.
-        */
-       if (event->state == PERF_EVENT_STATE_OFF)
-               __perf_event_mark_enabled(event, ctx);
+       }
 
 out:
        raw_spin_unlock_irq(&ctx->lock);
@@ -1227,6 +1761,7 @@ static void ctx_sched_out(struct perf_event_context *ctx,
        if (likely(!ctx->nr_events))
                goto out;
        update_context_time(ctx);
+       update_cgrp_time_from_cpuctx(cpuctx);
 
        if (!ctx->nr_active)
                goto out;
@@ -1339,8 +1874,8 @@ static void perf_event_sync_stat(struct perf_event_context *ctx,
        }
 }
 
-void perf_event_context_sched_out(struct task_struct *task, int ctxn,
-                                 struct task_struct *next)
+static void perf_event_context_sched_out(struct task_struct *task, int ctxn,
+                                        struct task_struct *next)
 {
        struct perf_event_context *ctx = task->perf_event_ctxp[ctxn];
        struct perf_event_context *next_ctx;
@@ -1416,6 +1951,14 @@ void __perf_event_task_sched_out(struct task_struct *task,
 
        for_each_task_context_nr(ctxn)
                perf_event_context_sched_out(task, ctxn, next);
+
+       /*
+        * if cgroup events exist on this CPU, then we need
+        * to check if we have to switch out PMU state.
+        * cgroup event are system-wide mode only
+        */
+       if (atomic_read(&__get_cpu_var(perf_cgroup_events)))
+               perf_cgroup_sched_out(task);
 }
 
 static void task_ctx_sched_out(struct perf_event_context *ctx,
@@ -1454,6 +1997,10 @@ ctx_pinned_sched_in(struct perf_event_context *ctx,
                if (!event_filter_match(event))
                        continue;
 
+               /* may need to reset tstamp_enabled */
+               if (is_cgroup_event(event))
+                       perf_cgroup_mark_enabled(event, ctx);
+
                if (group_can_go_on(event, cpuctx, 1))
                        group_sched_in(event, cpuctx, ctx);
 
@@ -1486,6 +2033,10 @@ ctx_flexible_sched_in(struct perf_event_context *ctx,
                if (!event_filter_match(event))
                        continue;
 
+               /* may need to reset tstamp_enabled */
+               if (is_cgroup_event(event))
+                       perf_cgroup_mark_enabled(event, ctx);
+
                if (group_can_go_on(event, cpuctx, can_add_hw)) {
                        if (group_sched_in(event, cpuctx, ctx))
                                can_add_hw = 0;
@@ -1496,15 +2047,19 @@ ctx_flexible_sched_in(struct perf_event_context *ctx,
 static void
 ctx_sched_in(struct perf_event_context *ctx,
             struct perf_cpu_context *cpuctx,
-            enum event_type_t event_type)
+            enum event_type_t event_type,
+            struct task_struct *task)
 {
+       u64 now;
+
        raw_spin_lock(&ctx->lock);
        ctx->is_active = 1;
        if (likely(!ctx->nr_events))
                goto out;
 
-       ctx->timestamp = perf_clock();
-
+       now = perf_clock();
+       ctx->timestamp = now;
+       perf_cgroup_set_timestamp(task, ctx);
        /*
         * First go through the list and put on any pinned groups
         * in order to give them the best chance of going on.
@@ -1521,11 +2076,12 @@ out:
 }
 
 static void cpu_ctx_sched_in(struct perf_cpu_context *cpuctx,
-                            enum event_type_t event_type)
+                            enum event_type_t event_type,
+                            struct task_struct *task)
 {
        struct perf_event_context *ctx = &cpuctx->ctx;
 
-       ctx_sched_in(ctx, cpuctx, event_type);
+       ctx_sched_in(ctx, cpuctx, event_type, task);
 }
 
 static void task_ctx_sched_in(struct perf_event_context *ctx,
@@ -1533,15 +2089,16 @@ static void task_ctx_sched_in(struct perf_event_context *ctx,
 {
        struct perf_cpu_context *cpuctx;
 
-               cpuctx = __get_cpu_context(ctx);
+       cpuctx = __get_cpu_context(ctx);
        if (cpuctx->task_ctx == ctx)
                return;
 
-       ctx_sched_in(ctx, cpuctx, event_type);
+       ctx_sched_in(ctx, cpuctx, event_type, NULL);
        cpuctx->task_ctx = ctx;
 }
 
-void perf_event_context_sched_in(struct perf_event_context *ctx)
+static void perf_event_context_sched_in(struct perf_event_context *ctx,
+                                       struct task_struct *task)
 {
        struct perf_cpu_context *cpuctx;
 
@@ -1557,9 +2114,9 @@ void perf_event_context_sched_in(struct perf_event_context *ctx)
         */
        cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE);
 
-       ctx_sched_in(ctx, cpuctx, EVENT_PINNED);
-       cpu_ctx_sched_in(cpuctx, EVENT_FLEXIBLE);
-       ctx_sched_in(ctx, cpuctx, EVENT_FLEXIBLE);
+       ctx_sched_in(ctx, cpuctx, EVENT_PINNED, task);
+       cpu_ctx_sched_in(cpuctx, EVENT_FLEXIBLE, task);
+       ctx_sched_in(ctx, cpuctx, EVENT_FLEXIBLE, task);
 
        cpuctx->task_ctx = ctx;
 
@@ -1592,14 +2149,17 @@ void __perf_event_task_sched_in(struct task_struct *task)
                if (likely(!ctx))
                        continue;
 
-               perf_event_context_sched_in(ctx);
+               perf_event_context_sched_in(ctx, task);
        }
+       /*
+        * if cgroup events exist on this CPU, then we need
+        * to check if we have to switch in PMU state.
+        * cgroup event are system-wide mode only
+        */
+       if (atomic_read(&__get_cpu_var(perf_cgroup_events)))
+               perf_cgroup_sched_in(task);
 }
 
-#define MAX_INTERRUPTS (~0ULL)
-
-static void perf_log_throttle(struct perf_event *event, int enable);
-
 static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count)
 {
        u64 frequency = event->attr.sample_freq;
@@ -1627,7 +2187,7 @@ static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count)
         * Reduce accuracy by one bit such that @a and @b converge
         * to a similar magnitude.
         */
-#define REDUCE_FLS(a, b)               \
+#define REDUCE_FLS(a, b)               \
 do {                                   \
        if (a##_fls > b##_fls) {        \
                a >>= 1;                \
@@ -1797,7 +2357,7 @@ static void perf_rotate_context(struct perf_cpu_context *cpuctx)
        if (ctx)
                rotate_ctx(ctx);
 
-       cpu_ctx_sched_in(cpuctx, EVENT_FLEXIBLE);
+       cpu_ctx_sched_in(cpuctx, EVENT_FLEXIBLE, current);
        if (ctx)
                task_ctx_sched_in(ctx, EVENT_FLEXIBLE);
 
@@ -1876,7 +2436,7 @@ static void perf_event_enable_on_exec(struct perf_event_context *ctx)
 
        raw_spin_unlock(&ctx->lock);
 
-       perf_event_context_sched_in(ctx);
+       perf_event_context_sched_in(ctx, ctx->task);
 out:
        local_irq_restore(flags);
 }
@@ -1901,11 +2461,14 @@ static void __perf_event_read(void *info)
                return;
 
        raw_spin_lock(&ctx->lock);
-       update_context_time(ctx);
+       if (ctx->is_active) {
+               update_context_time(ctx);
+               update_cgrp_time_from_event(event);
+       }
        update_event_times(event);
+       if (event->state == PERF_EVENT_STATE_ACTIVE)
+               event->pmu->read(event);
        raw_spin_unlock(&ctx->lock);
-
-       event->pmu->read(event);
 }
 
 static inline u64 perf_event_count(struct perf_event *event)
@@ -1932,8 +2495,10 @@ static u64 perf_event_read(struct perf_event *event)
                 * (e.g., thread is blocked), in that case
                 * we cannot update context time
                 */
-               if (ctx->is_active)
+               if (ctx->is_active) {
                        update_context_time(ctx);
+                       update_cgrp_time_from_event(event);
+               }
                update_event_times(event);
                raw_spin_unlock_irqrestore(&ctx->lock, flags);
        }
@@ -1999,8 +2564,7 @@ static int alloc_callchain_buffers(void)
         * accessed from NMI. Use a temporary manual per cpu allocation
         * until that gets sorted out.
         */
-       size = sizeof(*entries) + sizeof(struct perf_callchain_entry *) *
-               num_possible_cpus();
+       size = offsetof(struct callchain_cpus_entries, cpu_entries[nr_cpu_ids]);
 
        entries = kzalloc(size, GFP_KERNEL);
        if (!entries)
@@ -2213,6 +2777,9 @@ errout:
 
 }
 
+/*
+ * Returns a matching context with refcount and pincount.
+ */
 static struct perf_event_context *
 find_get_context(struct pmu *pmu, struct task_struct *task, int cpu)
 {
@@ -2237,6 +2804,7 @@ find_get_context(struct pmu *pmu, struct task_struct *task, int cpu)
                cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
                ctx = &cpuctx->ctx;
                get_ctx(ctx);
+               ++ctx->pin_count;
 
                return ctx;
        }
@@ -2250,6 +2818,7 @@ retry:
        ctx = perf_lock_task_context(task, ctxn, &flags);
        if (ctx) {
                unclone_ctx(ctx);
+               ++ctx->pin_count;
                raw_spin_unlock_irqrestore(&ctx->lock, flags);
        }
 
@@ -2271,8 +2840,10 @@ retry:
                        err = -ESRCH;
                else if (task->perf_event_ctxp[ctxn])
                        err = -EAGAIN;
-               else
+               else {
+                       ++ctx->pin_count;
                        rcu_assign_pointer(task->perf_event_ctxp[ctxn], ctx);
+               }
                mutex_unlock(&task->perf_event_mutex);
 
                if (unlikely(err)) {
@@ -2312,7 +2883,7 @@ static void free_event(struct perf_event *event)
 
        if (!event->parent) {
                if (event->attach_state & PERF_ATTACH_TASK)
-                       jump_label_dec(&perf_task_events);
+                       jump_label_dec(&perf_sched_events);
                if (event->attr.mmap || event->attr.mmap_data)
                        atomic_dec(&nr_mmap_events);
                if (event->attr.comm)
@@ -2321,6 +2892,10 @@ static void free_event(struct perf_event *event)
                        atomic_dec(&nr_task_events);
                if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN)
                        put_callchain_buffers();
+               if (is_cgroup_event(event)) {
+                       atomic_dec(&per_cpu(perf_cgroup_events, event->cpu));
+                       jump_label_dec(&perf_sched_events);
+               }
        }
 
        if (event->buffer) {
@@ -2328,6 +2903,9 @@ static void free_event(struct perf_event *event)
                event->buffer = NULL;
        }
 
+       if (is_cgroup_event(event))
+               perf_detach_cgroup(event);
+
        if (event->destroy)
                event->destroy(event);
 
@@ -4395,26 +4973,14 @@ static int __perf_event_overflow(struct perf_event *event, int nmi,
        if (unlikely(!is_sampling_event(event)))
                return 0;
 
-       if (!throttle) {
-               hwc->interrupts++;
-       } else {
-               if (hwc->interrupts != MAX_INTERRUPTS) {
-                       hwc->interrupts++;
-                       if (HZ * hwc->interrupts >
-                                       (u64)sysctl_perf_event_sample_rate) {
-                               hwc->interrupts = MAX_INTERRUPTS;
-                               perf_log_throttle(event, 0);
-                               ret = 1;
-                       }
-               } else {
-                       /*
-                        * Keep re-disabling events even though on the previous
-                        * pass we disabled it - just in case we raced with a
-                        * sched-in and the event got enabled again:
-                        */
+       if (unlikely(hwc->interrupts >= max_samples_per_tick)) {
+               if (throttle) {
+                       hwc->interrupts = MAX_INTERRUPTS;
+                       perf_log_throttle(event, 0);
                        ret = 1;
                }
-       }
+       } else
+               hwc->interrupts++;
 
        if (event->attr.freq) {
                u64 now = perf_clock();
@@ -5051,6 +5617,10 @@ static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer)
        u64 period;
 
        event = container_of(hrtimer, struct perf_event, hw.hrtimer);
+
+       if (event->state != PERF_EVENT_STATE_ACTIVE)
+               return HRTIMER_NORESTART;
+
        event->pmu->read(event);
 
        perf_sample_data_init(&data, 0);
@@ -5077,9 +5647,6 @@ static void perf_swevent_start_hrtimer(struct perf_event *event)
        if (!is_sampling_event(event))
                return;
 
-       hrtimer_init(&hwc->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-       hwc->hrtimer.function = perf_swevent_hrtimer;
-
        period = local64_read(&hwc->period_left);
        if (period) {
                if (period < 0)
@@ -5106,6 +5673,30 @@ static void perf_swevent_cancel_hrtimer(struct perf_event *event)
        }
 }
 
+static void perf_swevent_init_hrtimer(struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (!is_sampling_event(event))
+               return;
+
+       hrtimer_init(&hwc->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       hwc->hrtimer.function = perf_swevent_hrtimer;
+
+       /*
+        * Since hrtimers have a fixed rate, we can do a static freq->period
+        * mapping and avoid the whole period adjust feedback stuff.
+        */
+       if (event->attr.freq) {
+               long freq = event->attr.sample_freq;
+
+               event->attr.sample_period = NSEC_PER_SEC / freq;
+               hwc->sample_period = event->attr.sample_period;
+               local64_set(&hwc->period_left, hwc->sample_period);
+               event->attr.freq = 0;
+       }
+}
+
 /*
  * Software event: cpu wall time clock
  */
@@ -5158,6 +5749,8 @@ static int cpu_clock_event_init(struct perf_event *event)
        if (event->attr.config != PERF_COUNT_SW_CPU_CLOCK)
                return -ENOENT;
 
+       perf_swevent_init_hrtimer(event);
+
        return 0;
 }
 
@@ -5213,16 +5806,9 @@ static void task_clock_event_del(struct perf_event *event, int flags)
 
 static void task_clock_event_read(struct perf_event *event)
 {
-       u64 time;
-
-       if (!in_nmi()) {
-               update_context_time(event->ctx);
-               time = event->ctx->time;
-       } else {
-               u64 now = perf_clock();
-               u64 delta = now - event->ctx->timestamp;
-               time = event->ctx->time + delta;
-       }
+       u64 now = perf_clock();
+       u64 delta = now - event->ctx->timestamp;
+       u64 time = event->ctx->time + delta;
 
        task_clock_event_update(event, time);
 }
@@ -5235,6 +5821,8 @@ static int task_clock_event_init(struct perf_event *event)
        if (event->attr.config != PERF_COUNT_SW_TASK_CLOCK)
                return -ENOENT;
 
+       perf_swevent_init_hrtimer(event);
+
        return 0;
 }
 
@@ -5506,17 +6094,22 @@ struct pmu *perf_init_event(struct perf_event *event)
 {
        struct pmu *pmu = NULL;
        int idx;
+       int ret;
 
        idx = srcu_read_lock(&pmus_srcu);
 
        rcu_read_lock();
        pmu = idr_find(&pmu_idr, event->attr.type);
        rcu_read_unlock();
-       if (pmu)
+       if (pmu) {
+               ret = pmu->event_init(event);
+               if (ret)
+                       pmu = ERR_PTR(ret);
                goto unlock;
+       }
 
        list_for_each_entry_rcu(pmu, &pmus, entry) {
-               int ret = pmu->event_init(event);
+               ret = pmu->event_init(event);
                if (!ret)
                        goto unlock;
 
@@ -5642,7 +6235,7 @@ done:
 
        if (!event->parent) {
                if (event->attach_state & PERF_ATTACH_TASK)
-                       jump_label_inc(&perf_task_events);
+                       jump_label_inc(&perf_sched_events);
                if (event->attr.mmap || event->attr.mmap_data)
                        atomic_inc(&nr_mmap_events);
                if (event->attr.comm)
@@ -5817,7 +6410,7 @@ SYSCALL_DEFINE5(perf_event_open,
        int err;
 
        /* for future expandability... */
-       if (flags & ~(PERF_FLAG_FD_NO_GROUP | PERF_FLAG_FD_OUTPUT))
+       if (flags & ~PERF_FLAG_ALL)
                return -EINVAL;
 
        err = perf_copy_attr(attr_uptr, &attr);
@@ -5834,6 +6427,15 @@ SYSCALL_DEFINE5(perf_event_open,
                        return -EINVAL;
        }
 
+       /*
+        * In cgroup mode, the pid argument is used to pass the fd
+        * opened to the cgroup directory in cgroupfs. The cpu argument
+        * designates the cpu on which to monitor threads from that
+        * cgroup.
+        */
+       if ((flags & PERF_FLAG_PID_CGROUP) && (pid == -1 || cpu == -1))
+               return -EINVAL;
+
        event_fd = get_unused_fd_flags(O_RDWR);
        if (event_fd < 0)
                return event_fd;
@@ -5851,7 +6453,7 @@ SYSCALL_DEFINE5(perf_event_open,
                        group_leader = NULL;
        }
 
-       if (pid != -1) {
+       if (pid != -1 && !(flags & PERF_FLAG_PID_CGROUP)) {
                task = find_lively_task_by_vpid(pid);
                if (IS_ERR(task)) {
                        err = PTR_ERR(task);
@@ -5865,6 +6467,19 @@ SYSCALL_DEFINE5(perf_event_open,
                goto err_task;
        }
 
+       if (flags & PERF_FLAG_PID_CGROUP) {
+               err = perf_cgroup_connect(pid, event, &attr, group_leader);
+               if (err)
+                       goto err_alloc;
+               /*
+                * one more event:
+                * - that has cgroup constraint on event->cpu
+                * - that may need work on context switch
+                */
+               atomic_inc(&per_cpu(perf_cgroup_events, event->cpu));
+               jump_label_inc(&perf_sched_events);
+       }
+
        /*
         * Special case software events and allow them to be part of
         * any hardware group.
@@ -5950,10 +6565,10 @@ SYSCALL_DEFINE5(perf_event_open,
                struct perf_event_context *gctx = group_leader->ctx;
 
                mutex_lock(&gctx->mutex);
-               perf_event_remove_from_context(group_leader);
+               perf_remove_from_context(group_leader);
                list_for_each_entry(sibling, &group_leader->sibling_list,
                                    group_entry) {
-                       perf_event_remove_from_context(sibling);
+                       perf_remove_from_context(sibling);
                        put_ctx(gctx);
                }
                mutex_unlock(&gctx->mutex);
@@ -5976,6 +6591,7 @@ SYSCALL_DEFINE5(perf_event_open,
 
        perf_install_in_context(ctx, event, cpu);
        ++ctx->generation;
+       perf_unpin_context(ctx);
        mutex_unlock(&ctx->mutex);
 
        event->owner = current;
@@ -6001,6 +6617,7 @@ SYSCALL_DEFINE5(perf_event_open,
        return event_fd;
 
 err_context:
+       perf_unpin_context(ctx);
        put_ctx(ctx);
 err_alloc:
        free_event(event);
@@ -6051,6 +6668,7 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
        mutex_lock(&ctx->mutex);
        perf_install_in_context(ctx, event, cpu);
        ++ctx->generation;
+       perf_unpin_context(ctx);
        mutex_unlock(&ctx->mutex);
 
        return event;
@@ -6104,7 +6722,7 @@ __perf_event_exit_task(struct perf_event *child_event,
 {
        struct perf_event *parent_event;
 
-       perf_event_remove_from_context(child_event);
+       perf_remove_from_context(child_event);
 
        parent_event = child_event->parent;
        /*
@@ -6411,7 +7029,7 @@ inherit_task_group(struct perf_event *event, struct task_struct *parent,
                return 0;
        }
 
-               child_ctx = child->perf_event_ctxp[ctxn];
+       child_ctx = child->perf_event_ctxp[ctxn];
        if (!child_ctx) {
                /*
                 * This is executed from the parent task context, so
@@ -6526,6 +7144,7 @@ int perf_event_init_context(struct task_struct *child, int ctxn)
        mutex_unlock(&parent_ctx->mutex);
 
        perf_unpin_context(parent_ctx);
+       put_ctx(parent_ctx);
 
        return ret;
 }
@@ -6595,9 +7214,9 @@ static void __perf_event_exit_context(void *__info)
        perf_pmu_rotate_stop(ctx->pmu);
 
        list_for_each_entry_safe(event, tmp, &ctx->pinned_groups, group_entry)
-               __perf_event_remove_from_context(event);
+               __perf_remove_from_context(event);
        list_for_each_entry_safe(event, tmp, &ctx->flexible_groups, group_entry)
-               __perf_event_remove_from_context(event);
+               __perf_remove_from_context(event);
 }
 
 static void perf_event_exit_cpu_context(int cpu)
@@ -6721,3 +7340,83 @@ unlock:
        return ret;
 }
 device_initcall(perf_event_sysfs_init);
+
+#ifdef CONFIG_CGROUP_PERF
+static struct cgroup_subsys_state *perf_cgroup_create(
+       struct cgroup_subsys *ss, struct cgroup *cont)
+{
+       struct perf_cgroup *jc;
+
+       jc = kzalloc(sizeof(*jc), GFP_KERNEL);
+       if (!jc)
+               return ERR_PTR(-ENOMEM);
+
+       jc->info = alloc_percpu(struct perf_cgroup_info);
+       if (!jc->info) {
+               kfree(jc);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       return &jc->css;
+}
+
+static void perf_cgroup_destroy(struct cgroup_subsys *ss,
+                               struct cgroup *cont)
+{
+       struct perf_cgroup *jc;
+       jc = container_of(cgroup_subsys_state(cont, perf_subsys_id),
+                         struct perf_cgroup, css);
+       free_percpu(jc->info);
+       kfree(jc);
+}
+
+static int __perf_cgroup_move(void *info)
+{
+       struct task_struct *task = info;
+       perf_cgroup_switch(task, PERF_CGROUP_SWOUT | PERF_CGROUP_SWIN);
+       return 0;
+}
+
+static void perf_cgroup_move(struct task_struct *task)
+{
+       task_function_call(task, __perf_cgroup_move, task);
+}
+
+static void perf_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
+               struct cgroup *old_cgrp, struct task_struct *task,
+               bool threadgroup)
+{
+       perf_cgroup_move(task);
+       if (threadgroup) {
+               struct task_struct *c;
+               rcu_read_lock();
+               list_for_each_entry_rcu(c, &task->thread_group, thread_group) {
+                       perf_cgroup_move(c);
+               }
+               rcu_read_unlock();
+       }
+}
+
+static void perf_cgroup_exit(struct cgroup_subsys *ss, struct cgroup *cgrp,
+               struct cgroup *old_cgrp, struct task_struct *task)
+{
+       /*
+        * cgroup_exit() is called in the copy_process() failure path.
+        * Ignore this case since the task hasn't ran yet, this avoids
+        * trying to poke a half freed task state from generic code.
+        */
+       if (!(task->flags & PF_EXITING))
+               return;
+
+       perf_cgroup_move(task);
+}
+
+struct cgroup_subsys perf_subsys = {
+       .name = "perf_event",
+       .subsys_id = perf_subsys_id,
+       .create = perf_cgroup_create,
+       .destroy = perf_cgroup_destroy,
+       .exit = perf_cgroup_exit,
+       .attach = perf_cgroup_attach,
+};
+#endif /* CONFIG_CGROUP_PERF */
index 05bb717..67fea9d 100644 (file)
@@ -176,7 +176,8 @@ static inline cputime_t virt_ticks(struct task_struct *p)
        return p->utime;
 }
 
-int posix_cpu_clock_getres(const clockid_t which_clock, struct timespec *tp)
+static int
+posix_cpu_clock_getres(const clockid_t which_clock, struct timespec *tp)
 {
        int error = check_clock(which_clock);
        if (!error) {
@@ -194,7 +195,8 @@ int posix_cpu_clock_getres(const clockid_t which_clock, struct timespec *tp)
        return error;
 }
 
-int posix_cpu_clock_set(const clockid_t which_clock, const struct timespec *tp)
+static int
+posix_cpu_clock_set(const clockid_t which_clock, const struct timespec *tp)
 {
        /*
         * You can never reset a CPU clock, but we check for other errors
@@ -317,7 +319,7 @@ static int cpu_clock_sample_group(const clockid_t which_clock,
 }
 
 
-int posix_cpu_clock_get(const clockid_t which_clock, struct timespec *tp)
+static int posix_cpu_clock_get(const clockid_t which_clock, struct timespec *tp)
 {
        const pid_t pid = CPUCLOCK_PID(which_clock);
        int error = -EINVAL;
@@ -379,7 +381,7 @@ int posix_cpu_clock_get(const clockid_t which_clock, struct timespec *tp)
  * This is called from sys_timer_create() and do_cpu_nanosleep() with the
  * new timer already all-zeros initialized.
  */
-int posix_cpu_timer_create(struct k_itimer *new_timer)
+static int posix_cpu_timer_create(struct k_itimer *new_timer)
 {
        int ret = 0;
        const pid_t pid = CPUCLOCK_PID(new_timer->it_clock);
@@ -425,7 +427,7 @@ int posix_cpu_timer_create(struct k_itimer *new_timer)
  * If we return TIMER_RETRY, it's necessary to release the timer's lock
  * and try again.  (This happens when the timer is in the middle of firing.)
  */
-int posix_cpu_timer_del(struct k_itimer *timer)
+static int posix_cpu_timer_del(struct k_itimer *timer)
 {
        struct task_struct *p = timer->it.cpu.task;
        int ret = 0;
@@ -665,8 +667,8 @@ static int cpu_timer_sample_group(const clockid_t which_clock,
  * If we return TIMER_RETRY, it's necessary to release the timer's lock
  * and try again.  (This happens when the timer is in the middle of firing.)
  */
-int posix_cpu_timer_set(struct k_itimer *timer, int flags,
-                       struct itimerspec *new, struct itimerspec *old)
+static int posix_cpu_timer_set(struct k_itimer *timer, int flags,
+                              struct itimerspec *new, struct itimerspec *old)
 {
        struct task_struct *p = timer->it.cpu.task;
        union cpu_time_count old_expires, new_expires, old_incr, val;
@@ -820,7 +822,7 @@ int posix_cpu_timer_set(struct k_itimer *timer, int flags,
        return ret;
 }
 
-void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp)
+static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp)
 {
        union cpu_time_count now;
        struct task_struct *p = timer->it.cpu.task;
@@ -1481,11 +1483,13 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
        return error;
 }
 
-int posix_cpu_nsleep(const clockid_t which_clock, int flags,
-                    struct timespec *rqtp, struct timespec __user *rmtp)
+static long posix_cpu_nsleep_restart(struct restart_block *restart_block);
+
+static int posix_cpu_nsleep(const clockid_t which_clock, int flags,
+                           struct timespec *rqtp, struct timespec __user *rmtp)
 {
        struct restart_block *restart_block =
-           &current_thread_info()->restart_block;
+               &current_thread_info()->restart_block;
        struct itimerspec it;
        int error;
 
@@ -1501,56 +1505,47 @@ int posix_cpu_nsleep(const clockid_t which_clock, int flags,
 
        if (error == -ERESTART_RESTARTBLOCK) {
 
-               if (flags & TIMER_ABSTIME)
+               if (flags & TIMER_ABSTIME)
                        return -ERESTARTNOHAND;
                /*
-                * Report back to the user the time still remaining.
-                */
-               if (rmtp != NULL && copy_to_user(rmtp, &it.it_value, sizeof *rmtp))
+                * Report back to the user the time still remaining.
+                */
+               if (rmtp && copy_to_user(rmtp, &it.it_value, sizeof *rmtp))
                        return -EFAULT;
 
                restart_block->fn = posix_cpu_nsleep_restart;
-               restart_block->arg0 = which_clock;
-               restart_block->arg1 = (unsigned long) rmtp;
-               restart_block->arg2 = rqtp->tv_sec;
-               restart_block->arg3 = rqtp->tv_nsec;
+               restart_block->nanosleep.index = which_clock;
+               restart_block->nanosleep.rmtp = rmtp;
+               restart_block->nanosleep.expires = timespec_to_ns(rqtp);
        }
        return error;
 }
 
-long posix_cpu_nsleep_restart(struct restart_block *restart_block)
+static long posix_cpu_nsleep_restart(struct restart_block *restart_block)
 {
-       clockid_t which_clock = restart_block->arg0;
-       struct timespec __user *rmtp;
+       clockid_t which_clock = restart_block->nanosleep.index;
        struct timespec t;
        struct itimerspec it;
        int error;
 
-       rmtp = (struct timespec __user *) restart_block->arg1;
-       t.tv_sec = restart_block->arg2;
-       t.tv_nsec = restart_block->arg3;
+       t = ns_to_timespec(restart_block->nanosleep.expires);
 
-       restart_block->fn = do_no_restart_syscall;
        error = do_cpu_nanosleep(which_clock, TIMER_ABSTIME, &t, &it);
 
        if (error == -ERESTART_RESTARTBLOCK) {
+               struct timespec __user *rmtp = restart_block->nanosleep.rmtp;
                /*
-                * Report back to the user the time still remaining.
-                */
-               if (rmtp != NULL && copy_to_user(rmtp, &it.it_value, sizeof *rmtp))
+                * Report back to the user the time still remaining.
+                */
+               if (rmtp && copy_to_user(rmtp, &it.it_value, sizeof *rmtp))
                        return -EFAULT;
 
-               restart_block->fn = posix_cpu_nsleep_restart;
-               restart_block->arg0 = which_clock;
-               restart_block->arg1 = (unsigned long) rmtp;
-               restart_block->arg2 = t.tv_sec;
-               restart_block->arg3 = t.tv_nsec;
+               restart_block->nanosleep.expires = timespec_to_ns(&t);
        }
        return error;
 
 }
 
-
 #define PROCESS_CLOCK  MAKE_PROCESS_CPUCLOCK(0, CPUCLOCK_SCHED)
 #define THREAD_CLOCK   MAKE_THREAD_CPUCLOCK(0, CPUCLOCK_SCHED)
 
@@ -1594,38 +1589,37 @@ static int thread_cpu_timer_create(struct k_itimer *timer)
        timer->it_clock = THREAD_CLOCK;
        return posix_cpu_timer_create(timer);
 }
-static int thread_cpu_nsleep(const clockid_t which_clock, int flags,
-                             struct timespec *rqtp, struct timespec __user *rmtp)
-{
-       return -EINVAL;
-}
-static long thread_cpu_nsleep_restart(struct restart_block *restart_block)
-{
-       return -EINVAL;
-}
+
+struct k_clock clock_posix_cpu = {
+       .clock_getres   = posix_cpu_clock_getres,
+       .clock_set      = posix_cpu_clock_set,
+       .clock_get      = posix_cpu_clock_get,
+       .timer_create   = posix_cpu_timer_create,
+       .nsleep         = posix_cpu_nsleep,
+       .nsleep_restart = posix_cpu_nsleep_restart,
+       .timer_set      = posix_cpu_timer_set,
+       .timer_del      = posix_cpu_timer_del,
+       .timer_get      = posix_cpu_timer_get,
+};
 
 static __init int init_posix_cpu_timers(void)
 {
        struct k_clock process = {
-               .clock_getres = process_cpu_clock_getres,
-               .clock_get = process_cpu_clock_get,
-               .clock_set = do_posix_clock_nosettime,
-               .timer_create = process_cpu_timer_create,
-               .nsleep = process_cpu_nsleep,
-               .nsleep_restart = process_cpu_nsleep_restart,
+               .clock_getres   = process_cpu_clock_getres,
+               .clock_get      = process_cpu_clock_get,
+               .timer_create   = process_cpu_timer_create,
+               .nsleep         = process_cpu_nsleep,
+               .nsleep_restart = process_cpu_nsleep_restart,
        };
        struct k_clock thread = {
-               .clock_getres = thread_cpu_clock_getres,
-               .clock_get = thread_cpu_clock_get,
-               .clock_set = do_posix_clock_nosettime,
-               .timer_create = thread_cpu_timer_create,
-               .nsleep = thread_cpu_nsleep,
-               .nsleep_restart = thread_cpu_nsleep_restart,
+               .clock_getres   = thread_cpu_clock_getres,
+               .clock_get      = thread_cpu_clock_get,
+               .timer_create   = thread_cpu_timer_create,
        };
        struct timespec ts;
 
-       register_posix_clock(CLOCK_PROCESS_CPUTIME_ID, &process);
-       register_posix_clock(CLOCK_THREAD_CPUTIME_ID, &thread);
+       posix_timers_register_clock(CLOCK_PROCESS_CPUTIME_ID, &process);
+       posix_timers_register_clock(CLOCK_THREAD_CPUTIME_ID, &thread);
 
        cputime_to_timespec(cputime_one_jiffy, &ts);
        onecputick = ts.tv_nsec;
index 93bd2eb..4c01249 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/init.h>
 #include <linux/compiler.h>
 #include <linux/idr.h>
+#include <linux/posix-clock.h>
 #include <linux/posix-timers.h>
 #include <linux/syscalls.h>
 #include <linux/wait.h>
@@ -81,6 +82,14 @@ static DEFINE_SPINLOCK(idr_lock);
 #error "SIGEV_THREAD_ID must not share bit with other SIGEV values!"
 #endif
 
+/*
+ * parisc wants ENOTSUP instead of EOPNOTSUPP
+ */
+#ifndef ENOTSUP
+# define ENANOSLEEP_NOTSUP EOPNOTSUPP
+#else
+# define ENANOSLEEP_NOTSUP ENOTSUP
+#endif
 
 /*
  * The timer ID is turned into a timer address by idr_find().
@@ -94,11 +103,7 @@ static DEFINE_SPINLOCK(idr_lock);
 /*
  * CLOCKs: The POSIX standard calls for a couple of clocks and allows us
  *         to implement others.  This structure defines the various
- *         clocks and allows the possibility of adding others.  We
- *         provide an interface to add clocks to the table and expect
- *         the "arch" code to add at least one clock that is high
- *         resolution.  Here we define the standard CLOCK_REALTIME as a
- *         1/HZ resolution clock.
+ *         clocks.
  *
  * RESOLUTION: Clock resolution is used to round up timer and interval
  *         times, NOT to report clock times, which are reported with as
@@ -108,20 +113,13 @@ static DEFINE_SPINLOCK(idr_lock);
  *         necessary code is written.  The standard says we should say
  *         something about this issue in the documentation...
  *
- * FUNCTIONS: The CLOCKs structure defines possible functions to handle
- *         various clock functions.  For clocks that use the standard
- *         system timer code these entries should be NULL.  This will
- *         allow dispatch without the overhead of indirect function
- *         calls.  CLOCKS that depend on other sources (e.g. WWV or GPS)
- *         must supply functions here, even if the function just returns
- *         ENOSYS.  The standard POSIX timer management code assumes the
- *         following: 1.) The k_itimer struct (sched.h) is used for the
- *         timer.  2.) The list, it_lock, it_clock, it_id and it_pid
- *         fields are not modified by timer code.
+ * FUNCTIONS: The CLOCKs structure defines possible functions to
+ *         handle various clock functions.
  *
- *          At this time all functions EXCEPT clock_nanosleep can be
- *          redirected by the CLOCKS structure.  Clock_nanosleep is in
- *          there, but the code ignores it.
+ *         The standard POSIX timer management code assumes the
+ *         following: 1.) The k_itimer struct (sched.h) is used for
+ *         the timer.  2.) The list, it_lock, it_clock, it_id and
+ *         it_pid fields are not modified by timer code.
  *
  * Permissions: It is assumed that the clock_settime() function defined
  *         for each clock will take care of permission checks.  Some
@@ -138,6 +136,7 @@ static struct k_clock posix_clocks[MAX_CLOCKS];
  */
 static int common_nsleep(const clockid_t, int flags, struct timespec *t,
                         struct timespec __user *rmtp);
+static int common_timer_create(struct k_itimer *new_timer);
 static void common_timer_get(struct k_itimer *, struct itimerspec *);
 static int common_timer_set(struct k_itimer *, int,
                            struct itimerspec *, struct itimerspec *);
@@ -158,76 +157,24 @@ static inline void unlock_timer(struct k_itimer *timr, unsigned long flags)
        spin_unlock_irqrestore(&timr->it_lock, flags);
 }
 
-/*
- * Call the k_clock hook function if non-null, or the default function.
- */
-#define CLOCK_DISPATCH(clock, call, arglist) \
-       ((clock) < 0 ? posix_cpu_##call arglist : \
-        (posix_clocks[clock].call != NULL \
-         ? (*posix_clocks[clock].call) arglist : common_##call arglist))
-
-/*
- * Default clock hook functions when the struct k_clock passed
- * to register_posix_clock leaves a function pointer null.
- *
- * The function common_CALL is the default implementation for
- * the function pointer CALL in struct k_clock.
- */
-
-static inline int common_clock_getres(const clockid_t which_clock,
-                                     struct timespec *tp)
-{
-       tp->tv_sec = 0;
-       tp->tv_nsec = posix_clocks[which_clock].res;
-       return 0;
-}
-
-/*
- * Get real time for posix timers
- */
-static int common_clock_get(clockid_t which_clock, struct timespec *tp)
+/* Get clock_realtime */
+static int posix_clock_realtime_get(clockid_t which_clock, struct timespec *tp)
 {
        ktime_get_real_ts(tp);
        return 0;
 }
 
-static inline int common_clock_set(const clockid_t which_clock,
-                                  struct timespec *tp)
+/* Set clock_realtime */
+static int posix_clock_realtime_set(const clockid_t which_clock,
+                                   const struct timespec *tp)
 {
        return do_sys_settimeofday(tp, NULL);
 }
 
-static int common_timer_create(struct k_itimer *new_timer)
-{
-       hrtimer_init(&new_timer->it.real.timer, new_timer->it_clock, 0);
-       return 0;
-}
-
-static int no_timer_create(struct k_itimer *new_timer)
-{
-       return -EOPNOTSUPP;
-}
-
-static int no_nsleep(const clockid_t which_clock, int flags,
-                    struct timespec *tsave, struct timespec __user *rmtp)
-{
-       return -EOPNOTSUPP;
-}
-
-/*
- * Return nonzero if we know a priori this clockid_t value is bogus.
- */
-static inline int invalid_clockid(const clockid_t which_clock)
+static int posix_clock_realtime_adj(const clockid_t which_clock,
+                                   struct timex *t)
 {
-       if (which_clock < 0)    /* CPU clock, posix_cpu_* will check it */
-               return 0;
-       if ((unsigned) which_clock >= MAX_CLOCKS)
-               return 1;
-       if (posix_clocks[which_clock].clock_getres != NULL)
-               return 0;
-       if (posix_clocks[which_clock].res != 0)
-               return 0;
-       return 1;
+       return do_adjtimex(t);
 }
 
 /*
@@ -240,7 +187,7 @@ static int posix_ktime_get_ts(clockid_t which_clock, struct timespec *tp)
 }
 
 /*
- * Get monotonic time for posix timers
+ * Get monotonic-raw time for posix timers
  */
 static int posix_get_monotonic_raw(clockid_t which_clock, struct timespec *tp)
 {
@@ -267,46 +214,70 @@ static int posix_get_coarse_res(const clockid_t which_clock, struct timespec *tp
        *tp = ktime_to_timespec(KTIME_LOW_RES);
        return 0;
 }
+
+static int posix_get_boottime(const clockid_t which_clock, struct timespec *tp)
+{
+       get_monotonic_boottime(tp);
+       return 0;
+}
+
+
 /*
  * Initialize everything, well, just everything in Posix clocks/timers ;)
  */
 static __init int init_posix_timers(void)
 {
        struct k_clock clock_realtime = {
-               .clock_getres = hrtimer_get_res,
+               .clock_getres   = hrtimer_get_res,
+               .clock_get      = posix_clock_realtime_get,
+               .clock_set      = posix_clock_realtime_set,
+               .clock_adj      = posix_clock_realtime_adj,
+               .nsleep         = common_nsleep,
+               .nsleep_restart = hrtimer_nanosleep_restart,
+               .timer_create   = common_timer_create,
+               .timer_set      = common_timer_set,
+               .timer_get      = common_timer_get,
+               .timer_del      = common_timer_del,
        };
        struct k_clock clock_monotonic = {
-               .clock_getres = hrtimer_get_res,
-               .clock_get = posix_ktime_get_ts,
-               .clock_set = do_posix_clock_nosettime,
+               .clock_getres   = hrtimer_get_res,
+               .clock_get      = posix_ktime_get_ts,
+               .nsleep         = common_nsleep,
+               .nsleep_restart = hrtimer_nanosleep_restart,
+               .timer_create   = common_timer_create,
+               .timer_set      = common_timer_set,
+               .timer_get      = common_timer_get,
+               .timer_del      = common_timer_del,
        };
        struct k_clock clock_monotonic_raw = {
-               .clock_getres = hrtimer_get_res,
-               .clock_get = posix_get_monotonic_raw,
-               .clock_set = do_posix_clock_nosettime,
-               .timer_create = no_timer_create,
-               .nsleep = no_nsleep,
+               .clock_getres   = hrtimer_get_res,
+               .clock_get      = posix_get_monotonic_raw,
        };
        struct k_clock clock_realtime_coarse = {
-               .clock_getres = posix_get_coarse_res,
-               .clock_get = posix_get_realtime_coarse,
-               .clock_set = do_posix_clock_nosettime,
-               .timer_create = no_timer_create,
-               .nsleep = no_nsleep,
+               .clock_getres   = posix_get_coarse_res,
+               .clock_get      = posix_get_realtime_coarse,
        };
        struct k_clock clock_monotonic_coarse = {
-               .clock_getres = posix_get_coarse_res,
-               .clock_get = posix_get_monotonic_coarse,
-               .clock_set = do_posix_clock_nosettime,
-               .timer_create = no_timer_create,
-               .nsleep = no_nsleep,
+               .clock_getres   = posix_get_coarse_res,
+               .clock_get      = posix_get_monotonic_coarse,
+       };
+       struct k_clock clock_boottime = {
+               .clock_getres   = hrtimer_get_res,
+               .clock_get      = posix_get_boottime,
+               .nsleep         = common_nsleep,
+               .nsleep_restart = hrtimer_nanosleep_restart,
+               .timer_create   = common_timer_create,
+               .timer_set      = common_timer_set,
+               .timer_get      = common_timer_get,
+               .timer_del      = common_timer_del,
        };
 
-       register_posix_clock(CLOCK_REALTIME, &clock_realtime);
-       register_posix_clock(CLOCK_MONOTONIC, &clock_monotonic);
-       register_posix_clock(CLOCK_MONOTONIC_RAW, &clock_monotonic_raw);
-       register_posix_clock(CLOCK_REALTIME_COARSE, &clock_realtime_coarse);
-       register_posix_clock(CLOCK_MONOTONIC_COARSE, &clock_monotonic_coarse);
+       posix_timers_register_clock(CLOCK_REALTIME, &clock_realtime);
+       posix_timers_register_clock(CLOCK_MONOTONIC, &clock_monotonic);
+       posix_timers_register_clock(CLOCK_MONOTONIC_RAW, &clock_monotonic_raw);
+       posix_timers_register_clock(CLOCK_REALTIME_COARSE, &clock_realtime_coarse);
+       posix_timers_register_clock(CLOCK_MONOTONIC_COARSE, &clock_monotonic_coarse);
+       posix_timers_register_clock(CLOCK_BOOTTIME, &clock_boottime);
 
        posix_timers_cache = kmem_cache_create("posix_timers_cache",
                                        sizeof (struct k_itimer), 0, SLAB_PANIC,
@@ -482,17 +453,29 @@ static struct pid *good_sigevent(sigevent_t * event)
        return task_pid(rtn);
 }
 
-void register_posix_clock(const clockid_t clock_id, struct k_clock *new_clock)
+void posix_timers_register_clock(const clockid_t clock_id,
+                                struct k_clock *new_clock)
 {
        if ((unsigned) clock_id >= MAX_CLOCKS) {
-               printk("POSIX clock register failed for clock_id %d\n",
+               printk(KERN_WARNING "POSIX clock register failed for clock_id %d\n",
+                      clock_id);
+               return;
+       }
+
+       if (!new_clock->clock_get) {
+               printk(KERN_WARNING "POSIX clock id %d lacks clock_get()\n",
+                      clock_id);
+               return;
+       }
+       if (!new_clock->clock_getres) {
+               printk(KERN_WARNING "POSIX clock id %d lacks clock_getres()\n",
                       clock_id);
                return;
        }
 
        posix_clocks[clock_id] = *new_clock;
 }
-EXPORT_SYMBOL_GPL(register_posix_clock);
+EXPORT_SYMBOL_GPL(posix_timers_register_clock);
 
 static struct k_itimer * alloc_posix_timer(void)
 {
@@ -523,19 +506,39 @@ static void release_posix_timer(struct k_itimer *tmr, int it_id_set)
        kmem_cache_free(posix_timers_cache, tmr);
 }
 
+static struct k_clock *clockid_to_kclock(const clockid_t id)
+{
+       if (id < 0)
+               return (id & CLOCKFD_MASK) == CLOCKFD ?
+                       &clock_posix_dynamic : &clock_posix_cpu;
+
+       if (id >= MAX_CLOCKS || !posix_clocks[id].clock_getres)
+               return NULL;
+       return &posix_clocks[id];
+}
+
+static int common_timer_create(struct k_itimer *new_timer)
+{
+       hrtimer_init(&new_timer->it.real.timer, new_timer->it_clock, 0);
+       return 0;
+}
+
 /* Create a POSIX.1b interval timer. */
 
 SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock,
                struct sigevent __user *, timer_event_spec,
                timer_t __user *, created_timer_id)
 {
+       struct k_clock *kc = clockid_to_kclock(which_clock);
        struct k_itimer *new_timer;
        int error, new_timer_id;
        sigevent_t event;
        int it_id_set = IT_ID_NOT_SET;
 
-       if (invalid_clockid(which_clock))
+       if (!kc)
                return -EINVAL;
+       if (!kc->timer_create)
+               return -EOPNOTSUPP;
 
        new_timer = alloc_posix_timer();
        if (unlikely(!new_timer))
@@ -597,7 +600,7 @@ SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock,
                goto out;
        }
 
-       error = CLOCK_DISPATCH(which_clock, timer_create, (new_timer));
+       error = kc->timer_create(new_timer);
        if (error)
                goto out;
 
@@ -607,7 +610,7 @@ SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock,
        spin_unlock_irq(&current->sighand->siglock);
 
        return 0;
-       /*
+       /*
         * In the case of the timer belonging to another task, after
         * the task is unlocked, the timer is owned by the other task
         * and may cease to exist at any time.  Don't use or modify
@@ -709,22 +712,28 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
 SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id,
                struct itimerspec __user *, setting)
 {
-       struct k_itimer *timr;
        struct itimerspec cur_setting;
+       struct k_itimer *timr;
+       struct k_clock *kc;
        unsigned long flags;
+       int ret = 0;
 
        timr = lock_timer(timer_id, &flags);
        if (!timr)
                return -EINVAL;
 
-       CLOCK_DISPATCH(timr->it_clock, timer_get, (timr, &cur_setting));
+       kc = clockid_to_kclock(timr->it_clock);
+       if (WARN_ON_ONCE(!kc || !kc->timer_get))
+               ret = -EINVAL;
+       else
+               kc->timer_get(timr, &cur_setting);
 
        unlock_timer(timr, flags);
 
-       if (copy_to_user(setting, &cur_setting, sizeof (cur_setting)))
+       if (!ret && copy_to_user(setting, &cur_setting, sizeof (cur_setting)))
                return -EFAULT;
 
-       return 0;
+       return ret;
 }
 
 /*
@@ -813,6 +822,7 @@ SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags,
        int error = 0;
        unsigned long flag;
        struct itimerspec *rtn = old_setting ? &old_spec : NULL;
+       struct k_clock *kc;
 
        if (!new_setting)
                return -EINVAL;
@@ -828,8 +838,11 @@ retry:
        if (!timr)
                return -EINVAL;
 
-       error = CLOCK_DISPATCH(timr->it_clock, timer_set,
-                              (timr, flags, &new_spec, rtn));
+       kc = clockid_to_kclock(timr->it_clock);
+       if (WARN_ON_ONCE(!kc || !kc->timer_set))
+               error = -EINVAL;
+       else
+               error = kc->timer_set(timr, flags, &new_spec, rtn);
 
        unlock_timer(timr, flag);
        if (error == TIMER_RETRY) {
@@ -844,7 +857,7 @@ retry:
        return error;
 }
 
-static inline int common_timer_del(struct k_itimer *timer)
+static int common_timer_del(struct k_itimer *timer)
 {
        timer->it.real.interval.tv64 = 0;
 
@@ -855,7 +868,11 @@ static inline int common_timer_del(struct k_itimer *timer)
 
 static inline int timer_delete_hook(struct k_itimer *timer)
 {
-       return CLOCK_DISPATCH(timer->it_clock, timer_del, (timer));
+       struct k_clock *kc = clockid_to_kclock(timer->it_clock);
+
+       if (WARN_ON_ONCE(!kc || !kc->timer_del))
+               return -EINVAL;
+       return kc->timer_del(timer);
 }
 
 /* Delete a POSIX.1b interval timer. */
@@ -927,69 +944,76 @@ void exit_itimers(struct signal_struct *sig)
        }
 }
 
-/* Not available / possible... functions */
-int do_posix_clock_nosettime(const clockid_t clockid, struct timespec *tp)
-{
-       return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(do_posix_clock_nosettime);
-
-int do_posix_clock_nonanosleep(const clockid_t clock, int flags,
-                              struct timespec *t, struct timespec __user *r)
-{
-#ifndef ENOTSUP
-       return -EOPNOTSUPP;     /* aka ENOTSUP in userland for POSIX */
-#else  /*  parisc does define it separately.  */
-       return -ENOTSUP;
-#endif
-}
-EXPORT_SYMBOL_GPL(do_posix_clock_nonanosleep);
-
 SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,
                const struct timespec __user *, tp)
 {
+       struct k_clock *kc = clockid_to_kclock(which_clock);
        struct timespec new_tp;
 
-       if (invalid_clockid(which_clock))
+       if (!kc || !kc->clock_set)
                return -EINVAL;
+
        if (copy_from_user(&new_tp, tp, sizeof (*tp)))
                return -EFAULT;
 
-       return CLOCK_DISPATCH(which_clock, clock_set, (which_clock, &new_tp));
+       return kc->clock_set(which_clock, &new_tp);
 }
 
 SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock,
                struct timespec __user *,tp)
 {
+       struct k_clock *kc = clockid_to_kclock(which_clock);
        struct timespec kernel_tp;
        int error;
 
-       if (invalid_clockid(which_clock))
+       if (!kc)
                return -EINVAL;
-       error = CLOCK_DISPATCH(which_clock, clock_get,
-                              (which_clock, &kernel_tp));
+
+       error = kc->clock_get(which_clock, &kernel_tp);
+
        if (!error && copy_to_user(tp, &kernel_tp, sizeof (kernel_tp)))
                error = -EFAULT;
 
        return error;
+}
+
+SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock,
+               struct timex __user *, utx)
+{
+       struct k_clock *kc = clockid_to_kclock(which_clock);
+       struct timex ktx;
+       int err;
+
+       if (!kc)
+               return -EINVAL;
+       if (!kc->clock_adj)
+               return -EOPNOTSUPP;
+
+       if (copy_from_user(&ktx, utx, sizeof(ktx)))
+               return -EFAULT;
+
+       err = kc->clock_adj(which_clock, &ktx);
+
+       if (!err && copy_to_user(utx, &ktx, sizeof(ktx)))
+               return -EFAULT;
 
+       return err;
 }
 
 SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock,
                struct timespec __user *, tp)
 {
+       struct k_clock *kc = clockid_to_kclock(which_clock);
        struct timespec rtn_tp;
        int error;
 
-       if (invalid_clockid(which_clock))
+       if (!kc)
                return -EINVAL;
 
-       error = CLOCK_DISPATCH(which_clock, clock_getres,
-                              (which_clock, &rtn_tp));
+       error = kc->clock_getres(which_clock, &rtn_tp);
 
-       if (!error && tp && copy_to_user(tp, &rtn_tp, sizeof (rtn_tp))) {
+       if (!error && tp && copy_to_user(tp, &rtn_tp, sizeof (rtn_tp)))
                error = -EFAULT;
-       }
 
        return error;
 }
@@ -1009,10 +1033,13 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
                const struct timespec __user *, rqtp,
                struct timespec __user *, rmtp)
 {
+       struct k_clock *kc = clockid_to_kclock(which_clock);
        struct timespec t;
 
-       if (invalid_clockid(which_clock))
+       if (!kc)
                return -EINVAL;
+       if (!kc->nsleep)
+               return -ENANOSLEEP_NOTSUP;
 
        if (copy_from_user(&t, rqtp, sizeof (struct timespec)))
                return -EFAULT;
@@ -1020,27 +1047,20 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags,
        if (!timespec_valid(&t))
                return -EINVAL;
 
-       return CLOCK_DISPATCH(which_clock, nsleep,
-                             (which_clock, flags, &t, rmtp));
-}
-
-/*
- * nanosleep_restart for monotonic and realtime clocks
- */
-static int common_nsleep_restart(struct restart_block *restart_block)
-{
-       return hrtimer_nanosleep_restart(restart_block);
+       return kc->nsleep(which_clock, flags, &t, rmtp);
 }
 
 /*
  * This will restart clock_nanosleep. This is required only by
  * compat_clock_nanosleep_restart for now.
  */
-long
-clock_nanosleep_restart(struct restart_block *restart_block)
+long clock_nanosleep_restart(struct restart_block *restart_block)
 {
-       clockid_t which_clock = restart_block->arg0;
+       clockid_t which_clock = restart_block->nanosleep.index;
+       struct k_clock *kc = clockid_to_kclock(which_clock);
+
+       if (WARN_ON_ONCE(!kc || !kc->nsleep_restart))
+               return -EINVAL;
 
-       return CLOCK_DISPATCH(which_clock, nsleep_restart,
-                             (restart_block));
+       return kc->nsleep_restart(restart_block);
 }
index 7b5db6a..7018530 100644 (file)
@@ -326,7 +326,7 @@ EXPORT_SYMBOL_GPL(pm_wq);
 
 static int __init pm_start_workqueue(void)
 {
-       pm_wq = alloc_workqueue("pm", WQ_FREEZEABLE, 0);
+       pm_wq = alloc_workqueue("pm", WQ_FREEZABLE, 0);
 
        return pm_wq ? 0 : -ENOMEM;
 }
index d6d2a10..0cf3a27 100644 (file)
@@ -22,7 +22,7 @@
  */
 #define TIMEOUT        (20 * HZ)
 
-static inline int freezeable(struct task_struct * p)
+static inline int freezable(struct task_struct * p)
 {
        if ((p == current) ||
            (p->flags & PF_NOFREEZE) ||
@@ -53,7 +53,7 @@ static int try_to_freeze_tasks(bool sig_only)
                todo = 0;
                read_lock(&tasklist_lock);
                do_each_thread(g, p) {
-                       if (frozen(p) || !freezeable(p))
+                       if (frozen(p) || !freezable(p))
                                continue;
 
                        if (!freeze_task(p, sig_only))
@@ -167,7 +167,7 @@ static void thaw_tasks(bool nosig_only)
 
        read_lock(&tasklist_lock);
        do_each_thread(g, p) {
-               if (!freezeable(p))
+               if (!freezable(p))
                        continue;
 
                if (nosig_only && should_send_signal(p))
index 0dac75e..64db648 100644 (file)
@@ -1519,11 +1519,8 @@ static int
 swsusp_alloc(struct memory_bitmap *orig_bm, struct memory_bitmap *copy_bm,
                unsigned int nr_pages, unsigned int nr_highmem)
 {
-       int error = 0;
-
        if (nr_highmem > 0) {
-               error = get_highmem_buffer(PG_ANY);
-               if (error)
+               if (get_highmem_buffer(PG_ANY))
                        goto err_out;
                if (nr_highmem > alloc_highmem) {
                        nr_highmem -= alloc_highmem;
@@ -1546,7 +1543,7 @@ swsusp_alloc(struct memory_bitmap *orig_bm, struct memory_bitmap *copy_bm,
 
  err_out:
        swsusp_free();
-       return error;
+       return -ENOMEM;
 }
 
 asmlinkage int swsusp_save(void)
index 53d9a9e..3623152 100644 (file)
@@ -97,7 +97,7 @@ static int console_locked, console_suspended;
 /*
  * logbuf_lock protects log_buf, log_start, log_end, con_start and logged_chars
  * It is also used in interesting ways to provide interlocking in
- * release_console_sem().
+ * console_unlock();.
  */
 static DEFINE_SPINLOCK(logbuf_lock);
 
@@ -262,25 +262,47 @@ int dmesg_restrict = 1;
 int dmesg_restrict;
 #endif
 
+static int syslog_action_restricted(int type)
+{
+       if (dmesg_restrict)
+               return 1;
+       /* Unless restricted, we allow "read all" and "get buffer size" for everybody */
+       return type != SYSLOG_ACTION_READ_ALL && type != SYSLOG_ACTION_SIZE_BUFFER;
+}
+
+static int check_syslog_permissions(int type, bool from_file)
+{
+       /*
+        * If this is from /proc/kmsg and we've already opened it, then we've
+        * already done the capabilities checks at open time.
+        */
+       if (from_file && type != SYSLOG_ACTION_OPEN)
+               return 0;
+
+       if (syslog_action_restricted(type)) {
+               if (capable(CAP_SYSLOG))
+                       return 0;
+               /* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */
+               if (capable(CAP_SYS_ADMIN)) {
+                       WARN_ONCE(1, "Attempt to access syslog with CAP_SYS_ADMIN "
+                                "but no CAP_SYSLOG (deprecated).\n");
+                       return 0;
+               }
+               return -EPERM;
+       }
+       return 0;
+}
+
 int do_syslog(int type, char __user *buf, int len, bool from_file)
 {
        unsigned i, j, limit, count;
        int do_clear = 0;
        char c;
-       int error = 0;
+       int error;
 
-       /*
-        * If this is from /proc/kmsg we only do the capabilities checks
-        * at open time.
-        */
-       if (type == SYSLOG_ACTION_OPEN || !from_file) {
-               if (dmesg_restrict && !capable(CAP_SYSLOG))
-                       goto warn; /* switch to return -EPERM after 2.6.39 */
-               if ((type != SYSLOG_ACTION_READ_ALL &&
-                    type != SYSLOG_ACTION_SIZE_BUFFER) &&
-                   !capable(CAP_SYSLOG))
-                       goto warn; /* switch to return -EPERM after 2.6.39 */
-       }
+       error = check_syslog_permissions(type, from_file);
+       if (error)
+               goto out;
 
        error = security_syslog(type);
        if (error)
@@ -423,12 +445,6 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
        }
 out:
        return error;
-warn:
-       /* remove after 2.6.39 */
-       if (capable(CAP_SYS_ADMIN))
-               WARN_ONCE(1, "Attempt to access syslog with CAP_SYS_ADMIN "
-                 "but no CAP_SYSLOG (deprecated and denied).\n");
-       return -EPERM;
 }
 
 SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
@@ -501,7 +517,7 @@ static void _call_console_drivers(unsigned start,
 /*
  * Call the console drivers, asking them to write out
  * log_buf[start] to log_buf[end - 1].
- * The console_sem must be held.
+ * The console_lock must be held.
  */
 static void call_console_drivers(unsigned start, unsigned end)
 {
@@ -604,11 +620,11 @@ static int have_callable_console(void)
  *
  * This is printk().  It can be called from any context.  We want it to work.
  *
- * We try to grab the console_sem.  If we succeed, it's easy - we log the output and
+ * We try to grab the console_lock.  If we succeed, it's easy - we log the output and
  * call the console drivers.  If we fail to get the semaphore we place the output
  * into the log buffer and return.  The current holder of the console_sem will
- * notice the new output in release_console_sem() and will send it to the
- * consoles before releasing the semaphore.
+ * notice the new output in console_unlock(); and will send it to the
+ * consoles before releasing the lock.
  *
  * One effect of this deferred printing is that code which calls printk() and
  * then changes console_loglevel may break. This is because console_loglevel
@@ -659,19 +675,19 @@ static inline int can_use_console(unsigned int cpu)
 /*
  * Try to get console ownership to actually show the kernel
  * messages from a 'printk'. Return true (and with the
- * console_semaphore held, and 'console_locked' set) if it
+ * console_lock held, and 'console_locked' set) if it
  * is successful, false otherwise.
  *
  * This gets called with the 'logbuf_lock' spinlock held and
  * interrupts disabled. It should return with 'lockbuf_lock'
  * released but interrupts still disabled.
  */
-static int acquire_console_semaphore_for_printk(unsigned int cpu)
+static int console_trylock_for_printk(unsigned int cpu)
        __releases(&logbuf_lock)
 {
        int retval = 0;
 
-       if (!try_acquire_console_sem()) {
+       if (console_trylock()) {
                retval = 1;
 
                /*
@@ -827,12 +843,12 @@ asmlinkage int vprintk(const char *fmt, va_list args)
         * actual magic (print out buffers, wake up klogd,
         * etc). 
         *
-        * The acquire_console_semaphore_for_printk() function
+        * The console_trylock_for_printk() function
         * will release 'logbuf_lock' regardless of whether it
         * actually gets the semaphore or not.
         */
-       if (acquire_console_semaphore_for_printk(this_cpu))
-               release_console_sem();
+       if (console_trylock_for_printk(this_cpu))
+               console_unlock();
 
        lockdep_on();
 out_restore_irqs:
@@ -993,7 +1009,7 @@ void suspend_console(void)
        if (!console_suspend_enabled)
                return;
        printk("Suspending console(s) (use no_console_suspend to debug)\n");
-       acquire_console_sem();
+       console_lock();
        console_suspended = 1;
        up(&console_sem);
 }
@@ -1004,7 +1020,7 @@ void resume_console(void)
                return;
        down(&console_sem);
        console_suspended = 0;
-       release_console_sem();
+       console_unlock();
 }
 
 /**
@@ -1027,21 +1043,21 @@ static int __cpuinit console_cpu_notify(struct notifier_block *self,
        case CPU_DYING:
        case CPU_DOWN_FAILED:
        case CPU_UP_CANCELED:
-               acquire_console_sem();
-               release_console_sem();
+               console_lock();
+               console_unlock();
        }
        return NOTIFY_OK;
 }
 
 /**
- * acquire_console_sem - lock the console system for exclusive use.
+ * console_lock - lock the console system for exclusive use.
  *
- * Acquires a semaphore which guarantees that the caller has
+ * Acquires a lock which guarantees that the caller has
  * exclusive access to the console system and the console_drivers list.
  *
  * Can sleep, returns nothing.
  */
-void acquire_console_sem(void)
+void console_lock(void)
 {
        BUG_ON(in_interrupt());
        down(&console_sem);
@@ -1050,21 +1066,29 @@ void acquire_console_sem(void)
        console_locked = 1;
        console_may_schedule = 1;
 }
-EXPORT_SYMBOL(acquire_console_sem);
+EXPORT_SYMBOL(console_lock);
 
-int try_acquire_console_sem(void)
+/**
+ * console_trylock - try to lock the console system for exclusive use.
+ *
+ * Tried to acquire a lock which guarantees that the caller has
+ * exclusive access to the console system and the console_drivers list.
+ *
+ * returns 1 on success, and 0 on failure to acquire the lock.
+ */
+int console_trylock(void)
 {
        if (down_trylock(&console_sem))
-               return -1;
+               return 0;
        if (console_suspended) {
                up(&console_sem);
-               return -1;
+               return 0;
        }
        console_locked = 1;
        console_may_schedule = 0;
-       return 0;
+       return 1;
 }
-EXPORT_SYMBOL(try_acquire_console_sem);
+EXPORT_SYMBOL(console_trylock);
 
 int is_console_locked(void)
 {
@@ -1095,20 +1119,20 @@ void wake_up_klogd(void)
 }
 
 /**
- * release_console_sem - unlock the console system
+ * console_unlock - unlock the console system
  *
- * Releases the semaphore which the caller holds on the console system
+ * Releases the console_lock which the caller holds on the console system
  * and the console driver list.
  *
- * While the semaphore was held, console output may have been buffered
- * by printk().  If this is the case, release_console_sem() emits
- * the output prior to releasing the semaphore.
+ * While the console_lock was held, console output may have been buffered
+ * by printk().  If this is the case, console_unlock(); emits
+ * the output prior to releasing the lock.
  *
  * If there is output waiting for klogd, we wake it up.
  *
- * release_console_sem() may be called from any context.
+ * console_unlock(); may be called from any context.
  */
-void release_console_sem(void)
+void console_unlock(void)
 {
        unsigned long flags;
        unsigned _con_start, _log_end;
@@ -1141,7 +1165,7 @@ void release_console_sem(void)
        if (wake_klogd)
                wake_up_klogd();
 }
-EXPORT_SYMBOL(release_console_sem);
+EXPORT_SYMBOL(console_unlock);
 
 /**
  * console_conditional_schedule - yield the CPU if required
@@ -1150,7 +1174,7 @@ EXPORT_SYMBOL(release_console_sem);
  * if this CPU should yield the CPU to another task, do
  * so here.
  *
- * Must be called within acquire_console_sem().
+ * Must be called within console_lock();.
  */
 void __sched console_conditional_schedule(void)
 {
@@ -1171,14 +1195,14 @@ void console_unblank(void)
                if (down_trylock(&console_sem) != 0)
                        return;
        } else
-               acquire_console_sem();
+               console_lock();
 
        console_locked = 1;
        console_may_schedule = 0;
        for_each_console(c)
                if ((c->flags & CON_ENABLED) && c->unblank)
                        c->unblank();
-       release_console_sem();
+       console_unlock();
 }
 
 /*
@@ -1189,7 +1213,7 @@ struct tty_driver *console_device(int *index)
        struct console *c;
        struct tty_driver *driver = NULL;
 
-       acquire_console_sem();
+       console_lock();
        for_each_console(c) {
                if (!c->device)
                        continue;
@@ -1197,7 +1221,7 @@ struct tty_driver *console_device(int *index)
                if (driver)
                        break;
        }
-       release_console_sem();
+       console_unlock();
        return driver;
 }
 
@@ -1208,17 +1232,17 @@ struct tty_driver *console_device(int *index)
  */
 void console_stop(struct console *console)
 {
-       acquire_console_sem();
+       console_lock();
        console->flags &= ~CON_ENABLED;
-       release_console_sem();
+       console_unlock();
 }
 EXPORT_SYMBOL(console_stop);
 
 void console_start(struct console *console)
 {
-       acquire_console_sem();
+       console_lock();
        console->flags |= CON_ENABLED;
-       release_console_sem();
+       console_unlock();
 }
 EXPORT_SYMBOL(console_start);
 
@@ -1340,7 +1364,7 @@ void register_console(struct console *newcon)
         *      Put this console in the list - keep the
         *      preferred driver at the head of the list.
         */
-       acquire_console_sem();
+       console_lock();
        if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) {
                newcon->next = console_drivers;
                console_drivers = newcon;
@@ -1352,14 +1376,14 @@ void register_console(struct console *newcon)
        }
        if (newcon->flags & CON_PRINTBUFFER) {
                /*
-                * release_console_sem() will print out the buffered messages
+                * console_unlock(); will print out the buffered messages
                 * for us.
                 */
                spin_lock_irqsave(&logbuf_lock, flags);
                con_start = log_start;
                spin_unlock_irqrestore(&logbuf_lock, flags);
        }
-       release_console_sem();
+       console_unlock();
        console_sysfs_notify();
 
        /*
@@ -1396,7 +1420,7 @@ int unregister_console(struct console *console)
                return braille_unregister_console(console);
 #endif
 
-       acquire_console_sem();
+       console_lock();
        if (console_drivers == console) {
                console_drivers=console->next;
                res = 0;
@@ -1418,7 +1442,7 @@ int unregister_console(struct console *console)
        if (console_drivers != NULL && console->flags & CON_CONSDEV)
                console_drivers->flags |= CON_CONSDEV;
 
-       release_console_sem();
+       console_unlock();
        console_sysfs_notify();
        return res;
 }
index 99bbaa3..e2302e4 100644 (file)
@@ -163,7 +163,7 @@ bool ptrace_may_access(struct task_struct *task, unsigned int mode)
        return !err;
 }
 
-int ptrace_attach(struct task_struct *task)
+static int ptrace_attach(struct task_struct *task)
 {
        int retval;
 
@@ -219,7 +219,7 @@ out:
  * Performs checks and sets PT_PTRACED.
  * Should be used by all ptrace implementations for PTRACE_TRACEME.
  */
-int ptrace_traceme(void)
+static int ptrace_traceme(void)
 {
        int ret = -EPERM;
 
@@ -293,7 +293,7 @@ static bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p)
        return false;
 }
 
-int ptrace_detach(struct task_struct *child, unsigned int data)
+static int ptrace_detach(struct task_struct *child, unsigned int data)
 {
        bool dead = false;
 
@@ -313,7 +313,7 @@ int ptrace_detach(struct task_struct *child, unsigned int data)
                child->exit_code = data;
                dead = __ptrace_detach(current, child);
                if (!child->exit_state)
-                       wake_up_process(child);
+                       wake_up_state(child, TASK_TRACED | TASK_STOPPED);
        }
        write_unlock_irq(&tasklist_lock);
 
index a23a57a..f3240e9 100644 (file)
@@ -214,11 +214,12 @@ 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.
                 */
-#ifndef CONFIG_PREEMPT
-               WARN_ON(1);
-               return 0;
-#else
                if (rcu_preempt_depth() != 0 || preempt_count() != 0 ||
                    irqs_disabled()) {
                        WARN_ON(1);
@@ -229,7 +230,6 @@ static int rcuhead_fixup_free(void *addr, enum debug_obj_state state)
                rcu_barrier_bh();
                debug_object_free(head, &rcuhead_debug_descr);
                return 1;
-#endif
        default:
                return 0;
        }
index 015abae..3cb8e36 100644 (file)
@@ -852,7 +852,7 @@ 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_TINY_PREEMPT_RCU */
index 89613f9..c224da4 100644 (file)
@@ -47,7 +47,6 @@
 #include <linux/srcu.h>
 #include <linux/slab.h>
 #include <asm/byteorder.h>
-#include <linux/sched.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and "
index ddabb54..3c7cbc2 100644 (file)
@@ -215,7 +215,6 @@ void debug_rt_mutex_free_waiter(struct rt_mutex_waiter *waiter)
        put_pid(waiter->deadlock_task_pid);
        TRACE_WARN_ON(!plist_node_empty(&waiter->list_entry));
        TRACE_WARN_ON(!plist_node_empty(&waiter->pi_list_entry));
-       TRACE_WARN_ON(waiter->task);
        memset(waiter, 0x22, sizeof(*waiter));
 }
 
index 66cb89b..5c9ccd3 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/kthread.h>
 #include <linux/module.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/sysdev.h>
 #include <linux/timer.h>
@@ -27,7 +26,6 @@ struct test_thread_data {
        int                     opcode;
        int                     opdata;
        int                     mutexes[MAX_RT_TEST_MUTEXES];
-       int                     bkl;
        int                     event;
        struct sys_device       sysdev;
 };
@@ -46,9 +44,8 @@ enum test_opcodes {
        RTTEST_LOCKINTNOWAIT,   /* 6 Lock interruptible no wait in wakeup, data = lockindex */
        RTTEST_LOCKCONT,        /* 7 Continue locking after the wakeup delay */
        RTTEST_UNLOCK,          /* 8 Unlock, data = lockindex */
-       RTTEST_LOCKBKL,         /* 9 Lock BKL */
-       RTTEST_UNLOCKBKL,       /* 10 Unlock BKL */
-       RTTEST_SIGNAL,          /* 11 Signal other test thread, data = thread id */
+       /* 9, 10 - reserved for BKL commemoration */
+       RTTEST_SIGNAL = 11,     /* 11 Signal other test thread, data = thread id */
        RTTEST_RESETEVENT = 98, /* 98 Reset event counter */
        RTTEST_RESET = 99,      /* 99 Reset all pending operations */
 };
@@ -74,13 +71,6 @@ static int handle_op(struct test_thread_data *td, int lockwakeup)
                                td->mutexes[i] = 0;
                        }
                }
-
-               if (!lockwakeup && td->bkl == 4) {
-#ifdef CONFIG_LOCK_KERNEL
-                       unlock_kernel();
-#endif
-                       td->bkl = 0;
-               }
                return 0;
 
        case RTTEST_RESETEVENT:
@@ -131,25 +121,6 @@ static int handle_op(struct test_thread_data *td, int lockwakeup)
                td->mutexes[id] = 0;
                return 0;
 
-       case RTTEST_LOCKBKL:
-               if (td->bkl)
-                       return 0;
-               td->bkl = 1;
-#ifdef CONFIG_LOCK_KERNEL
-               lock_kernel();
-#endif
-               td->bkl = 4;
-               return 0;
-
-       case RTTEST_UNLOCKBKL:
-               if (td->bkl != 4)
-                       break;
-#ifdef CONFIG_LOCK_KERNEL
-               unlock_kernel();
-#endif
-               td->bkl = 0;
-               return 0;
-
        default:
                break;
        }
@@ -196,7 +167,6 @@ void schedule_rt_mutex_test(struct rt_mutex *mutex)
                td->event = atomic_add_return(1, &rttest_event);
                break;
 
-       case RTTEST_LOCKBKL:
        default:
                break;
        }
@@ -229,8 +199,6 @@ void schedule_rt_mutex_test(struct rt_mutex *mutex)
                td->event = atomic_add_return(1, &rttest_event);
                return;
 
-       case RTTEST_LOCKBKL:
-               return;
        default:
                return;
        }
@@ -380,11 +348,11 @@ static ssize_t sysfs_test_status(struct sys_device *dev, struct sysdev_attribute
        spin_lock(&rttest_lock);
 
        curr += sprintf(curr,
-               "O: %4d, E:%8d, S: 0x%08lx, P: %4d, N: %4d, B: %p, K: %d, M:",
+               "O: %4d, E:%8d, S: 0x%08lx, P: %4d, N: %4d, B: %p, M:",
                td->opcode, td->event, tsk->state,
                        (MAX_RT_PRIO - 1) - tsk->prio,
                        (MAX_RT_PRIO - 1) - tsk->normal_prio,
-               tsk->pi_blocked_on, td->bkl);
+               tsk->pi_blocked_on);
 
        for (i = MAX_RT_TEST_MUTEXES - 1; i >=0 ; i--)
                curr += sprintf(curr, "%d", td->mutexes[i]);
index a960481..ab44911 100644 (file)
 /*
  * lock->owner state tracking:
  *
- * lock->owner holds the task_struct pointer of the owner. Bit 0 and 1
- * are used to keep track of the "owner is pending" and "lock has
- * waiters" state.
+ * lock->owner holds the task_struct pointer of the owner. Bit 0
+ * is used to keep track of the "lock has waiters" state.
  *
- * owner       bit1    bit0
- * NULL                0       0       lock is free (fast acquire possible)
- * NULL                0       1       invalid state
- * NULL                1       0       Transitional State*
- * NULL                1       1       invalid state
- * taskpointer 0       0       lock is held (fast release possible)
- * taskpointer 0       1       task is pending owner
- * taskpointer 1       0       lock is held and has waiters
- * taskpointer 1       1       task is pending owner and lock has more waiters
- *
- * Pending ownership is assigned to the top (highest priority)
- * waiter of the lock, when the lock is released. The thread is woken
- * up and can now take the lock. Until the lock is taken (bit 0
- * cleared) a competing higher priority thread can steal the lock
- * which puts the woken up thread back on the waiters list.
+ * owner       bit0
+ * NULL                0       lock is free (fast acquire possible)
+ * NULL                1       lock is free and has waiters and the top waiter
+ *                             is going to take the lock*
+ * taskpointer 0       lock is held (fast release possible)
+ * taskpointer 1       lock is held and has waiters**
  *
  * The fast atomic compare exchange based acquire and release is only
- * possible when bit 0 and 1 of lock->owner are 0.
+ * possible when bit 0 of lock->owner is 0.
+ *
+ * (*) It also can be a transitional state when grabbing the lock
+ * with ->wait_lock is held. To prevent any fast path cmpxchg to the lock,
+ * we need to set the bit0 before looking at the lock, and the owner may be
+ * NULL in this small time, hence this can be a transitional state.
  *
- * (*) There's a small time where the owner can be NULL and the
- * "lock has waiters" bit is set.  This can happen when grabbing the lock.
- * To prevent a cmpxchg of the owner releasing the lock, we need to set this
- * bit before looking at the lock, hence the reason this is a transitional
- * state.
+ * (**) There is a small time when bit 0 is set but there are no
+ * waiters. This can happen when grabbing the lock in the slow path.
+ * To prevent a cmpxchg of the owner releasing the lock, we need to
+ * set this bit before looking at the lock.
  */
 
 static void
-rt_mutex_set_owner(struct rt_mutex *lock, struct task_struct *owner,
-                  unsigned long mask)
+rt_mutex_set_owner(struct rt_mutex *lock, struct task_struct *owner)
 {
-       unsigned long val = (unsigned long)owner | mask;
+       unsigned long val = (unsigned long)owner;
 
        if (rt_mutex_has_waiters(lock))
                val |= RT_MUTEX_HAS_WAITERS;
@@ -203,15 +196,14 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
         * reached or the state of the chain has changed while we
         * dropped the locks.
         */
-       if (!waiter || !waiter->task)
+       if (!waiter)
                goto out_unlock_pi;
 
        /*
         * Check the orig_waiter state. After we dropped the locks,
-        * the previous owner of the lock might have released the lock
-        * and made us the pending owner:
+        * the previous owner of the lock might have released the lock.
         */
-       if (orig_waiter && !orig_waiter->task)
+       if (orig_waiter && !rt_mutex_owner(orig_lock))
                goto out_unlock_pi;
 
        /*
@@ -254,6 +246,17 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
 
        /* Release the task */
        raw_spin_unlock_irqrestore(&task->pi_lock, flags);
+       if (!rt_mutex_owner(lock)) {
+               /*
+                * If the requeue above changed the top waiter, then we need
+                * to wake the new top waiter up to try to get the lock.
+                */
+
+               if (top_waiter != rt_mutex_top_waiter(lock))
+                       wake_up_process(rt_mutex_top_waiter(lock)->task);
+               raw_spin_unlock(&lock->wait_lock);
+               goto out_put_task;
+       }
        put_task_struct(task);
 
        /* Grab the next task */
@@ -295,79 +298,17 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
        return ret;
 }
 
-/*
- * Optimization: check if we can steal the lock from the
- * assigned pending owner [which might not have taken the
- * lock yet]:
- */
-static inline int try_to_steal_lock(struct rt_mutex *lock,
-                                   struct task_struct *task)
-{
-       struct task_struct *pendowner = rt_mutex_owner(lock);
-       struct rt_mutex_waiter *next;
-       unsigned long flags;
-
-       if (!rt_mutex_owner_pending(lock))
-               return 0;
-
-       if (pendowner == task)
-               return 1;
-
-       raw_spin_lock_irqsave(&pendowner->pi_lock, flags);
-       if (task->prio >= pendowner->prio) {
-               raw_spin_unlock_irqrestore(&pendowner->pi_lock, flags);
-               return 0;
-       }
-
-       /*
-        * Check if a waiter is enqueued on the pending owners
-        * pi_waiters list. Remove it and readjust pending owners
-        * priority.
-        */
-       if (likely(!rt_mutex_has_waiters(lock))) {
-               raw_spin_unlock_irqrestore(&pendowner->pi_lock, flags);
-               return 1;
-       }
-
-       /* No chain handling, pending owner is not blocked on anything: */
-       next = rt_mutex_top_waiter(lock);
-       plist_del(&next->pi_list_entry, &pendowner->pi_waiters);
-       __rt_mutex_adjust_prio(pendowner);
-       raw_spin_unlock_irqrestore(&pendowner->pi_lock, flags);
-
-       /*
-        * We are going to steal the lock and a waiter was
-        * enqueued on the pending owners pi_waiters queue. So
-        * we have to enqueue this waiter into
-        * task->pi_waiters list. This covers the case,
-        * where task is boosted because it holds another
-        * lock and gets unboosted because the booster is
-        * interrupted, so we would delay a waiter with higher
-        * priority as task->normal_prio.
-        *
-        * Note: in the rare case of a SCHED_OTHER task changing
-        * its priority and thus stealing the lock, next->task
-        * might be task:
-        */
-       if (likely(next->task != task)) {
-               raw_spin_lock_irqsave(&task->pi_lock, flags);
-               plist_add(&next->pi_list_entry, &task->pi_waiters);
-               __rt_mutex_adjust_prio(task);
-               raw_spin_unlock_irqrestore(&task->pi_lock, flags);
-       }
-       return 1;
-}
-
 /*
  * Try to take an rt-mutex
  *
- * This fails
- * - when the lock has a real owner
- * - when a different pending owner exists and has higher priority than current
- *
  * Must be called with lock->wait_lock held.
+ *
+ * @lock:   the lock to be acquired.
+ * @task:   the task which wants to acquire the lock
+ * @waiter: the waiter that is queued to the lock's wait list. (could be NULL)
  */
-static int try_to_take_rt_mutex(struct rt_mutex *lock)
+static int try_to_take_rt_mutex(struct rt_mutex *lock, struct task_struct *task,
+               struct rt_mutex_waiter *waiter)
 {
        /*
         * We have to be careful here if the atomic speedups are
@@ -390,15 +331,52 @@ static int try_to_take_rt_mutex(struct rt_mutex *lock)
         */
        mark_rt_mutex_waiters(lock);
 
-       if (rt_mutex_owner(lock) && !try_to_steal_lock(lock, current))
+       if (rt_mutex_owner(lock))
                return 0;
 
+       /*
+        * It will get the lock because of one of these conditions:
+        * 1) there is no waiter
+        * 2) higher priority than waiters
+        * 3) it is top waiter
+        */
+       if (rt_mutex_has_waiters(lock)) {
+               if (task->prio >= rt_mutex_top_waiter(lock)->list_entry.prio) {
+                       if (!waiter || waiter != rt_mutex_top_waiter(lock))
+                               return 0;
+               }
+       }
+
+       if (waiter || rt_mutex_has_waiters(lock)) {
+               unsigned long flags;
+               struct rt_mutex_waiter *top;
+
+               raw_spin_lock_irqsave(&task->pi_lock, flags);
+
+               /* remove the queued waiter. */
+               if (waiter) {
+                       plist_del(&waiter->list_entry, &lock->wait_list);
+                       task->pi_blocked_on = NULL;
+               }
+
+               /*
+                * We have to enqueue the top waiter(if it exists) into
+                * task->pi_waiters list.
+                */
+               if (rt_mutex_has_waiters(lock)) {
+                       top = rt_mutex_top_waiter(lock);
+                       top->pi_list_entry.prio = top->list_entry.prio;
+                       plist_add(&top->pi_list_entry, &task->pi_waiters);
+               }
+               raw_spin_unlock_irqrestore(&task->pi_lock, flags);
+       }
+
        /* We got the lock. */
        debug_rt_mutex_lock(lock);
 
-       rt_mutex_set_owner(lock, current, 0);
+       rt_mutex_set_owner(lock, task);
 
-       rt_mutex_deadlock_account_lock(lock, current);
+       rt_mutex_deadlock_account_lock(lock, task);
 
        return 1;
 }
@@ -436,6 +414,9 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock,
 
        raw_spin_unlock_irqrestore(&task->pi_lock, flags);
 
+       if (!owner)
+               return 0;
+
        if (waiter == rt_mutex_top_waiter(lock)) {
                raw_spin_lock_irqsave(&owner->pi_lock, flags);
                plist_del(&top_waiter->pi_list_entry, &owner->pi_waiters);
@@ -472,21 +453,18 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock,
 /*
  * Wake up the next waiter on the lock.
  *
- * Remove the top waiter from the current tasks waiter list and from
- * the lock waiter list. Set it as pending owner. Then wake it up.
+ * Remove the top waiter from the current tasks waiter list and wake it up.
  *
  * Called with lock->wait_lock held.
  */
 static void wakeup_next_waiter(struct rt_mutex *lock)
 {
        struct rt_mutex_waiter *waiter;
-       struct task_struct *pendowner;
        unsigned long flags;
 
        raw_spin_lock_irqsave(&current->pi_lock, flags);
 
        waiter = rt_mutex_top_waiter(lock);
-       plist_del(&waiter->list_entry, &lock->wait_list);
 
        /*
         * Remove it from current->pi_waiters. We do not adjust a
@@ -495,43 +473,19 @@ static void wakeup_next_waiter(struct rt_mutex *lock)
         * lock->wait_lock.
         */
        plist_del(&waiter->pi_list_entry, &current->pi_waiters);
-       pendowner = waiter->task;
-       waiter->task = NULL;
 
-       rt_mutex_set_owner(lock, pendowner, RT_MUTEX_OWNER_PENDING);
+       rt_mutex_set_owner(lock, NULL);
 
        raw_spin_unlock_irqrestore(&current->pi_lock, flags);
 
-       /*
-        * Clear the pi_blocked_on variable and enqueue a possible
-        * waiter into the pi_waiters list of the pending owner. This
-        * prevents that in case the pending owner gets unboosted a
-        * waiter with higher priority than pending-owner->normal_prio
-        * is blocked on the unboosted (pending) owner.
-        */
-       raw_spin_lock_irqsave(&pendowner->pi_lock, flags);
-
-       WARN_ON(!pendowner->pi_blocked_on);
-       WARN_ON(pendowner->pi_blocked_on != waiter);
-       WARN_ON(pendowner->pi_blocked_on->lock != lock);
-
-       pendowner->pi_blocked_on = NULL;
-
-       if (rt_mutex_has_waiters(lock)) {
-               struct rt_mutex_waiter *next;
-
-               next = rt_mutex_top_waiter(lock);
-               plist_add(&next->pi_list_entry, &pendowner->pi_waiters);
-       }
-       raw_spin_unlock_irqrestore(&pendowner->pi_lock, flags);
-
-       wake_up_process(pendowner);
+       wake_up_process(waiter->task);
 }
 
 /*
- * Remove a waiter from a lock
+ * Remove a waiter from a lock and give up
  *
- * Must be called with lock->wait_lock held
+ * Must be called with lock->wait_lock held and
+ * have just failed to try_to_take_rt_mutex().
  */
 static void remove_waiter(struct rt_mutex *lock,
                          struct rt_mutex_waiter *waiter)
@@ -543,11 +497,13 @@ static void remove_waiter(struct rt_mutex *lock,
 
        raw_spin_lock_irqsave(&current->pi_lock, flags);
        plist_del(&waiter->list_entry, &lock->wait_list);
-       waiter->task = NULL;
        current->pi_blocked_on = NULL;
        raw_spin_unlock_irqrestore(&current->pi_lock, flags);
 
-       if (first && owner != current) {
+       if (!owner)
+               return;
+
+       if (first) {
 
                raw_spin_lock_irqsave(&owner->pi_lock, flags);
 
@@ -614,21 +570,19 @@ void rt_mutex_adjust_pi(struct task_struct *task)
  *                      or TASK_UNINTERRUPTIBLE)
  * @timeout:            the pre-initialized and started timer, or NULL for none
  * @waiter:             the pre-initialized rt_mutex_waiter
- * @detect_deadlock:    passed to task_blocks_on_rt_mutex
  *
  * lock->wait_lock must be held by the caller.
  */
 static int __sched
 __rt_mutex_slowlock(struct rt_mutex *lock, int state,
                    struct hrtimer_sleeper *timeout,
-                   struct rt_mutex_waiter *waiter,
-                   int detect_deadlock)
+                   struct rt_mutex_waiter *waiter)
 {
        int ret = 0;
 
        for (;;) {
                /* Try to acquire the lock: */
-               if (try_to_take_rt_mutex(lock))
+               if (try_to_take_rt_mutex(lock, current, waiter))
                        break;
 
                /*
@@ -645,39 +599,11 @@ __rt_mutex_slowlock(struct rt_mutex *lock, int state,
                                break;
                }
 
-               /*
-                * waiter->task is NULL the first time we come here and
-                * when we have been woken up by the previous owner
-                * but the lock got stolen by a higher prio task.
-                */
-               if (!waiter->task) {
-                       ret = task_blocks_on_rt_mutex(lock, waiter, current,
-                                                     detect_deadlock);
-                       /*
-                        * If we got woken up by the owner then start loop
-                        * all over without going into schedule to try
-                        * to get the lock now:
-                        */
-                       if (unlikely(!waiter->task)) {
-                               /*
-                                * Reset the return value. We might
-                                * have returned with -EDEADLK and the
-                                * owner released the lock while we
-                                * were walking the pi chain.
-                                */
-                               ret = 0;
-                               continue;
-                       }
-                       if (unlikely(ret))
-                               break;
-               }
-
                raw_spin_unlock(&lock->wait_lock);
 
                debug_rt_mutex_print_deadlock(waiter);
 
-               if (waiter->task)
-                       schedule_rt_mutex(lock);
+               schedule_rt_mutex(lock);
 
                raw_spin_lock(&lock->wait_lock);
                set_current_state(state);
@@ -698,12 +624,11 @@ rt_mutex_slowlock(struct rt_mutex *lock, int state,
        int ret = 0;
 
        debug_rt_mutex_init_waiter(&waiter);
-       waiter.task = NULL;
 
        raw_spin_lock(&lock->wait_lock);
 
        /* Try to acquire the lock again: */
-       if (try_to_take_rt_mutex(lock)) {
+       if (try_to_take_rt_mutex(lock, current, NULL)) {
                raw_spin_unlock(&lock->wait_lock);
                return 0;
        }
@@ -717,12 +642,14 @@ rt_mutex_slowlock(struct rt_mutex *lock, int state,
                        timeout->task = NULL;
        }
 
-       ret = __rt_mutex_slowlock(lock, state, timeout, &waiter,
-                                 detect_deadlock);
+       ret = task_blocks_on_rt_mutex(lock, &waiter, current, detect_deadlock);
+
+       if (likely(!ret))
+               ret = __rt_mutex_slowlock(lock, state, timeout, &waiter);
 
        set_current_state(TASK_RUNNING);
 
-       if (unlikely(waiter.task))
+       if (unlikely(ret))
                remove_waiter(lock, &waiter);
 
        /*
@@ -737,14 +664,6 @@ rt_mutex_slowlock(struct rt_mutex *lock, int state,
        if (unlikely(timeout))
                hrtimer_cancel(&timeout->timer);
 
-       /*
-        * Readjust priority, when we did not get the lock. We might
-        * have been the pending owner and boosted. Since we did not
-        * take the lock, the PI boost has to go.
-        */
-       if (unlikely(ret))
-               rt_mutex_adjust_prio(current);
-
        debug_rt_mutex_free_waiter(&waiter);
 
        return ret;
@@ -762,7 +681,7 @@ rt_mutex_slowtrylock(struct rt_mutex *lock)
 
        if (likely(rt_mutex_owner(lock) != current)) {
 
-               ret = try_to_take_rt_mutex(lock);
+               ret = try_to_take_rt_mutex(lock, current, NULL);
                /*
                 * try_to_take_rt_mutex() sets the lock waiters
                 * bit unconditionally. Clean this up.
@@ -992,7 +911,7 @@ void rt_mutex_init_proxy_locked(struct rt_mutex *lock,
 {
        __rt_mutex_init(lock, NULL);
        debug_rt_mutex_proxy_lock(lock, proxy_owner);
-       rt_mutex_set_owner(lock, proxy_owner, 0);
+       rt_mutex_set_owner(lock, proxy_owner);
        rt_mutex_deadlock_account_lock(lock, proxy_owner);
 }
 
@@ -1008,7 +927,7 @@ void rt_mutex_proxy_unlock(struct rt_mutex *lock,
                           struct task_struct *proxy_owner)
 {
        debug_rt_mutex_proxy_unlock(lock);
-       rt_mutex_set_owner(lock, NULL, 0);
+       rt_mutex_set_owner(lock, NULL);
        rt_mutex_deadlock_account_unlock(proxy_owner);
 }
 
@@ -1034,20 +953,14 @@ int rt_mutex_start_proxy_lock(struct rt_mutex *lock,
 
        raw_spin_lock(&lock->wait_lock);
 
-       mark_rt_mutex_waiters(lock);
-
-       if (!rt_mutex_owner(lock) || try_to_steal_lock(lock, task)) {
-               /* We got the lock for task. */
-               debug_rt_mutex_lock(lock);
-               rt_mutex_set_owner(lock, task, 0);
+       if (try_to_take_rt_mutex(lock, task, NULL)) {
                raw_spin_unlock(&lock->wait_lock);
-               rt_mutex_deadlock_account_lock(lock, task);
                return 1;
        }
 
        ret = task_blocks_on_rt_mutex(lock, waiter, task, detect_deadlock);
 
-       if (ret && !waiter->task) {
+       if (ret && !rt_mutex_owner(lock)) {
                /*
                 * Reset the return value. We might have
                 * returned with -EDEADLK and the owner
@@ -1056,6 +969,10 @@ int rt_mutex_start_proxy_lock(struct rt_mutex *lock,
                 */
                ret = 0;
        }
+
+       if (unlikely(ret))
+               remove_waiter(lock, waiter);
+
        raw_spin_unlock(&lock->wait_lock);
 
        debug_rt_mutex_print_deadlock(waiter);
@@ -1110,12 +1027,11 @@ int rt_mutex_finish_proxy_lock(struct rt_mutex *lock,
 
        set_current_state(TASK_INTERRUPTIBLE);
 
-       ret = __rt_mutex_slowlock(lock, TASK_INTERRUPTIBLE, to, waiter,
-                                 detect_deadlock);
+       ret = __rt_mutex_slowlock(lock, TASK_INTERRUPTIBLE, to, waiter);
 
        set_current_state(TASK_RUNNING);
 
-       if (unlikely(waiter->task))
+       if (unlikely(ret))
                remove_waiter(lock, waiter);
 
        /*
@@ -1126,13 +1042,5 @@ int rt_mutex_finish_proxy_lock(struct rt_mutex *lock,
 
        raw_spin_unlock(&lock->wait_lock);
 
-       /*
-        * Readjust priority, when we did not get the lock. We might have been
-        * the pending owner and boosted. Since we did not take the lock, the
-        * PI boost has to go.
-        */
-       if (unlikely(ret))
-               rt_mutex_adjust_prio(current);
-
        return ret;
 }
index 97a2f81..53a66c8 100644 (file)
@@ -91,9 +91,8 @@ task_top_pi_waiter(struct task_struct *p)
 /*
  * lock->owner state tracking:
  */
-#define RT_MUTEX_OWNER_PENDING 1UL
-#define RT_MUTEX_HAS_WAITERS   2UL
-#define RT_MUTEX_OWNER_MASKALL 3UL
+#define RT_MUTEX_HAS_WAITERS   1UL
+#define RT_MUTEX_OWNER_MASKALL 1UL
 
 static inline struct task_struct *rt_mutex_owner(struct rt_mutex *lock)
 {
@@ -101,17 +100,6 @@ static inline struct task_struct *rt_mutex_owner(struct rt_mutex *lock)
                ((unsigned long)lock->owner & ~RT_MUTEX_OWNER_MASKALL);
 }
 
-static inline struct task_struct *rt_mutex_real_owner(struct rt_mutex *lock)
-{
-       return (struct task_struct *)
-               ((unsigned long)lock->owner & ~RT_MUTEX_HAS_WAITERS);
-}
-
-static inline unsigned long rt_mutex_owner_pending(struct rt_mutex *lock)
-{
-       return (unsigned long)lock->owner & RT_MUTEX_OWNER_PENDING;
-}
-
 /*
  * PI-futex support (proxy locking functions, etc.):
  */
index 18d38e4..c8e40b7 100644 (file)
@@ -324,7 +324,7 @@ struct cfs_rq {
         * 'curr' points to currently running entity on this cfs_rq.
         * It is set to NULL otherwise (i.e when none are currently running).
         */
-       struct sched_entity *curr, *next, *last;
+       struct sched_entity *curr, *next, *last, *skip;
 
        unsigned int nr_spread_over;
 
@@ -606,9 +606,6 @@ static inline struct task_group *task_group(struct task_struct *p)
        struct task_group *tg;
        struct cgroup_subsys_state *css;
 
-       if (p->flags & PF_EXITING)
-               return &root_task_group;
-
        css = task_subsys_state_check(p, cpu_cgroup_subsys_id,
                        lockdep_is_held(&task_rq(p)->lock));
        tg = container_of(css, struct task_group, css);
@@ -1686,6 +1683,39 @@ static void double_rq_unlock(struct rq *rq1, struct rq *rq2)
                __release(rq2->lock);
 }
 
+#else /* CONFIG_SMP */
+
+/*
+ * double_rq_lock - safely lock two runqueues
+ *
+ * Note this does not disable interrupts like task_rq_lock,
+ * you need to do so manually before calling.
+ */
+static void double_rq_lock(struct rq *rq1, struct rq *rq2)
+       __acquires(rq1->lock)
+       __acquires(rq2->lock)
+{
+       BUG_ON(!irqs_disabled());
+       BUG_ON(rq1 != rq2);
+       raw_spin_lock(&rq1->lock);
+       __acquire(rq2->lock);   /* Fake it out ;) */
+}
+
+/*
+ * double_rq_unlock - safely unlock two runqueues
+ *
+ * Note this does not restore interrupts like task_rq_unlock,
+ * you need to do so manually after calling.
+ */
+static void double_rq_unlock(struct rq *rq1, struct rq *rq2)
+       __releases(rq1->lock)
+       __releases(rq2->lock)
+{
+       BUG_ON(rq1 != rq2);
+       raw_spin_unlock(&rq1->lock);
+       __release(rq2->lock);
+}
+
 #endif
 
 static void calc_load_account_idle(struct rq *this_rq);
@@ -1880,7 +1910,7 @@ void account_system_vtime(struct task_struct *curr)
         */
        if (hardirq_count())
                __this_cpu_add(cpu_hardirq_time, delta);
-       else if (in_serving_softirq() && !(curr->flags & PF_KSOFTIRQD))
+       else if (in_serving_softirq() && curr != this_cpu_ksoftirqd())
                __this_cpu_add(cpu_softirq_time, delta);
 
        irq_time_write_end();
@@ -1920,8 +1950,40 @@ static void update_rq_clock_task(struct rq *rq, s64 delta)
                sched_rt_avg_update(rq, irq_delta);
 }
 
+static int irqtime_account_hi_update(void)
+{
+       struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat;
+       unsigned long flags;
+       u64 latest_ns;
+       int ret = 0;
+
+       local_irq_save(flags);
+       latest_ns = this_cpu_read(cpu_hardirq_time);
+       if (cputime64_gt(nsecs_to_cputime64(latest_ns), cpustat->irq))
+               ret = 1;
+       local_irq_restore(flags);
+       return ret;
+}
+
+static int irqtime_account_si_update(void)
+{
+       struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat;
+       unsigned long flags;
+       u64 latest_ns;
+       int ret = 0;
+
+       local_irq_save(flags);
+       latest_ns = this_cpu_read(cpu_softirq_time);
+       if (cputime64_gt(nsecs_to_cputime64(latest_ns), cpustat->softirq))
+               ret = 1;
+       local_irq_restore(flags);
+       return ret;
+}
+
 #else /* CONFIG_IRQ_TIME_ACCOUNTING */
 
+#define sched_clock_irqtime    (0)
+
 static void update_rq_clock_task(struct rq *rq, s64 delta)
 {
        rq->clock_task += delta;
@@ -2025,14 +2087,14 @@ inline int task_curr(const struct task_struct *p)
 
 static inline void check_class_changed(struct rq *rq, struct task_struct *p,
                                       const struct sched_class *prev_class,
-                                      int oldprio, int running)
+                                      int oldprio)
 {
        if (prev_class != p->sched_class) {
                if (prev_class->switched_from)
-                       prev_class->switched_from(rq, p, running);
-               p->sched_class->switched_to(rq, p, running);
-       } else
-               p->sched_class->prio_changed(rq, p, oldprio, running);
+                       prev_class->switched_from(rq, p);
+               p->sched_class->switched_to(rq, p);
+       } else if (oldprio != p->prio)
+               p->sched_class->prio_changed(rq, p, oldprio);
 }
 
 static void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags)
@@ -2224,7 +2286,10 @@ unsigned long wait_task_inactive(struct task_struct *p, long match_state)
                 * yield - it could be a while.
                 */
                if (unlikely(on_rq)) {
-                       schedule_timeout_uninterruptible(1);
+                       ktime_t to = ktime_set(0, NSEC_PER_SEC/HZ);
+
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       schedule_hrtimeout(&to, HRTIMER_MODE_REL);
                        continue;
                }
 
@@ -2265,27 +2330,6 @@ void kick_process(struct task_struct *p)
 EXPORT_SYMBOL_GPL(kick_process);
 #endif /* CONFIG_SMP */
 
-/**
- * task_oncpu_function_call - call a function on the cpu on which a task runs
- * @p:         the task to evaluate
- * @func:      the function to be called
- * @info:      the function call argument
- *
- * Calls the function @func when the task is currently running. This might
- * be on the current CPU, which just calls the function directly
- */
-void task_oncpu_function_call(struct task_struct *p,
-                             void (*func) (void *info), void *info)
-{
-       int cpu;
-
-       preempt_disable();
-       cpu = task_cpu(p);
-       if (task_curr(p))
-               smp_call_function_single(cpu, func, info, 1);
-       preempt_enable();
-}
-
 #ifdef CONFIG_SMP
 /*
  * ->cpus_allowed is protected by either TASK_WAKING or rq->lock held.
@@ -2566,6 +2610,7 @@ static void __sched_fork(struct task_struct *p)
        p->se.sum_exec_runtime          = 0;
        p->se.prev_sum_exec_runtime     = 0;
        p->se.nr_migrations             = 0;
+       p->se.vruntime                  = 0;
 
 #ifdef CONFIG_SCHEDSTATS
        memset(&p->se.statistics, 0, sizeof(p->se.statistics));
@@ -2776,9 +2821,12 @@ static inline void
 prepare_task_switch(struct rq *rq, struct task_struct *prev,
                    struct task_struct *next)
 {
+       sched_info_switch(prev, next);
+       perf_event_task_sched_out(prev, next);
        fire_sched_out_preempt_notifiers(prev, next);
        prepare_lock_switch(rq, next);
        prepare_arch_switch(next);
+       trace_sched_switch(prev, next);
 }
 
 /**
@@ -2911,7 +2959,7 @@ context_switch(struct rq *rq, struct task_struct *prev,
        struct mm_struct *mm, *oldmm;
 
        prepare_task_switch(rq, prev, next);
-       trace_sched_switch(prev, next);
+
        mm = next->mm;
        oldmm = prev->active_mm;
        /*
@@ -3567,6 +3615,32 @@ static void account_guest_time(struct task_struct *p, cputime_t cputime,
        }
 }
 
+/*
+ * Account system cpu time to a process and desired cpustat field
+ * @p: the process that the cpu time gets accounted to
+ * @cputime: the cpu time spent in kernel space since the last update
+ * @cputime_scaled: cputime scaled by cpu frequency
+ * @target_cputime64: pointer to cpustat field that has to be updated
+ */
+static inline
+void __account_system_time(struct task_struct *p, cputime_t cputime,
+                       cputime_t cputime_scaled, cputime64_t *target_cputime64)
+{
+       cputime64_t tmp = cputime_to_cputime64(cputime);
+
+       /* Add system time to process. */
+       p->stime = cputime_add(p->stime, cputime);
+       p->stimescaled = cputime_add(p->stimescaled, cputime_scaled);
+       account_group_system_time(p, cputime);
+
+       /* Add system time to cpustat. */
+       *target_cputime64 = cputime64_add(*target_cputime64, tmp);
+       cpuacct_update_stats(p, CPUACCT_STAT_SYSTEM, cputime);
+
+       /* Account for system time used */
+       acct_update_integrals(p);
+}
+
 /*
  * Account system cpu time to a process.
  * @p: the process that the cpu time gets accounted to
@@ -3578,36 +3652,26 @@ void account_system_time(struct task_struct *p, int hardirq_offset,
                         cputime_t cputime, cputime_t cputime_scaled)
 {
        struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat;
-       cputime64_t tmp;
+       cputime64_t *target_cputime64;
 
        if ((p->flags & PF_VCPU) && (irq_count() - hardirq_offset == 0)) {
                account_guest_time(p, cputime, cputime_scaled);
                return;
        }
 
-       /* Add system time to process. */
-       p->stime = cputime_add(p->stime, cputime);
-       p->stimescaled = cputime_add(p->stimescaled, cputime_scaled);
-       account_group_system_time(p, cputime);
-
-       /* Add system time to cpustat. */
-       tmp = cputime_to_cputime64(cputime);
        if (hardirq_count() - hardirq_offset)
-               cpustat->irq = cputime64_add(cpustat->irq, tmp);
+               target_cputime64 = &cpustat->irq;
        else if (in_serving_softirq())
-               cpustat->softirq = cputime64_add(cpustat->softirq, tmp);
+               target_cputime64 = &cpustat->softirq;
        else
-               cpustat->system = cputime64_add(cpustat->system, tmp);
+               target_cputime64 = &cpustat->system;
 
-       cpuacct_update_stats(p, CPUACCT_STAT_SYSTEM, cputime);
-
-       /* Account for system time used */
-       acct_update_integrals(p);
+       __account_system_time(p, cputime, cputime_scaled, target_cputime64);
 }
 
 /*
  * Account for involuntary wait time.
- * @steal: the cpu time spent in involuntary wait
+ * @cputime: the cpu time spent in involuntary wait
  */
 void account_steal_time(cputime_t cputime)
 {
@@ -3635,6 +3699,73 @@ void account_idle_time(cputime_t cputime)
 
 #ifndef CONFIG_VIRT_CPU_ACCOUNTING
 
+#ifdef CONFIG_IRQ_TIME_ACCOUNTING
+/*
+ * Account a tick to a process and cpustat
+ * @p: the process that the cpu time gets accounted to
+ * @user_tick: is the tick from userspace
+ * @rq: the pointer to rq
+ *
+ * Tick demultiplexing follows the order
+ * - pending hardirq update
+ * - pending softirq update
+ * - user_time
+ * - idle_time
+ * - system time
+ *   - check for guest_time
+ *   - else account as system_time
+ *
+ * Check for hardirq is done both for system and user time as there is
+ * no timer going off while we are on hardirq and hence we may never get an
+ * opportunity to update it solely in system time.
+ * p->stime and friends are only updated on system time and not on irq
+ * softirq as those do not count in task exec_runtime any more.
+ */
+static void irqtime_account_process_tick(struct task_struct *p, int user_tick,
+                                               struct rq *rq)
+{
+       cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy);
+       cputime64_t tmp = cputime_to_cputime64(cputime_one_jiffy);
+       struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat;
+
+       if (irqtime_account_hi_update()) {
+               cpustat->irq = cputime64_add(cpustat->irq, tmp);
+       } else if (irqtime_account_si_update()) {
+               cpustat->softirq = cputime64_add(cpustat->softirq, tmp);
+       } else if (this_cpu_ksoftirqd() == p) {
+               /*
+                * ksoftirqd time do not get accounted in cpu_softirq_time.
+                * So, we have to handle it separately here.
+                * Also, p->stime needs to be updated for ksoftirqd.
+                */
+               __account_system_time(p, cputime_one_jiffy, one_jiffy_scaled,
+                                       &cpustat->softirq);
+       } else if (user_tick) {
+               account_user_time(p, cputime_one_jiffy, one_jiffy_scaled);
+       } else if (p == rq->idle) {
+               account_idle_time(cputime_one_jiffy);
+       } else if (p->flags & PF_VCPU) { /* System time or guest time */
+               account_guest_time(p, cputime_one_jiffy, one_jiffy_scaled);
+       } else {
+               __account_system_time(p, cputime_one_jiffy, one_jiffy_scaled,
+                                       &cpustat->system);
+       }
+}
+
+static void irqtime_account_idle_ticks(int ticks)
+{
+       int i;
+       struct rq *rq = this_rq();
+
+       for (i = 0; i < ticks; i++)
+               irqtime_account_process_tick(current, 0, rq);
+}
+#else /* CONFIG_IRQ_TIME_ACCOUNTING */
+static void irqtime_account_idle_ticks(int ticks) {}
+static void irqtime_account_process_tick(struct task_struct *p, int user_tick,
+                                               struct rq *rq) {}
+#endif /* CONFIG_IRQ_TIME_ACCOUNTING */
+
 /*
  * Account a single tick of cpu time.
  * @p: the process that the cpu time gets accounted to
@@ -3645,6 +3776,11 @@ void account_process_tick(struct task_struct *p, int user_tick)
        cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy);
        struct rq *rq = this_rq();
 
+       if (sched_clock_irqtime) {
+               irqtime_account_process_tick(p, user_tick, rq);
+               return;
+       }
+
        if (user_tick)
                account_user_time(p, cputime_one_jiffy, one_jiffy_scaled);
        else if ((p != rq->idle) || (irq_count() != HARDIRQ_OFFSET))
@@ -3670,6 +3806,12 @@ void account_steal_ticks(unsigned long ticks)
  */
 void account_idle_ticks(unsigned long ticks)
 {
+
+       if (sched_clock_irqtime) {
+               irqtime_account_idle_ticks(ticks);
+               return;
+       }
+
        account_idle_time(jiffies_to_cputime(ticks));
 }
 
@@ -3989,9 +4131,6 @@ need_resched_nonpreemptible:
        rq->skip_clock_update = 0;
 
        if (likely(prev != next)) {
-               sched_info_switch(prev, next);
-               perf_event_task_sched_out(prev, next);
-
                rq->nr_switches++;
                rq->curr = next;
                ++*switch_count;
@@ -4213,6 +4352,7 @@ void __wake_up_locked_key(wait_queue_head_t *q, unsigned int mode, void *key)
 {
        __wake_up_common(q, mode, 1, 0, key);
 }
+EXPORT_SYMBOL_GPL(__wake_up_locked_key);
 
 /**
  * __wake_up_sync_key - wake up threads blocked on a waitqueue.
@@ -4570,11 +4710,10 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
 
        if (running)
                p->sched_class->set_curr_task(rq);
-       if (on_rq) {
+       if (on_rq)
                enqueue_task(rq, p, oldprio < prio ? ENQUEUE_HEAD : 0);
 
-               check_class_changed(rq, p, prev_class, oldprio, running);
-       }
+       check_class_changed(rq, p, prev_class, oldprio);
        task_rq_unlock(rq, &flags);
 }
 
@@ -4822,12 +4961,15 @@ recheck:
                            param->sched_priority > rlim_rtprio)
                                return -EPERM;
                }
+
                /*
-                * Like positive nice levels, dont allow tasks to
-                * move out of SCHED_IDLE either:
+                * Treat SCHED_IDLE as nice 20. Only allow a switch to
+                * SCHED_NORMAL if the RLIMIT_NICE would normally permit it.
                 */
-               if (p->policy == SCHED_IDLE && policy != SCHED_IDLE)
-                       return -EPERM;
+               if (p->policy == SCHED_IDLE && policy != SCHED_IDLE) {
+                       if (!can_nice(p, TASK_NICE(p)))
+                               return -EPERM;
+               }
 
                /* can't change other user's priorities */
                if (!check_same_owner(p))
@@ -4902,11 +5044,10 @@ recheck:
 
        if (running)
                p->sched_class->set_curr_task(rq);
-       if (on_rq) {
+       if (on_rq)
                activate_task(rq, p, 0);
 
-               check_class_changed(rq, p, prev_class, oldprio, running);
-       }
+       check_class_changed(rq, p, prev_class, oldprio);
        __task_rq_unlock(rq);
        raw_spin_unlock_irqrestore(&p->pi_lock, flags);
 
@@ -5323,6 +5464,65 @@ void __sched yield(void)
 }
 EXPORT_SYMBOL(yield);
 
+/**
+ * yield_to - yield the current processor to another thread in
+ * your thread group, or accelerate that thread toward the
+ * processor it's on.
+ *
+ * It's the caller's job to ensure that the target task struct
+ * can't go away on us before we can do any checks.
+ *
+ * Returns true if we indeed boosted the target task.
+ */
+bool __sched yield_to(struct task_struct *p, bool preempt)
+{
+       struct task_struct *curr = current;
+       struct rq *rq, *p_rq;
+       unsigned long flags;
+       bool yielded = 0;
+
+       local_irq_save(flags);
+       rq = this_rq();
+
+again:
+       p_rq = task_rq(p);
+       double_rq_lock(rq, p_rq);
+       while (task_rq(p) != p_rq) {
+               double_rq_unlock(rq, p_rq);
+               goto again;
+       }
+
+       if (!curr->sched_class->yield_to_task)
+               goto out;
+
+       if (curr->sched_class != p->sched_class)
+               goto out;
+
+       if (task_running(p_rq, p) || p->state)
+               goto out;
+
+       yielded = curr->sched_class->yield_to_task(rq, p, preempt);
+       if (yielded) {
+               schedstat_inc(rq, yld_count);
+               /*
+                * Make p's CPU reschedule; pick_next_entity takes care of
+                * fairness.
+                */
+               if (preempt && rq != p_rq)
+                       resched_task(p_rq->curr);
+       }
+
+out:
+       double_rq_unlock(rq, p_rq);
+       local_irq_restore(flags);
+
+       if (yielded)
+               schedule();
+
+       return yielded;
+}
+EXPORT_SYMBOL_GPL(yield_to);
+
 /*
  * This task is about to go to sleep on IO. Increment rq->nr_iowait so
  * that process accounting knows that this is a task in IO wait state.
@@ -5571,7 +5771,7 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu)
         * The idle tasks have their own, simple scheduling class:
         */
        idle->sched_class = &idle_sched_class;
-       ftrace_graph_init_task(idle);
+       ftrace_graph_init_idle_task(idle, cpu);
 }
 
 /*
@@ -7796,6 +7996,10 @@ static void init_cfs_rq(struct cfs_rq *cfs_rq, struct rq *rq)
        INIT_LIST_HEAD(&cfs_rq->tasks);
 #ifdef CONFIG_FAIR_GROUP_SCHED
        cfs_rq->rq = rq;
+       /* allow initial update_cfs_load() to truncate */
+#ifdef CONFIG_SMP
+       cfs_rq->load_stamp = 1;
+#endif
 #endif
        cfs_rq->min_vruntime = (u64)(-(1LL << 20));
 }
@@ -8109,6 +8313,8 @@ EXPORT_SYMBOL(__might_sleep);
 #ifdef CONFIG_MAGIC_SYSRQ
 static void normalize_task(struct rq *rq, struct task_struct *p)
 {
+       const struct sched_class *prev_class = p->sched_class;
+       int old_prio = p->prio;
        int on_rq;
 
        on_rq = p->se.on_rq;
@@ -8119,6 +8325,8 @@ static void normalize_task(struct rq *rq, struct task_struct *p)
                activate_task(rq, p, 0);
                resched_task(rq->curr);
        }
+
+       check_class_changed(rq, p, prev_class, old_prio);
 }
 
 void normalize_rt_tasks(void)
@@ -8510,7 +8718,7 @@ int sched_group_set_shares(struct task_group *tg, unsigned long shares)
                /* Propagate contribution to hierarchy */
                raw_spin_lock_irqsave(&rq->lock, flags);
                for_each_sched_entity(se)
-                       update_cfs_shares(group_cfs_rq(se), 0);
+                       update_cfs_shares(group_cfs_rq(se));
                raw_spin_unlock_irqrestore(&rq->lock, flags);
        }
 
@@ -8884,7 +9092,8 @@ cpu_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
 }
 
 static void
-cpu_cgroup_exit(struct cgroup_subsys *ss, struct task_struct *task)
+cpu_cgroup_exit(struct cgroup_subsys *ss, struct cgroup *cgrp,
+               struct cgroup *old_cgrp, struct task_struct *task)
 {
        /*
         * cgroup_exit() is called in the copy_process() failure path.
index 9fb6562..5946ac5 100644 (file)
@@ -12,7 +12,6 @@ static atomic_t autogroup_seq_nr;
 static void __init autogroup_init(struct task_struct *init_task)
 {
        autogroup_default.tg = &root_task_group;
-       root_task_group.autogroup = &autogroup_default;
        kref_init(&autogroup_default.kref);
        init_rwsem(&autogroup_default.lock);
        init_task->signal->autogroup = &autogroup_default;
@@ -130,7 +129,7 @@ task_wants_autogroup(struct task_struct *p, struct task_group *tg)
 
 static inline bool task_group_is_autogroup(struct task_group *tg)
 {
-       return tg != &root_task_group && tg->autogroup;
+       return !!tg->autogroup;
 }
 
 static inline struct task_group *
@@ -161,11 +160,15 @@ autogroup_move_group(struct task_struct *p, struct autogroup *ag)
 
        p->signal->autogroup = autogroup_kref_get(ag);
 
+       if (!ACCESS_ONCE(sysctl_sched_autogroup_enabled))
+               goto out;
+
        t = p;
        do {
                sched_move_task(t);
        } while_each_thread(p, t);
 
+out:
        unlock_task_sighand(p, &flags);
        autogroup_kref_put(prev);
 }
@@ -247,10 +250,14 @@ void proc_sched_autogroup_show_task(struct task_struct *p, struct seq_file *m)
 {
        struct autogroup *ag = autogroup_task_get(p);
 
+       if (!task_group_is_autogroup(ag->tg))
+               goto out;
+
        down_read(&ag->lock);
        seq_printf(m, "/autogroup-%ld nice %d\n", ag->id, ag->nice);
        up_read(&ag->lock);
 
+out:
        autogroup_kref_put(ag);
 }
 #endif /* CONFIG_PROC_FS */
@@ -258,9 +265,7 @@ void proc_sched_autogroup_show_task(struct task_struct *p, struct seq_file *m)
 #ifdef CONFIG_SCHED_DEBUG
 static inline int autogroup_path(struct task_group *tg, char *buf, int buflen)
 {
-       int enabled = ACCESS_ONCE(sysctl_sched_autogroup_enabled);
-
-       if (!enabled || !tg->autogroup)
+       if (!task_group_is_autogroup(tg))
                return 0;
 
        return snprintf(buf, buflen, "%s-%ld", "/autogroup", tg->autogroup->id);
index 7b859ff..0557705 100644 (file)
@@ -1,6 +1,11 @@
 #ifdef CONFIG_SCHED_AUTOGROUP
 
 struct autogroup {
+       /*
+        * reference doesn't mean how many thread attach to this
+        * autogroup now. It just stands for the number of task
+        * could use this autogroup.
+        */
        struct kref             kref;
        struct task_group       *tg;
        struct rw_semaphore     lock;
index eb6cb8e..7bacd83 100644 (file)
@@ -179,7 +179,7 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
 
        raw_spin_lock_irqsave(&rq->lock, flags);
        if (cfs_rq->rb_leftmost)
-               MIN_vruntime = (__pick_next_entity(cfs_rq))->vruntime;
+               MIN_vruntime = (__pick_first_entity(cfs_rq))->vruntime;
        last = __pick_last_entity(cfs_rq);
        if (last)
                max_vruntime = last->vruntime;
index 3547699..3f7ec9e 100644 (file)
@@ -68,14 +68,6 @@ static unsigned int sched_nr_latency = 8;
  */
 unsigned int sysctl_sched_child_runs_first __read_mostly;
 
-/*
- * sys_sched_yield() compat mode
- *
- * This option switches the agressive yield implementation of the
- * old scheduler back on.
- */
-unsigned int __read_mostly sysctl_sched_compat_yield;
-
 /*
  * SCHED_OTHER wake-up granularity.
  * (default: 1 msec * (1 + ilog(ncpus)), units: nanoseconds)
@@ -419,7 +411,7 @@ static void __dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
        rb_erase(&se->run_node, &cfs_rq->tasks_timeline);
 }
 
-static struct sched_entity *__pick_next_entity(struct cfs_rq *cfs_rq)
+static struct sched_entity *__pick_first_entity(struct cfs_rq *cfs_rq)
 {
        struct rb_node *left = cfs_rq->rb_leftmost;
 
@@ -429,6 +421,17 @@ static struct sched_entity *__pick_next_entity(struct cfs_rq *cfs_rq)
        return rb_entry(left, struct sched_entity, run_node);
 }
 
+static struct sched_entity *__pick_next_entity(struct sched_entity *se)
+{
+       struct rb_node *next = rb_next(&se->run_node);
+
+       if (!next)
+               return NULL;
+
+       return rb_entry(next, struct sched_entity, run_node);
+}
+
+#ifdef CONFIG_SCHED_DEBUG
 static struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq)
 {
        struct rb_node *last = rb_last(&cfs_rq->tasks_timeline);
@@ -443,7 +446,6 @@ static struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq)
  * Scheduling class statistics methods:
  */
 
-#ifdef CONFIG_SCHED_DEBUG
 int sched_proc_update_handler(struct ctl_table *table, int write,
                void __user *buffer, size_t *lenp,
                loff_t *ppos)
@@ -540,7 +542,7 @@ static u64 sched_vslice(struct cfs_rq *cfs_rq, struct sched_entity *se)
 }
 
 static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update);
-static void update_cfs_shares(struct cfs_rq *cfs_rq, long weight_delta);
+static void update_cfs_shares(struct cfs_rq *cfs_rq);
 
 /*
  * Update the current task's runtime statistics. Skip current tasks that
@@ -722,10 +724,10 @@ static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update)
        u64 now, delta;
        unsigned long load = cfs_rq->load.weight;
 
-       if (!cfs_rq)
+       if (cfs_rq->tg == &root_task_group)
                return;
 
-       now = rq_of(cfs_rq)->clock;
+       now = rq_of(cfs_rq)->clock_task;
        delta = now - cfs_rq->load_stamp;
 
        /* truncate load history at 4 idle periods */
@@ -733,6 +735,7 @@ static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update)
            now - cfs_rq->load_last > 4 * period) {
                cfs_rq->load_period = 0;
                cfs_rq->load_avg = 0;
+               delta = period - 1;
        }
 
        cfs_rq->load_stamp = now;
@@ -763,16 +766,15 @@ static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update)
                list_del_leaf_cfs_rq(cfs_rq);
 }
 
-static long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg,
-                               long weight_delta)
+static long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg)
 {
        long load_weight, load, shares;
 
-       load = cfs_rq->load.weight + weight_delta;
+       load = cfs_rq->load.weight;
 
        load_weight = atomic_read(&tg->load_weight);
-       load_weight -= cfs_rq->load_contribution;
        load_weight += load;
+       load_weight -= cfs_rq->load_contribution;
 
        shares = (tg->shares * load);
        if (load_weight)
@@ -790,7 +792,7 @@ static void update_entity_shares_tick(struct cfs_rq *cfs_rq)
 {
        if (cfs_rq->load_unacc_exec_time > sysctl_sched_shares_window) {
                update_cfs_load(cfs_rq, 0);
-               update_cfs_shares(cfs_rq, 0);
+               update_cfs_shares(cfs_rq);
        }
 }
 # else /* CONFIG_SMP */
@@ -798,8 +800,7 @@ static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update)
 {
 }
 
-static inline long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg,
-                               long weight_delta)
+static inline long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg)
 {
        return tg->shares;
 }
@@ -824,15 +825,12 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
                account_entity_enqueue(cfs_rq, se);
 }
 
-static void update_cfs_shares(struct cfs_rq *cfs_rq, long weight_delta)
+static void update_cfs_shares(struct cfs_rq *cfs_rq)
 {
        struct task_group *tg;
        struct sched_entity *se;
        long shares;
 
-       if (!cfs_rq)
-               return;
-
        tg = cfs_rq->tg;
        se = tg->se[cpu_of(rq_of(cfs_rq))];
        if (!se)
@@ -841,7 +839,7 @@ static void update_cfs_shares(struct cfs_rq *cfs_rq, long weight_delta)
        if (likely(se->load.weight == tg->shares))
                return;
 #endif
-       shares = calc_cfs_shares(cfs_rq, tg, weight_delta);
+       shares = calc_cfs_shares(cfs_rq, tg);
 
        reweight_entity(cfs_rq_of(se), se, shares);
 }
@@ -850,7 +848,7 @@ static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update)
 {
 }
 
-static inline void update_cfs_shares(struct cfs_rq *cfs_rq, long weight_delta)
+static inline void update_cfs_shares(struct cfs_rq *cfs_rq)
 {
 }
 
@@ -981,8 +979,8 @@ enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
         */
        update_curr(cfs_rq);
        update_cfs_load(cfs_rq, 0);
-       update_cfs_shares(cfs_rq, se->load.weight);
        account_entity_enqueue(cfs_rq, se);
+       update_cfs_shares(cfs_rq);
 
        if (flags & ENQUEUE_WAKEUP) {
                place_entity(cfs_rq, se, 0);
@@ -999,19 +997,49 @@ enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
                list_add_leaf_cfs_rq(cfs_rq);
 }
 
-static void __clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se)
+static void __clear_buddies_last(struct sched_entity *se)
 {
-       if (!se || cfs_rq->last == se)
-               cfs_rq->last = NULL;
+       for_each_sched_entity(se) {
+               struct cfs_rq *cfs_rq = cfs_rq_of(se);
+               if (cfs_rq->last == se)
+                       cfs_rq->last = NULL;
+               else
+                       break;
+       }
+}
 
-       if (!se || cfs_rq->next == se)
-               cfs_rq->next = NULL;
+static void __clear_buddies_next(struct sched_entity *se)
+{
+       for_each_sched_entity(se) {
+               struct cfs_rq *cfs_rq = cfs_rq_of(se);
+               if (cfs_rq->next == se)
+                       cfs_rq->next = NULL;
+               else
+                       break;
+       }
+}
+
+static void __clear_buddies_skip(struct sched_entity *se)
+{
+       for_each_sched_entity(se) {
+               struct cfs_rq *cfs_rq = cfs_rq_of(se);
+               if (cfs_rq->skip == se)
+                       cfs_rq->skip = NULL;
+               else
+                       break;
+       }
 }
 
 static void clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-       for_each_sched_entity(se)
-               __clear_buddies(cfs_rq_of(se), se);
+       if (cfs_rq->last == se)
+               __clear_buddies_last(se);
+
+       if (cfs_rq->next == se)
+               __clear_buddies_next(se);
+
+       if (cfs_rq->skip == se)
+               __clear_buddies_skip(se);
 }
 
 static void
@@ -1044,7 +1072,7 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
        update_cfs_load(cfs_rq, 0);
        account_entity_dequeue(cfs_rq, se);
        update_min_vruntime(cfs_rq);
-       update_cfs_shares(cfs_rq, 0);
+       update_cfs_shares(cfs_rq);
 
        /*
         * Normalize the entity after updating the min_vruntime because the
@@ -1087,7 +1115,7 @@ check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
                return;
 
        if (cfs_rq->nr_running > 1) {
-               struct sched_entity *se = __pick_next_entity(cfs_rq);
+               struct sched_entity *se = __pick_first_entity(cfs_rq);
                s64 delta = curr->vruntime - se->vruntime;
 
                if (delta < 0)
@@ -1131,13 +1159,27 @@ set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
 static int
 wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se);
 
+/*
+ * Pick the next process, keeping these things in mind, in this order:
+ * 1) keep things fair between processes/task groups
+ * 2) pick the "next" process, since someone really wants that to run
+ * 3) pick the "last" process, for cache locality
+ * 4) do not run the "skip" process, if something else is available
+ */
 static struct sched_entity *pick_next_entity(struct cfs_rq *cfs_rq)
 {
-       struct sched_entity *se = __pick_next_entity(cfs_rq);
+       struct sched_entity *se = __pick_first_entity(cfs_rq);
        struct sched_entity *left = se;
 
-       if (cfs_rq->next && wakeup_preempt_entity(cfs_rq->next, left) < 1)
-               se = cfs_rq->next;
+       /*
+        * Avoid running the skip buddy, if running something else can
+        * be done without getting too unfair.
+        */
+       if (cfs_rq->skip == se) {
+               struct sched_entity *second = __pick_next_entity(se);
+               if (second && wakeup_preempt_entity(second, left) < 1)
+                       se = second;
+       }
 
        /*
         * Prefer last buddy, try to return the CPU to a preempted task.
@@ -1145,6 +1187,12 @@ static struct sched_entity *pick_next_entity(struct cfs_rq *cfs_rq)
        if (cfs_rq->last && wakeup_preempt_entity(cfs_rq->last, left) < 1)
                se = cfs_rq->last;
 
+       /*
+        * Someone really wants this to run. If it's not unfair, run it.
+        */
+       if (cfs_rq->next && wakeup_preempt_entity(cfs_rq->next, left) < 1)
+               se = cfs_rq->next;
+
        clear_buddies(cfs_rq, se);
 
        return se;
@@ -1285,7 +1333,7 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
                struct cfs_rq *cfs_rq = cfs_rq_of(se);
 
                update_cfs_load(cfs_rq, 0);
-               update_cfs_shares(cfs_rq, 0);
+               update_cfs_shares(cfs_rq);
        }
 
        hrtick_update(rq);
@@ -1315,58 +1363,12 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
                struct cfs_rq *cfs_rq = cfs_rq_of(se);
 
                update_cfs_load(cfs_rq, 0);
-               update_cfs_shares(cfs_rq, 0);
+               update_cfs_shares(cfs_rq);
        }
 
        hrtick_update(rq);
 }
 
-/*
- * sched_yield() support is very simple - we dequeue and enqueue.
- *
- * If compat_yield is turned on then we requeue to the end of the tree.
- */
-static void yield_task_fair(struct rq *rq)
-{
-       struct task_struct *curr = rq->curr;
-       struct cfs_rq *cfs_rq = task_cfs_rq(curr);
-       struct sched_entity *rightmost, *se = &curr->se;
-
-       /*
-        * Are we the only task in the tree?
-        */
-       if (unlikely(cfs_rq->nr_running == 1))
-               return;
-
-       clear_buddies(cfs_rq, se);
-
-       if (likely(!sysctl_sched_compat_yield) && curr->policy != SCHED_BATCH) {
-               update_rq_clock(rq);
-               /*
-                * Update run-time statistics of the 'current'.
-                */
-               update_curr(cfs_rq);
-
-               return;
-       }
-       /*
-        * Find the rightmost entry in the rbtree:
-        */
-       rightmost = __pick_last_entity(cfs_rq);
-       /*
-        * Already in the rightmost position?
-        */
-       if (unlikely(!rightmost || entity_before(rightmost, se)))
-               return;
-
-       /*
-        * Minimally necessary key value to be last in the tree:
-        * Upon rescheduling, sched_class::put_prev_task() will place
-        * 'current' within the tree based on its new key value.
-        */
-       se->vruntime = rightmost->vruntime + 1;
-}
-
 #ifdef CONFIG_SMP
 
 static void task_waking_fair(struct rq *rq, struct task_struct *p)
@@ -1432,7 +1434,7 @@ static inline unsigned long effective_load(struct task_group *tg, int cpu,
 
 static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync)
 {
-       unsigned long this_load, load;
+       s64 this_load, load;
        int idx, this_cpu, prev_cpu;
        unsigned long tl_per_task;
        struct task_group *tg;
@@ -1471,8 +1473,8 @@ static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync)
         * Otherwise check if either cpus are near enough in load to allow this
         * task to be woken on this_cpu.
         */
-       if (this_load) {
-               unsigned long this_eff_load, prev_eff_load;
+       if (this_load > 0) {
+               s64 this_eff_load, prev_eff_load;
 
                this_eff_load = 100;
                this_eff_load *= power_of(prev_cpu);
@@ -1837,6 +1839,14 @@ static void set_next_buddy(struct sched_entity *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;
+       }
+}
+
 /*
  * Preempt the current task with a newly woken task if needed:
  */
@@ -1860,16 +1870,18 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_
        if (test_tsk_need_resched(curr))
                return;
 
+       /* Idle tasks are by definition preempted by non-idle tasks. */
+       if (unlikely(curr->policy == SCHED_IDLE) &&
+           likely(p->policy != SCHED_IDLE))
+               goto preempt;
+
        /*
-        * Batch and idle tasks do not preempt (their preemption is driven by
-        * the tick):
+        * Batch and idle tasks do not preempt non-idle tasks (their preemption
+        * is driven by the tick):
         */
        if (unlikely(p->policy != SCHED_NORMAL))
                return;
 
-       /* Idle tasks are by definition preempted by everybody. */
-       if (unlikely(curr->policy == SCHED_IDLE))
-               goto preempt;
 
        if (!sched_feat(WAKEUP_PREEMPT))
                return;
@@ -1935,6 +1947,51 @@ static void put_prev_task_fair(struct rq *rq, struct task_struct *prev)
        }
 }
 
+/*
+ * sched_yield() is very simple
+ *
+ * The magic of dealing with the ->skip buddy is in pick_next_entity.
+ */
+static void yield_task_fair(struct rq *rq)
+{
+       struct task_struct *curr = rq->curr;
+       struct cfs_rq *cfs_rq = task_cfs_rq(curr);
+       struct sched_entity *se = &curr->se;
+
+       /*
+        * Are we the only task in the tree?
+        */
+       if (unlikely(rq->nr_running == 1))
+               return;
+
+       clear_buddies(cfs_rq, se);
+
+       if (curr->policy != SCHED_BATCH) {
+               update_rq_clock(rq);
+               /*
+                * Update run-time statistics of the 'current'.
+                */
+               update_curr(cfs_rq);
+       }
+
+       set_skip_buddy(se);
+}
+
+static bool yield_to_task_fair(struct rq *rq, struct task_struct *p, bool preempt)
+{
+       struct sched_entity *se = &p->se;
+
+       if (!se->on_rq)
+               return false;
+
+       /* Tell the scheduler that we'd really like pse to run next. */
+       set_next_buddy(se);
+
+       yield_task_fair(rq);
+
+       return true;
+}
+
 #ifdef CONFIG_SMP
 /**************************************************
  * Fair scheduling class load-balancing methods:
@@ -2126,7 +2183,7 @@ static int update_shares_cpu(struct task_group *tg, int cpu)
         * We need to update shares after updating tg->load_weight in
         * order to adjust the weight of groups with long running tasks.
         */
-       update_cfs_shares(cfs_rq, 0);
+       update_cfs_shares(cfs_rq);
 
        raw_spin_unlock_irqrestore(&rq->lock, flags);
 
@@ -2613,7 +2670,6 @@ fix_small_capacity(struct sched_domain *sd, struct sched_group *group)
  * @this_cpu: Cpu for which load balance is currently performed.
  * @idle: Idle status of this_cpu
  * @load_idx: Load index of sched_domain of this_cpu for load calc.
- * @sd_idle: Idle status of the sched_domain containing group.
  * @local_group: Does group contain this_cpu.
  * @cpus: Set of cpus considered for load balancing.
  * @balance: Should we balance.
@@ -2621,7 +2677,7 @@ fix_small_capacity(struct sched_domain *sd, struct sched_group *group)
  */
 static inline void update_sg_lb_stats(struct sched_domain *sd,
                        struct sched_group *group, int this_cpu,
-                       enum cpu_idle_type idle, int load_idx, int *sd_idle,
+                       enum cpu_idle_type idle, int load_idx,
                        int local_group, const struct cpumask *cpus,
                        int *balance, struct sg_lb_stats *sgs)
 {
@@ -2641,9 +2697,6 @@ static inline void update_sg_lb_stats(struct sched_domain *sd,
        for_each_cpu_and(i, sched_group_cpus(group), cpus) {
                struct rq *rq = cpu_rq(i);
 
-               if (*sd_idle && rq->nr_running)
-                       *sd_idle = 0;
-
                /* Bias balancing toward cpus of our domain */
                if (local_group) {
                        if (idle_cpu(i) && !first_idle_cpu) {
@@ -2688,7 +2741,7 @@ static inline void update_sg_lb_stats(struct sched_domain *sd,
 
        /*
         * Consider the group unbalanced when the imbalance is larger
-        * than the average weight of two tasks.
+        * than the average weight of a task.
         *
         * APZ: with cgroup the avg task weight can vary wildly and
         *      might not be a suitable number - should we keep a
@@ -2698,7 +2751,7 @@ static inline void update_sg_lb_stats(struct sched_domain *sd,
        if (sgs->sum_nr_running)
                avg_load_per_task = sgs->sum_weighted_load / sgs->sum_nr_running;
 
-       if ((max_cpu_load - min_cpu_load) > 2*avg_load_per_task && max_nr_running > 1)
+       if ((max_cpu_load - min_cpu_load) >avg_load_per_task && max_nr_running > 1)
                sgs->group_imb = 1;
 
        sgs->group_capacity = DIV_ROUND_CLOSEST(group->cpu_power, SCHED_LOAD_SCALE);
@@ -2758,15 +2811,13 @@ static bool update_sd_pick_busiest(struct sched_domain *sd,
  * @sd: sched_domain whose statistics are to be updated.
  * @this_cpu: Cpu for which load balance is currently performed.
  * @idle: Idle status of this_cpu
- * @sd_idle: Idle status of the sched_domain containing sg.
  * @cpus: Set of cpus considered for load balancing.
  * @balance: Should we balance.
  * @sds: variable to hold the statistics for this sched_domain.
  */
 static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu,
-                       enum cpu_idle_type idle, int *sd_idle,
-                       const struct cpumask *cpus, int *balance,
-                       struct sd_lb_stats *sds)
+                       enum cpu_idle_type idle, const struct cpumask *cpus,
+                       int *balance, struct sd_lb_stats *sds)
 {
        struct sched_domain *child = sd->child;
        struct sched_group *sg = sd->groups;
@@ -2784,7 +2835,7 @@ static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu,
 
                local_group = cpumask_test_cpu(this_cpu, sched_group_cpus(sg));
                memset(&sgs, 0, sizeof(sgs));
-               update_sg_lb_stats(sd, sg, this_cpu, idle, load_idx, sd_idle,
+               update_sg_lb_stats(sd, sg, this_cpu, idle, load_idx,
                                local_group, cpus, balance, &sgs);
 
                if (local_group && !(*balance))
@@ -3036,7 +3087,6 @@ static inline void calculate_imbalance(struct sd_lb_stats *sds, int this_cpu,
  * @imbalance: Variable which stores amount of weighted load which should
  *             be moved to restore balance/put a group to idle.
  * @idle: The idle status of this_cpu.
- * @sd_idle: The idleness of sd
  * @cpus: The set of CPUs under consideration for load-balancing.
  * @balance: Pointer to a variable indicating if this_cpu
  *     is the appropriate cpu to perform load balancing at this_level.
@@ -3049,7 +3099,7 @@ static inline void calculate_imbalance(struct sd_lb_stats *sds, int this_cpu,
 static struct sched_group *
 find_busiest_group(struct sched_domain *sd, int this_cpu,
                   unsigned long *imbalance, enum cpu_idle_type idle,
-                  int *sd_idle, const struct cpumask *cpus, int *balance)
+                  const struct cpumask *cpus, int *balance)
 {
        struct sd_lb_stats sds;
 
@@ -3059,22 +3109,11 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
         * Compute the various statistics relavent for load balancing at
         * this level.
         */
-       update_sd_lb_stats(sd, this_cpu, idle, sd_idle, cpus,
-                                       balance, &sds);
-
-       /* Cases where imbalance does not exist from POV of this_cpu */
-       /* 1) this_cpu is not the appropriate cpu to perform load balancing
-        *    at this level.
-        * 2) There is no busy sibling group to pull from.
-        * 3) This group is the busiest group.
-        * 4) This group is more busy than the avg busieness at this
-        *    sched_domain.
-        * 5) The imbalance is within the specified limit.
-        *
-        * Note: when doing newidle balance, if the local group has excess
-        * capacity (i.e. nr_running < group_capacity) and the busiest group
-        * does not have any capacity, we force a load balance to pull tasks
-        * to the local group. In this case, we skip past checks 3, 4 and 5.
+       update_sd_lb_stats(sd, this_cpu, idle, cpus, balance, &sds);
+
+       /*
+        * this_cpu is not the appropriate cpu to perform load balancing at
+        * this level.
         */
        if (!(*balance))
                goto ret;
@@ -3083,41 +3122,55 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
            check_asym_packing(sd, &sds, this_cpu, imbalance))
                return sds.busiest;
 
+       /* There is no busy sibling group to pull tasks from */
        if (!sds.busiest || sds.busiest_nr_running == 0)
                goto out_balanced;
 
-       /*  SD_BALANCE_NEWIDLE trumps SMP nice when underutilized */
+       /*
+        * If the busiest group is imbalanced the below checks don't
+        * work because they assumes all things are equal, which typically
+        * isn't true due to cpus_allowed constraints and the like.
+        */
+       if (sds.group_imb)
+               goto force_balance;
+
+       /* SD_BALANCE_NEWIDLE trumps SMP nice when underutilized */
        if (idle == CPU_NEWLY_IDLE && sds.this_has_capacity &&
                        !sds.busiest_has_capacity)
                goto force_balance;
 
+       /*
+        * If the local group is more busy than the selected busiest group
+        * don't try and pull any tasks.
+        */
        if (sds.this_load >= sds.max_load)
                goto out_balanced;
 
+       /*
+        * Don't pull any tasks if this group is already above the domain
+        * average load.
+        */
        sds.avg_load = (SCHED_LOAD_SCALE * sds.total_load) / sds.total_pwr;
-
        if (sds.this_load >= sds.avg_load)
                goto out_balanced;
 
-       /*
-        * In the CPU_NEWLY_IDLE, use imbalance_pct to be conservative.
-        * And to check for busy balance use !idle_cpu instead of
-        * CPU_NOT_IDLE. This is because HT siblings will use CPU_NOT_IDLE
-        * even when they are idle.
-        */
-       if (idle == CPU_NEWLY_IDLE || !idle_cpu(this_cpu)) {
-               if (100 * sds.max_load <= sd->imbalance_pct * sds.this_load)
-                       goto out_balanced;
-       } else {
+       if (idle == CPU_IDLE) {
                /*
                 * This cpu is idle. If the busiest group load doesn't
                 * have more tasks than the number of available cpu's and
                 * there is no imbalance between this and busiest group
                 * wrt to idle cpu's, it is balanced.
                 */
-               if ((sds.this_idle_cpus  <= sds.busiest_idle_cpus + 1) &&
+               if ((sds.this_idle_cpus <= sds.busiest_idle_cpus + 1) &&
                    sds.busiest_nr_running <= sds.busiest_group_weight)
                        goto out_balanced;
+       } else {
+               /*
+                * In the CPU_NEWLY_IDLE, CPU_NOT_IDLE cases, use
+                * imbalance_pct to be conservative.
+                */
+               if (100 * sds.max_load <= sd->imbalance_pct * sds.this_load)
+                       goto out_balanced;
        }
 
 force_balance:
@@ -3196,7 +3249,7 @@ find_busiest_queue(struct sched_domain *sd, struct sched_group *group,
 /* Working cpumask for load_balance and load_balance_newidle. */
 static DEFINE_PER_CPU(cpumask_var_t, load_balance_tmpmask);
 
-static int need_active_balance(struct sched_domain *sd, int sd_idle, int idle,
+static int need_active_balance(struct sched_domain *sd, int idle,
                               int busiest_cpu, int this_cpu)
 {
        if (idle == CPU_NEWLY_IDLE) {
@@ -3228,10 +3281,6 @@ static int need_active_balance(struct sched_domain *sd, int sd_idle, int idle,
                 * move_tasks() will succeed.  ld_moved will be true and this
                 * active balance code will not be triggered.
                 */
-               if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER &&
-                   !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
-                       return 0;
-
                if (sched_mc_power_savings < POWERSAVINGS_BALANCE_WAKEUP)
                        return 0;
        }
@@ -3249,7 +3298,7 @@ static int load_balance(int this_cpu, struct rq *this_rq,
                        struct sched_domain *sd, enum cpu_idle_type idle,
                        int *balance)
 {
-       int ld_moved, all_pinned = 0, active_balance = 0, sd_idle = 0;
+       int ld_moved, all_pinned = 0, active_balance = 0;
        struct sched_group *group;
        unsigned long imbalance;
        struct rq *busiest;
@@ -3258,20 +3307,10 @@ static int load_balance(int this_cpu, struct rq *this_rq,
 
        cpumask_copy(cpus, cpu_active_mask);
 
-       /*
-        * When power savings policy is enabled for the parent domain, idle
-        * sibling can pick up load irrespective of busy siblings. In this case,
-        * let the state of idle sibling percolate up as CPU_IDLE, instead of
-        * portraying it as CPU_NOT_IDLE.
-        */
-       if (idle != CPU_NOT_IDLE && sd->flags & SD_SHARE_CPUPOWER &&
-           !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
-               sd_idle = 1;
-
        schedstat_inc(sd, lb_count[idle]);
 
 redo:
-       group = find_busiest_group(sd, this_cpu, &imbalance, idle, &sd_idle,
+       group = find_busiest_group(sd, this_cpu, &imbalance, idle,
                                   cpus, balance);
 
        if (*balance == 0)
@@ -3333,8 +3372,7 @@ redo:
                if (idle != CPU_NEWLY_IDLE)
                        sd->nr_balance_failed++;
 
-               if (need_active_balance(sd, sd_idle, idle, cpu_of(busiest),
-                                       this_cpu)) {
+               if (need_active_balance(sd, idle, cpu_of(busiest), this_cpu)) {
                        raw_spin_lock_irqsave(&busiest->lock, flags);
 
                        /* don't kick the active_load_balance_cpu_stop,
@@ -3389,10 +3427,6 @@ redo:
                        sd->balance_interval *= 2;
        }
 
-       if (!ld_moved && !sd_idle && sd->flags & SD_SHARE_CPUPOWER &&
-           !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
-               ld_moved = -1;
-
        goto out;
 
 out_balanced:
@@ -3406,11 +3440,7 @@ out_one_pinned:
                        (sd->balance_interval < sd->max_interval))
                sd->balance_interval *= 2;
 
-       if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER &&
-           !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
-               ld_moved = -1;
-       else
-               ld_moved = 0;
+       ld_moved = 0;
 out:
        return ld_moved;
 }
@@ -3834,8 +3864,7 @@ static void rebalance_domains(int cpu, enum cpu_idle_type idle)
                        if (load_balance(cpu, rq, sd, idle, &balance)) {
                                /*
                                 * We've pulled tasks over so either we're no
-                                * longer idle, or one of our SMT siblings is
-                                * not idle.
+                                * longer idle.
                                 */
                                idle = CPU_NOT_IDLE;
                        }
@@ -4082,33 +4111,62 @@ static void task_fork_fair(struct task_struct *p)
  * Priority of the task has changed. Check to see if we preempt
  * the current task.
  */
-static void prio_changed_fair(struct rq *rq, struct task_struct *p,
-                             int oldprio, int running)
+static void
+prio_changed_fair(struct rq *rq, struct task_struct *p, int oldprio)
 {
+       if (!p->se.on_rq)
+               return;
+
        /*
         * Reschedule if we are currently running on this runqueue and
         * our priority decreased, or if we are not currently running on
         * this runqueue and our priority is higher than the current's
         */
-       if (running) {
+       if (rq->curr == p) {
                if (p->prio > oldprio)
                        resched_task(rq->curr);
        } else
                check_preempt_curr(rq, p, 0);
 }
 
+static void switched_from_fair(struct rq *rq, struct task_struct *p)
+{
+       struct sched_entity *se = &p->se;
+       struct cfs_rq *cfs_rq = cfs_rq_of(se);
+
+       /*
+        * Ensure the task's vruntime is normalized, so that when its
+        * switched back to the fair class the enqueue_entity(.flags=0) will
+        * do the right thing.
+        *
+        * If it was on_rq, then the dequeue_entity(.flags=0) will already
+        * have normalized the vruntime, if it was !on_rq, then only when
+        * the task is sleeping will it still have non-normalized vruntime.
+        */
+       if (!se->on_rq && p->state != TASK_RUNNING) {
+               /*
+                * Fix up our vruntime so that the current sleep doesn't
+                * cause 'unlimited' sleep bonus.
+                */
+               place_entity(cfs_rq, se, 0);
+               se->vruntime -= cfs_rq->min_vruntime;
+       }
+}
+
 /*
  * We switched to the sched_fair class.
  */
-static void switched_to_fair(struct rq *rq, struct task_struct *p,
-                            int running)
+static void switched_to_fair(struct rq *rq, struct task_struct *p)
 {
+       if (!p->se.on_rq)
+               return;
+
        /*
         * We were most likely switched from sched_rt, so
         * kick off the schedule if running, otherwise just see
         * if we can still preempt the current task.
         */
-       if (running)
+       if (rq->curr == p)
                resched_task(rq->curr);
        else
                check_preempt_curr(rq, p, 0);
@@ -4174,6 +4232,7 @@ static const struct sched_class fair_sched_class = {
        .enqueue_task           = enqueue_task_fair,
        .dequeue_task           = dequeue_task_fair,
        .yield_task             = yield_task_fair,
+       .yield_to_task          = yield_to_task_fair,
 
        .check_preempt_curr     = check_preempt_wakeup,
 
@@ -4194,6 +4253,7 @@ static const struct sched_class fair_sched_class = {
        .task_fork              = task_fork_fair,
 
        .prio_changed           = prio_changed_fair,
+       .switched_from          = switched_from_fair,
        .switched_to            = switched_to_fair,
 
        .get_rr_interval        = get_rr_interval_fair,
index 9fa0f40..c82f26c 100644 (file)
@@ -52,31 +52,15 @@ static void set_curr_task_idle(struct rq *rq)
 {
 }
 
-static void switched_to_idle(struct rq *rq, struct task_struct *p,
-                            int running)
+static void switched_to_idle(struct rq *rq, struct task_struct *p)
 {
-       /* Can this actually happen?? */
-       if (running)
-               resched_task(rq->curr);
-       else
-               check_preempt_curr(rq, p, 0);
+       BUG();
 }
 
-static void prio_changed_idle(struct rq *rq, struct task_struct *p,
-                             int oldprio, int running)
+static void
+prio_changed_idle(struct rq *rq, struct task_struct *p, int oldprio)
 {
-       /* This can happen for hot plug CPUS */
-
-       /*
-        * Reschedule if we are currently running on this runqueue and
-        * our priority decreased, or if we are not currently running on
-        * this runqueue and our priority is higher than the current's
-        */
-       if (running) {
-               if (p->prio > oldprio)
-                       resched_task(rq->curr);
-       } else
-               check_preempt_curr(rq, p, 0);
+       BUG();
 }
 
 static unsigned int get_rr_interval_idle(struct rq *rq, struct task_struct *task)
index c914ec7..db308cb 100644 (file)
@@ -210,11 +210,12 @@ static void dequeue_rt_entity(struct sched_rt_entity *rt_se);
 
 static void sched_rt_rq_enqueue(struct rt_rq *rt_rq)
 {
-       int this_cpu = smp_processor_id();
        struct task_struct *curr = rq_of_rt_rq(rt_rq)->curr;
        struct sched_rt_entity *rt_se;
 
-       rt_se = rt_rq->tg->rt_se[this_cpu];
+       int cpu = cpu_of(rq_of_rt_rq(rt_rq));
+
+       rt_se = rt_rq->tg->rt_se[cpu];
 
        if (rt_rq->rt_nr_running) {
                if (rt_se && !on_rt_rq(rt_se))
@@ -226,10 +227,10 @@ static void sched_rt_rq_enqueue(struct rt_rq *rt_rq)
 
 static void sched_rt_rq_dequeue(struct rt_rq *rt_rq)
 {
-       int this_cpu = smp_processor_id();
        struct sched_rt_entity *rt_se;
+       int cpu = cpu_of(rq_of_rt_rq(rt_rq));
 
-       rt_se = rt_rq->tg->rt_se[this_cpu];
+       rt_se = rt_rq->tg->rt_se[cpu];
 
        if (rt_se && on_rt_rq(rt_se))
                dequeue_rt_entity(rt_se);
@@ -565,8 +566,11 @@ static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun)
                        if (rt_rq->rt_time || rt_rq->rt_nr_running)
                                idle = 0;
                        raw_spin_unlock(&rt_rq->rt_runtime_lock);
-               } else if (rt_rq->rt_nr_running)
+               } else if (rt_rq->rt_nr_running) {
                        idle = 0;
+                       if (!rt_rq_throttled(rt_rq))
+                               enqueue = 1;
+               }
 
                if (enqueue)
                        sched_rt_rq_enqueue(rt_rq);
@@ -625,7 +629,7 @@ static void update_curr_rt(struct rq *rq)
        struct rt_rq *rt_rq = rt_rq_of_se(rt_se);
        u64 delta_exec;
 
-       if (!task_has_rt_policy(curr))
+       if (curr->sched_class != &rt_sched_class)
                return;
 
        delta_exec = rq->clock_task - curr->se.exec_start;
@@ -1595,8 +1599,7 @@ static void rq_offline_rt(struct rq *rq)
  * When switch from the rt queue, we bring ourselves to a position
  * that we might want to pull RT tasks from other runqueues.
  */
-static void switched_from_rt(struct rq *rq, struct task_struct *p,
-                          int running)
+static void switched_from_rt(struct rq *rq, struct task_struct *p)
 {
        /*
         * If there are other RT tasks then we will reschedule
@@ -1605,7 +1608,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 (!rq->rt.rt_nr_running)
+       if (p->se.on_rq && !rq->rt.rt_nr_running)
                pull_rt_task(rq);
 }
 
@@ -1624,8 +1627,7 @@ static inline void init_sched_rt_class(void)
  * with RT tasks. In this case we try to push them off to
  * other runqueues.
  */
-static void switched_to_rt(struct rq *rq, struct task_struct *p,
-                          int running)
+static void switched_to_rt(struct rq *rq, struct task_struct *p)
 {
        int check_resched = 1;
 
@@ -1636,7 +1638,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 (!running) {
+       if (p->se.on_rq && rq->curr != p) {
 #ifdef CONFIG_SMP
                if (rq->rt.overloaded && push_rt_task(rq) &&
                    /* Don't resched if we changed runqueues */
@@ -1652,10 +1654,13 @@ static void switched_to_rt(struct rq *rq, struct task_struct *p,
  * Priority of the task has changed. This may cause
  * us to initiate a push or pull.
  */
-static void prio_changed_rt(struct rq *rq, struct task_struct *p,
-                           int oldprio, int running)
+static void
+prio_changed_rt(struct rq *rq, struct task_struct *p, int oldprio)
 {
-       if (running) {
+       if (!p->se.on_rq)
+               return;
+
+       if (rq->curr == p) {
 #ifdef CONFIG_SMP
                /*
                 * If our priority decreases while running, we
index 2bf6b47..84ec9bc 100644 (file)
@@ -59,14 +59,13 @@ static void set_curr_task_stop(struct rq *rq)
 {
 }
 
-static void switched_to_stop(struct rq *rq, struct task_struct *p,
-                            int running)
+static void switched_to_stop(struct rq *rq, struct task_struct *p)
 {
        BUG(); /* its impossible to change to this class */
 }
 
-static void prio_changed_stop(struct rq *rq, struct task_struct *p,
-                             int oldprio, int running)
+static void
+prio_changed_stop(struct rq *rq, struct task_struct *p, int oldprio)
 {
        BUG(); /* how!?, what priority? */
 }
index 68eb5ef..56e5dec 100644 (file)
@@ -54,7 +54,7 @@ EXPORT_SYMBOL(irq_stat);
 
 static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp;
 
-static DEFINE_PER_CPU(struct task_struct *, ksoftirqd);
+DEFINE_PER_CPU(struct task_struct *, ksoftirqd);
 
 char *softirq_to_name[NR_SOFTIRQS] = {
        "HI", "TIMER", "NET_TX", "NET_RX", "BLOCK", "BLOCK_IOPOLL",
@@ -311,9 +311,21 @@ void irq_enter(void)
 }
 
 #ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED
-# define invoke_softirq()      __do_softirq()
+static inline void invoke_softirq(void)
+{
+       if (!force_irqthreads)
+               __do_softirq();
+       else
+               wakeup_softirqd();
+}
 #else
-# define invoke_softirq()      do_softirq()
+static inline void invoke_softirq(void)
+{
+       if (!force_irqthreads)
+               do_softirq();
+       else
+               wakeup_softirqd();
+}
 #endif
 
 /*
@@ -721,7 +733,6 @@ static int run_ksoftirqd(void * __bind_cpu)
 {
        set_current_state(TASK_INTERRUPTIBLE);
 
-       current->flags |= PF_KSOFTIRQD;
        while (!kthread_should_stop()) {
                preempt_disable();
                if (!local_softirq_pending()) {
@@ -738,7 +749,10 @@ static int run_ksoftirqd(void * __bind_cpu)
                           don't process */
                        if (cpu_is_offline((long)__bind_cpu))
                                goto wait_to_die;
-                       do_softirq();
+                       local_irq_disable();
+                       if (local_softirq_pending())
+                               __do_softirq();
+                       local_irq_enable();
                        preempt_enable_no_resched();
                        cond_resched();
                        preempt_disable();
index 31b71a2..18da702 100644 (file)
@@ -1385,7 +1385,8 @@ static int check_prlimit_permission(struct task_struct *task)
        const struct cred *cred = current_cred(), *tcred;
 
        tcred = __task_cred(task);
-       if ((cred->uid != tcred->euid ||
+       if (current != task &&
+           (cred->uid != tcred->euid ||
             cred->uid != tcred->suid ||
             cred->uid != tcred->uid  ||
             cred->gid != tcred->egid ||
index c782fe9..25cc41c 100644 (file)
@@ -186,3 +186,8 @@ cond_syscall(sys_perf_event_open);
 /* fanotify! */
 cond_syscall(sys_fanotify_init);
 cond_syscall(sys_fanotify_mark);
+
+/* open by handle */
+cond_syscall(sys_name_to_handle_at);
+cond_syscall(sys_open_by_handle_at);
+cond_syscall(compat_sys_open_by_handle_at);
index bc86bb3..51054fe 100644 (file)
@@ -170,7 +170,8 @@ static int proc_taint(struct ctl_table *table, int write,
 #endif
 
 #ifdef CONFIG_MAGIC_SYSRQ
-static int __sysrq_enabled; /* Note: sysrq code ises it's own private copy */
+/* Note: sysrq code uses it's own private copy */
+static int __sysrq_enabled = SYSRQ_DEFAULT_ENABLE;
 
 static int sysrq_sysctl_handler(ctl_table *table, int write,
                                void __user *buffer, size_t *lenp,
@@ -193,9 +194,9 @@ static int sysrq_sysctl_handler(ctl_table *table, int write,
 static struct ctl_table root_table[];
 static struct ctl_table_root sysctl_table_root;
 static struct ctl_table_header root_table_header = {
-       .count = 1,
+       {{.count = 1,
        .ctl_table = root_table,
-       .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.default_set.list),
+       .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.default_set.list),}},
        .root = &sysctl_table_root,
        .set = &sysctl_table_root.default_set,
 };
@@ -360,20 +361,13 @@ static struct ctl_table kern_table[] = {
                .mode           = 0644,
                .proc_handler   = sched_rt_handler,
        },
-       {
-               .procname       = "sched_compat_yield",
-               .data           = &sysctl_sched_compat_yield,
-               .maxlen         = sizeof(unsigned int),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec,
-       },
 #ifdef CONFIG_SCHED_AUTOGROUP
        {
                .procname       = "sched_autogroup_enabled",
                .data           = &sysctl_sched_autogroup_enabled,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
+               .proc_handler   = proc_dointvec_minmax,
                .extra1         = &zero,
                .extra2         = &one,
        },
@@ -947,7 +941,7 @@ static struct ctl_table kern_table[] = {
                .data           = &sysctl_perf_event_sample_rate,
                .maxlen         = sizeof(sysctl_perf_event_sample_rate),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
+               .proc_handler   = perf_proc_update_handler,
        },
 #endif
 #ifdef CONFIG_KMEMCHECK
@@ -1566,11 +1560,16 @@ void sysctl_head_get(struct ctl_table_header *head)
        spin_unlock(&sysctl_lock);
 }
 
+static void free_head(struct rcu_head *rcu)
+{
+       kfree(container_of(rcu, struct ctl_table_header, rcu));
+}
+
 void sysctl_head_put(struct ctl_table_header *head)
 {
        spin_lock(&sysctl_lock);
        if (!--head->count)
-               kfree(head);
+               call_rcu(&head->rcu, free_head);
        spin_unlock(&sysctl_lock);
 }
 
@@ -1947,10 +1946,10 @@ void unregister_sysctl_table(struct ctl_table_header * header)
        start_unregistering(header);
        if (!--header->parent->count) {
                WARN_ON(1);
-               kfree(header->parent);
+               call_rcu(&header->parent->rcu, free_head);
        }
        if (!--header->count)
-               kfree(header);
+               call_rcu(&header->rcu, free_head);
        spin_unlock(&sysctl_lock);
 }
 
index b875bed..3b8e028 100644 (file)
@@ -1321,13 +1321,11 @@ static ssize_t binary_sysctl(const int *name, int nlen,
        void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
 {
        const struct bin_table *table = NULL;
-       struct nameidata nd;
        struct vfsmount *mnt;
        struct file *file;
        ssize_t result;
        char *pathname;
        int flags;
-       int acc_mode;
 
        pathname = sysctl_getname(name, nlen, &table);
        result = PTR_ERR(pathname);
@@ -1337,28 +1335,17 @@ static ssize_t binary_sysctl(const int *name, int nlen,
        /* How should the sysctl be accessed? */
        if (oldval && oldlen && newval && newlen) {
                flags = O_RDWR;
-               acc_mode = MAY_READ | MAY_WRITE;
        } else if (newval && newlen) {
                flags = O_WRONLY;
-               acc_mode = MAY_WRITE;
        } else if (oldval && oldlen) {
                flags = O_RDONLY;
-               acc_mode = MAY_READ;
        } else {
                result = 0;
                goto out_putname;
        }
 
        mnt = current->nsproxy->pid_ns->proc_mnt;
-       result = vfs_path_lookup(mnt->mnt_root, mnt, pathname, 0, &nd);
-       if (result)
-               goto out_putname;
-
-       result = may_open(&nd.path, acc_mode, flags);
-       if (result)
-               goto out_putpath;
-
-       file = dentry_open(nd.path.dentry, nd.path.mnt, flags, current_cred());
+       file = file_open_root(mnt->mnt_root, mnt, pathname, flags);
        result = PTR_ERR(file);
        if (IS_ERR(file))
                goto out_putname;
@@ -1370,10 +1357,6 @@ out_putname:
        putname(pathname);
 out:
        return result;
-
-out_putpath:
-       path_put(&nd.path);
-       goto out_putname;
 }
 
 
index 3217435..8e8dc6d 100644 (file)
@@ -150,7 +150,7 @@ static inline void warp_clock(void)
  * various programs will get confused when the clock gets warped.
  */
 
-int do_sys_settimeofday(struct timespec *tv, struct timezone *tz)
+int do_sys_settimeofday(const struct timespec *tv, const struct timezone *tz)
 {
        static int firsttime = 1;
        int error = 0;
@@ -645,7 +645,7 @@ u64 nsec_to_clock_t(u64 x)
 }
 
 /**
- * nsecs_to_jiffies - Convert nsecs in u64 to jiffies
+ * nsecs_to_jiffies64 - Convert nsecs in u64 to jiffies64
  *
  * @n: nsecs in u64
  *
@@ -657,7 +657,7 @@ u64 nsec_to_clock_t(u64 x)
  *   NSEC_PER_SEC = 10^9 = (5^9 * 2^9) = (1953125 * 512)
  *   ULLONG_MAX ns = 18446744073.709551615 secs = about 584 years
  */
-unsigned long nsecs_to_jiffies(u64 n)
+u64 nsecs_to_jiffies64(u64 n)
 {
 #if (NSEC_PER_SEC % HZ) == 0
        /* Common case, HZ = 100, 128, 200, 250, 256, 500, 512, 1000 etc. */
@@ -674,22 +674,23 @@ unsigned long nsecs_to_jiffies(u64 n)
 #endif
 }
 
-#if (BITS_PER_LONG < 64)
-u64 get_jiffies_64(void)
+/**
+ * nsecs_to_jiffies - Convert nsecs in u64 to jiffies
+ *
+ * @n: nsecs in u64
+ *
+ * Unlike {m,u}secs_to_jiffies, type of input is not unsigned int but u64.
+ * And this doesn't return MAX_JIFFY_OFFSET since this function is designed
+ * for scheduler, not for use in device drivers to calculate timeout value.
+ *
+ * note:
+ *   NSEC_PER_SEC = 10^9 = (5^9 * 2^9) = (1953125 * 512)
+ *   ULLONG_MAX ns = 18446744073.709551615 secs = about 584 years
+ */
+unsigned long nsecs_to_jiffies(u64 n)
 {
-       unsigned long seq;
-       u64 ret;
-
-       do {
-               seq = read_seqbegin(&xtime_lock);
-               ret = jiffies_64;
-       } while (read_seqretry(&xtime_lock, seq));
-       return ret;
+       return (unsigned long)nsecs_to_jiffies64(n);
 }
-EXPORT_SYMBOL(get_jiffies_64);
-#endif
-
-EXPORT_SYMBOL(jiffies);
 
 /*
  * Add two timespec values and do a safety check for overflow.
index ee26662..b042599 100644 (file)
@@ -1,4 +1,5 @@
-obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o timecompare.o timeconv.o
+obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o timecompare.o
+obj-y += timeconv.o posix-clock.o
 
 obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD)                += clockevents.o
 obj-$(CONFIG_GENERIC_CLOCKEVENTS)              += tick-common.o
index d7395fd..0d74b9b 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/notifier.h>
 #include <linux/smp.h>
 #include <linux/sysdev.h>
-#include <linux/tick.h>
 
 #include "tick-internal.h"
 
index 5404a84..b2fa506 100644 (file)
 ************************************************************************/
 #include <linux/clocksource.h>
 #include <linux/jiffies.h>
+#include <linux/module.h>
 #include <linux/init.h>
 
+#include "tick-internal.h"
+
 /* The Jiffies based clocksource is the lowest common
  * denominator clock source which should function on
  * all systems. It has the same coarse resolution as
@@ -64,6 +67,23 @@ struct clocksource clocksource_jiffies = {
        .shift          = JIFFIES_SHIFT,
 };
 
+#if (BITS_PER_LONG < 64)
+u64 get_jiffies_64(void)
+{
+       unsigned long seq;
+       u64 ret;
+
+       do {
+               seq = read_seqbegin(&xtime_lock);
+               ret = jiffies_64;
+       } while (read_seqretry(&xtime_lock, seq));
+       return ret;
+}
+EXPORT_SYMBOL(get_jiffies_64);
+#endif
+
+EXPORT_SYMBOL(jiffies);
+
 static int __init init_jiffies_clocksource(void)
 {
        return clocksource_register(&clocksource_jiffies);
index 5c00242..5f1bb8e 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 
+#include "tick-internal.h"
+
 /*
  * NTP timekeeping variables:
  */
@@ -646,6 +648,17 @@ int do_adjtimex(struct timex *txc)
                        hrtimer_cancel(&leap_timer);
        }
 
+       if (txc->modes & ADJ_SETOFFSET) {
+               struct timespec delta;
+               delta.tv_sec  = txc->time.tv_sec;
+               delta.tv_nsec = txc->time.tv_usec;
+               if (!(txc->modes & ADJ_NANO))
+                       delta.tv_nsec *= 1000;
+               result = timekeeping_inject_offset(&delta);
+               if (result)
+                       return result;
+       }
+
        getnstimeofday(&ts);
 
        write_seqlock_irq(&xtime_lock);
diff --git a/kernel/time/posix-clock.c b/kernel/time/posix-clock.c
new file mode 100644 (file)
index 0000000..25028dd
--- /dev/null
@@ -0,0 +1,451 @@
+/*
+ * posix-clock.c - support for dynamic clock devices
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/device.h>
+#include <linux/file.h>
+#include <linux/mutex.h>
+#include <linux/posix-clock.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+
+static void delete_clock(struct kref *kref);
+
+/*
+ * Returns NULL if the posix_clock instance attached to 'fp' is old and stale.
+ */
+static struct posix_clock *get_posix_clock(struct file *fp)
+{
+       struct posix_clock *clk = fp->private_data;
+
+       mutex_lock(&clk->mutex);
+
+       if (!clk->zombie)
+               return clk;
+
+       mutex_unlock(&clk->mutex);
+
+       return NULL;
+}
+
+static void put_posix_clock(struct posix_clock *clk)
+{
+       mutex_unlock(&clk->mutex);
+}
+
+static ssize_t posix_clock_read(struct file *fp, char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       struct posix_clock *clk = get_posix_clock(fp);
+       int err = -EINVAL;
+
+       if (!clk)
+               return -ENODEV;
+
+       if (clk->ops.read)
+               err = clk->ops.read(clk, fp->f_flags, buf, count);
+
+       put_posix_clock(clk);
+
+       return err;
+}
+
+static unsigned int posix_clock_poll(struct file *fp, poll_table *wait)
+{
+       struct posix_clock *clk = get_posix_clock(fp);
+       int result = 0;
+
+       if (!clk)
+               return -ENODEV;
+
+       if (clk->ops.poll)
+               result = clk->ops.poll(clk, fp, wait);
+
+       put_posix_clock(clk);
+
+       return result;
+}
+
+static int posix_clock_fasync(int fd, struct file *fp, int on)
+{
+       struct posix_clock *clk = get_posix_clock(fp);
+       int err = 0;
+
+       if (!clk)
+               return -ENODEV;
+
+       if (clk->ops.fasync)
+               err = clk->ops.fasync(clk, fd, fp, on);
+
+       put_posix_clock(clk);
+
+       return err;
+}
+
+static int posix_clock_mmap(struct file *fp, struct vm_area_struct *vma)
+{
+       struct posix_clock *clk = get_posix_clock(fp);
+       int err = -ENODEV;
+
+       if (!clk)
+               return -ENODEV;
+
+       if (clk->ops.mmap)
+               err = clk->ops.mmap(clk, vma);
+
+       put_posix_clock(clk);
+
+       return err;
+}
+
+static long posix_clock_ioctl(struct file *fp,
+                             unsigned int cmd, unsigned long arg)
+{
+       struct posix_clock *clk = get_posix_clock(fp);
+       int err = -ENOTTY;
+
+       if (!clk)
+               return -ENODEV;
+
+       if (clk->ops.ioctl)
+               err = clk->ops.ioctl(clk, cmd, arg);
+
+       put_posix_clock(clk);
+
+       return err;
+}
+
+#ifdef CONFIG_COMPAT
+static long posix_clock_compat_ioctl(struct file *fp,
+                                    unsigned int cmd, unsigned long arg)
+{
+       struct posix_clock *clk = get_posix_clock(fp);
+       int err = -ENOTTY;
+
+       if (!clk)
+               return -ENODEV;
+
+       if (clk->ops.ioctl)
+               err = clk->ops.ioctl(clk, cmd, arg);
+
+       put_posix_clock(clk);
+
+       return err;
+}
+#endif
+
+static int posix_clock_open(struct inode *inode, struct file *fp)
+{
+       int err;
+       struct posix_clock *clk =
+               container_of(inode->i_cdev, struct posix_clock, cdev);
+
+       mutex_lock(&clk->mutex);
+
+       if (clk->zombie) {
+               err = -ENODEV;
+               goto out;
+       }
+       if (clk->ops.open)
+               err = clk->ops.open(clk, fp->f_mode);
+       else
+               err = 0;
+
+       if (!err) {
+               kref_get(&clk->kref);
+               fp->private_data = clk;
+       }
+out:
+       mutex_unlock(&clk->mutex);
+       return err;
+}
+
+static int posix_clock_release(struct inode *inode, struct file *fp)
+{
+       struct posix_clock *clk = fp->private_data;
+       int err = 0;
+
+       if (clk->ops.release)
+               err = clk->ops.release(clk);
+
+       kref_put(&clk->kref, delete_clock);
+
+       fp->private_data = NULL;
+
+       return err;
+}
+
+static const struct file_operations posix_clock_file_operations = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .read           = posix_clock_read,
+       .poll           = posix_clock_poll,
+       .unlocked_ioctl = posix_clock_ioctl,
+       .open           = posix_clock_open,
+       .release        = posix_clock_release,
+       .fasync         = posix_clock_fasync,
+       .mmap           = posix_clock_mmap,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = posix_clock_compat_ioctl,
+#endif
+};
+
+int posix_clock_register(struct posix_clock *clk, dev_t devid)
+{
+       int err;
+
+       kref_init(&clk->kref);
+       mutex_init(&clk->mutex);
+
+       cdev_init(&clk->cdev, &posix_clock_file_operations);
+       clk->cdev.owner = clk->ops.owner;
+       err = cdev_add(&clk->cdev, devid, 1);
+       if (err)
+               goto no_cdev;
+
+       return err;
+no_cdev:
+       mutex_destroy(&clk->mutex);
+       return err;
+}
+EXPORT_SYMBOL_GPL(posix_clock_register);
+
+static void delete_clock(struct kref *kref)
+{
+       struct posix_clock *clk = container_of(kref, struct posix_clock, kref);
+       mutex_destroy(&clk->mutex);
+       if (clk->release)
+               clk->release(clk);
+}
+
+void posix_clock_unregister(struct posix_clock *clk)
+{
+       cdev_del(&clk->cdev);
+
+       mutex_lock(&clk->mutex);
+       clk->zombie = true;
+       mutex_unlock(&clk->mutex);
+
+       kref_put(&clk->kref, delete_clock);
+}
+EXPORT_SYMBOL_GPL(posix_clock_unregister);
+
+struct posix_clock_desc {
+       struct file *fp;
+       struct posix_clock *clk;
+};
+
+static int get_clock_desc(const clockid_t id, struct posix_clock_desc *cd)
+{
+       struct file *fp = fget(CLOCKID_TO_FD(id));
+       int err = -EINVAL;
+
+       if (!fp)
+               return err;
+
+       if (fp->f_op->open != posix_clock_open || !fp->private_data)
+               goto out;
+
+       cd->fp = fp;
+       cd->clk = get_posix_clock(fp);
+
+       err = cd->clk ? 0 : -ENODEV;
+out:
+       if (err)
+               fput(fp);
+       return err;
+}
+
+static void put_clock_desc(struct posix_clock_desc *cd)
+{
+       put_posix_clock(cd->clk);
+       fput(cd->fp);
+}
+
+static int pc_clock_adjtime(clockid_t id, struct timex *tx)
+{
+       struct posix_clock_desc cd;
+       int err;
+
+       err = get_clock_desc(id, &cd);
+       if (err)
+               return err;
+
+       if ((cd.fp->f_mode & FMODE_WRITE) == 0) {
+               err = -EACCES;
+               goto out;
+       }
+
+       if (cd.clk->ops.clock_adjtime)
+               err = cd.clk->ops.clock_adjtime(cd.clk, tx);
+       else
+               err = -EOPNOTSUPP;
+out:
+       put_clock_desc(&cd);
+
+       return err;
+}
+
+static int pc_clock_gettime(clockid_t id, struct timespec *ts)
+{
+       struct posix_clock_desc cd;
+       int err;
+
+       err = get_clock_desc(id, &cd);
+       if (err)
+               return err;
+
+       if (cd.clk->ops.clock_gettime)
+               err = cd.clk->ops.clock_gettime(cd.clk, ts);
+       else
+               err = -EOPNOTSUPP;
+
+       put_clock_desc(&cd);
+
+       return err;
+}
+
+static int pc_clock_getres(clockid_t id, struct timespec *ts)
+{
+       struct posix_clock_desc cd;
+       int err;
+
+       err = get_clock_desc(id, &cd);
+       if (err)
+               return err;
+
+       if (cd.clk->ops.clock_getres)
+               err = cd.clk->ops.clock_getres(cd.clk, ts);
+       else
+               err = -EOPNOTSUPP;
+
+       put_clock_desc(&cd);
+
+       return err;
+}
+
+static int pc_clock_settime(clockid_t id, const struct timespec *ts)
+{
+       struct posix_clock_desc cd;
+       int err;
+
+       err = get_clock_desc(id, &cd);
+       if (err)
+               return err;
+
+       if ((cd.fp->f_mode & FMODE_WRITE) == 0) {
+               err = -EACCES;
+               goto out;
+       }
+
+       if (cd.clk->ops.clock_settime)
+               err = cd.clk->ops.clock_settime(cd.clk, ts);
+       else
+               err = -EOPNOTSUPP;
+out:
+       put_clock_desc(&cd);
+
+       return err;
+}
+
+static int pc_timer_create(struct k_itimer *kit)
+{
+       clockid_t id = kit->it_clock;
+       struct posix_clock_desc cd;
+       int err;
+
+       err = get_clock_desc(id, &cd);
+       if (err)
+               return err;
+
+       if (cd.clk->ops.timer_create)
+               err = cd.clk->ops.timer_create(cd.clk, kit);
+       else
+               err = -EOPNOTSUPP;
+
+       put_clock_desc(&cd);
+
+       return err;
+}
+
+static int pc_timer_delete(struct k_itimer *kit)
+{
+       clockid_t id = kit->it_clock;
+       struct posix_clock_desc cd;
+       int err;
+
+       err = get_clock_desc(id, &cd);
+       if (err)
+               return err;
+
+       if (cd.clk->ops.timer_delete)
+               err = cd.clk->ops.timer_delete(cd.clk, kit);
+       else
+               err = -EOPNOTSUPP;
+
+       put_clock_desc(&cd);
+
+       return err;
+}
+
+static void pc_timer_gettime(struct k_itimer *kit, struct itimerspec *ts)
+{
+       clockid_t id = kit->it_clock;
+       struct posix_clock_desc cd;
+
+       if (get_clock_desc(id, &cd))
+               return;
+
+       if (cd.clk->ops.timer_gettime)
+               cd.clk->ops.timer_gettime(cd.clk, kit, ts);
+
+       put_clock_desc(&cd);
+}
+
+static int pc_timer_settime(struct k_itimer *kit, int flags,
+                           struct itimerspec *ts, struct itimerspec *old)
+{
+       clockid_t id = kit->it_clock;
+       struct posix_clock_desc cd;
+       int err;
+
+       err = get_clock_desc(id, &cd);
+       if (err)
+               return err;
+
+       if (cd.clk->ops.timer_settime)
+               err = cd.clk->ops.timer_settime(cd.clk, kit, flags, ts, old);
+       else
+               err = -EOPNOTSUPP;
+
+       put_clock_desc(&cd);
+
+       return err;
+}
+
+struct k_clock clock_posix_dynamic = {
+       .clock_getres   = pc_clock_getres,
+       .clock_set      = pc_clock_settime,
+       .clock_get      = pc_clock_gettime,
+       .clock_adj      = pc_clock_adjtime,
+       .timer_create   = pc_timer_create,
+       .timer_set      = pc_timer_settime,
+       .timer_del      = pc_timer_delete,
+       .timer_get      = pc_timer_gettime,
+};
index 48b2761..da800ff 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/percpu.h>
 #include <linux/profile.h>
 #include <linux/sched.h>
-#include <linux/tick.h>
 
 #include "tick-internal.h"
 
@@ -600,4 +599,14 @@ int tick_broadcast_oneshot_active(void)
        return tick_broadcast_device.mode == TICKDEV_MODE_ONESHOT;
 }
 
+/*
+ * Check whether the broadcast device supports oneshot.
+ */
+bool tick_broadcast_oneshot_available(void)
+{
+       struct clock_event_device *bc = tick_broadcast_device.evtdev;
+
+       return bc ? bc->features & CLOCK_EVT_FEAT_ONESHOT : false;
+}
+
 #endif
index 051bc80..119528d 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/percpu.h>
 #include <linux/profile.h>
 #include <linux/sched.h>
-#include <linux/tick.h>
 
 #include <asm/irq_regs.h>
 
@@ -51,7 +50,11 @@ int tick_is_oneshot_available(void)
 {
        struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev);
 
-       return dev && (dev->features & CLOCK_EVT_FEAT_ONESHOT);
+       if (!dev || !(dev->features & CLOCK_EVT_FEAT_ONESHOT))
+               return 0;
+       if (!(dev->features & CLOCK_EVT_FEAT_C3STOP))
+               return 1;
+       return tick_broadcast_oneshot_available();
 }
 
 /*
index 290eefb..1009b06 100644 (file)
@@ -1,6 +1,10 @@
 /*
  * tick internal variable and functions used by low/high res code
  */
+#include <linux/hrtimer.h>
+#include <linux/tick.h>
+
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BUILD
 
 #define TICK_DO_TIMER_NONE     -1
 #define TICK_DO_TIMER_BOOT     -2
@@ -36,6 +40,7 @@ extern void tick_shutdown_broadcast_oneshot(unsigned int *cpup);
 extern int tick_resume_broadcast_oneshot(struct clock_event_device *bc);
 extern int tick_broadcast_oneshot_active(void);
 extern void tick_check_oneshot_broadcast(int cpu);
+bool tick_broadcast_oneshot_available(void);
 # else /* BROADCAST */
 static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
 {
@@ -46,6 +51,7 @@ static inline void tick_broadcast_switch_to_oneshot(void) { }
 static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { }
 static inline int tick_broadcast_oneshot_active(void) { return 0; }
 static inline void tick_check_oneshot_broadcast(int cpu) { }
+static inline bool tick_broadcast_oneshot_available(void) { return true; }
 # endif /* !BROADCAST */
 
 #else /* !ONESHOT */
@@ -76,6 +82,7 @@ static inline int tick_resume_broadcast_oneshot(struct clock_event_device *bc)
        return 0;
 }
 static inline int tick_broadcast_oneshot_active(void) { return 0; }
+static inline bool tick_broadcast_oneshot_available(void) { return false; }
 #endif /* !TICK_ONESHOT */
 
 /*
@@ -132,3 +139,8 @@ static inline int tick_device_is_functional(struct clock_event_device *dev)
 {
        return !(dev->features & CLOCK_EVT_FEAT_DUMMY);
 }
+
+#endif
+
+extern void do_timer(unsigned long ticks);
+extern seqlock_t xtime_lock;
index 5cbc101..2d04411 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/percpu.h>
 #include <linux/profile.h>
 #include <linux/sched.h>
-#include <linux/tick.h>
 
 #include "tick-internal.h"
 
index c55ea24..d5097c4 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/percpu.h>
 #include <linux/profile.h>
 #include <linux/sched.h>
-#include <linux/tick.h>
 #include <linux/module.h>
 
 #include <asm/irq_regs.h>
index d27c756..3bd7e3d 100644 (file)
@@ -353,7 +353,7 @@ EXPORT_SYMBOL(do_gettimeofday);
  *
  * Sets the time of day to the new time and update NTP and notify hrtimers
  */
-int do_settimeofday(struct timespec *tv)
+int do_settimeofday(const struct timespec *tv)
 {
        struct timespec ts_delta;
        unsigned long flags;
@@ -387,6 +387,42 @@ int do_settimeofday(struct timespec *tv)
 
 EXPORT_SYMBOL(do_settimeofday);
 
+
+/**
+ * timekeeping_inject_offset - Adds or subtracts from the current time.
+ * @tv:                pointer to the timespec variable containing the offset
+ *
+ * Adds or subtracts an offset value from the current time.
+ */
+int timekeeping_inject_offset(struct timespec *ts)
+{
+       unsigned long flags;
+
+       if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC)
+               return -EINVAL;
+
+       write_seqlock_irqsave(&xtime_lock, flags);
+
+       timekeeping_forward_now();
+
+       xtime = timespec_add(xtime, *ts);
+       wall_to_monotonic = timespec_sub(wall_to_monotonic, *ts);
+
+       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();
+
+       return 0;
+}
+EXPORT_SYMBOL(timekeeping_inject_offset);
+
 /**
  * change_clocksource - Swaps clocksources if a new one is available
  *
@@ -779,7 +815,7 @@ static cycle_t logarithmic_accumulation(cycle_t offset, int shift)
  *
  * Called from the timer interrupt, must hold a write on xtime_lock.
  */
-void update_wall_time(void)
+static void update_wall_time(void)
 {
        struct clocksource *clock;
        cycle_t offset;
@@ -871,7 +907,7 @@ void update_wall_time(void)
  * getboottime - Return the real time of system boot.
  * @ts:                pointer to the timespec to be set
  *
- * Returns the time of day in a timespec.
+ * Returns the wall-time of boot in a timespec.
  *
  * This is based on the wall_to_monotonic offset and the total suspend
  * time. Calls to settimeofday will affect the value returned (which
@@ -889,6 +925,55 @@ void getboottime(struct timespec *ts)
 }
 EXPORT_SYMBOL_GPL(getboottime);
 
+
+/**
+ * get_monotonic_boottime - Returns monotonic time since boot
+ * @ts:                pointer to the timespec to be set
+ *
+ * Returns the monotonic time since boot in a timespec.
+ *
+ * This is similar to CLOCK_MONTONIC/ktime_get_ts, but also
+ * includes the time spent in suspend.
+ */
+void get_monotonic_boottime(struct timespec *ts)
+{
+       struct timespec tomono, sleep;
+       unsigned int seq;
+       s64 nsecs;
+
+       WARN_ON(timekeeping_suspended);
+
+       do {
+               seq = read_seqbegin(&xtime_lock);
+               *ts = xtime;
+               tomono = wall_to_monotonic;
+               sleep = total_sleep_time;
+               nsecs = timekeeping_get_ns();
+
+       } while (read_seqretry(&xtime_lock, seq));
+
+       set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec + sleep.tv_sec,
+                       ts->tv_nsec + tomono.tv_nsec + sleep.tv_nsec + nsecs);
+}
+EXPORT_SYMBOL_GPL(get_monotonic_boottime);
+
+/**
+ * ktime_get_boottime - Returns monotonic time since boot in a ktime
+ *
+ * Returns the monotonic time since boot in a ktime
+ *
+ * This is similar to CLOCK_MONTONIC/ktime_get, but also
+ * includes the time spent in suspend.
+ */
+ktime_t ktime_get_boottime(void)
+{
+       struct timespec ts;
+
+       get_monotonic_boottime(&ts);
+       return timespec_to_ktime(ts);
+}
+EXPORT_SYMBOL_GPL(ktime_get_boottime);
+
 /**
  * monotonic_to_bootbased - Convert the monotonic time to boot based.
  * @ts:                pointer to the timespec to be converted
@@ -910,11 +995,6 @@ struct timespec __current_kernel_time(void)
        return xtime;
 }
 
-struct timespec __get_wall_to_monotonic(void)
-{
-       return wall_to_monotonic;
-}
-
 struct timespec current_kernel_time(void)
 {
        struct timespec now;
@@ -946,3 +1026,48 @@ struct timespec get_monotonic_coarse(void)
                                now.tv_nsec + mono.tv_nsec);
        return now;
 }
+
+/*
+ * The 64-bit jiffies value is not atomic - you MUST NOT read it
+ * without sampling the sequence number in xtime_lock.
+ * jiffies is defined in the linker script...
+ */
+void do_timer(unsigned long ticks)
+{
+       jiffies_64 += ticks;
+       update_wall_time();
+       calc_global_load(ticks);
+}
+
+/**
+ * get_xtime_and_monotonic_and_sleep_offset() - get xtime, wall_to_monotonic,
+ *    and sleep offsets.
+ * @xtim:      pointer to timespec to be set with xtime
+ * @wtom:      pointer to timespec to be set with wall_to_monotonic
+ * @sleep:     pointer to timespec to be set with time in suspend
+ */
+void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim,
+                               struct timespec *wtom, struct timespec *sleep)
+{
+       unsigned long seq;
+
+       do {
+               seq = read_seqbegin(&xtime_lock);
+               *xtim = xtime;
+               *wtom = wall_to_monotonic;
+               *sleep = total_sleep_time;
+       } while (read_seqretry(&xtime_lock, seq));
+}
+
+/**
+ * xtime_update() - advances the timekeeping infrastructure
+ * @ticks:     number of ticks, that have elapsed since the last call.
+ *
+ * Must be called with interrupts disabled.
+ */
+void xtime_update(unsigned long ticks)
+{
+       write_seqlock(&xtime_lock);
+       do_timer(ticks);
+       write_sequnlock(&xtime_lock);
+}
index 32a19f9..3258455 100644 (file)
@@ -41,7 +41,7 @@ static void print_name_offset(struct seq_file *m, void *sym)
        char symname[KSYM_NAME_LEN];
 
        if (lookup_symbol_name((unsigned long)sym, symname) < 0)
-               SEQ_printf(m, "<%p>", sym);
+               SEQ_printf(m, "<%pK>", sym);
        else
                SEQ_printf(m, "%s", symname);
 }
@@ -112,7 +112,7 @@ next_one:
 static void
 print_base(struct seq_file *m, struct hrtimer_clock_base *base, u64 now)
 {
-       SEQ_printf(m, "  .base:       %p\n", base);
+       SEQ_printf(m, "  .base:       %pK\n", base);
        SEQ_printf(m, "  .index:      %d\n",
                        base->index);
        SEQ_printf(m, "  .resolution: %Lu nsecs\n",
index 43ca993..fd61986 100644 (file)
@@ -404,6 +404,11 @@ static void timer_stats_account_timer(struct timer_list *timer) {}
 
 static struct debug_obj_descr timer_debug_descr;
 
+static void *timer_debug_hint(void *addr)
+{
+       return ((struct timer_list *) addr)->function;
+}
+
 /*
  * fixup_init is called when:
  * - an active object is initialized
@@ -477,6 +482,7 @@ static int timer_fixup_free(void *addr, enum debug_obj_state state)
 
 static struct debug_obj_descr timer_debug_descr = {
        .name           = "timer_list",
+       .debug_hint     = timer_debug_hint,
        .fixup_init     = timer_fixup_init,
        .fixup_activate = timer_fixup_activate,
        .fixup_free     = timer_fixup_free,
@@ -959,20 +965,45 @@ EXPORT_SYMBOL(try_to_del_timer_sync);
  *
  * Synchronization rules: Callers must prevent restarting of the timer,
  * otherwise this function is meaningless. It must not be called from
- * hardirq contexts. The caller must not hold locks which would prevent
+ * interrupt contexts. The caller must not hold locks which would prevent
  * completion of the timer's handler. The timer's handler must not call
  * add_timer_on(). Upon exit the timer is not queued and the handler is
  * not running on any CPU.
  *
+ * Note: You must not hold locks that are held in interrupt context
+ *   while calling this function. Even if the lock has nothing to do
+ *   with the timer in question.  Here's why:
+ *
+ *    CPU0                             CPU1
+ *    ----                             ----
+ *                                   <SOFTIRQ>
+ *                                   call_timer_fn();
+ *                                     base->running_timer = mytimer;
+ *  spin_lock_irq(somelock);
+ *                                     <IRQ>
+ *                                        spin_lock(somelock);
+ *  del_timer_sync(mytimer);
+ *   while (base->running_timer == mytimer);
+ *
+ * Now del_timer_sync() will never return and never release somelock.
+ * The interrupt on the other CPU is waiting to grab somelock but
+ * it has interrupted the softirq that CPU0 is waiting to finish.
+ *
  * The function returns whether it has deactivated a pending timer or not.
  */
 int del_timer_sync(struct timer_list *timer)
 {
 #ifdef CONFIG_LOCKDEP
-       local_bh_disable();
+       unsigned long flags;
+
+       /*
+        * If lockdep gives a backtrace here, please reference
+        * the synchronization rules above.
+        */
+       local_irq_save(flags);
        lock_map_acquire(&timer->lockdep_map);
        lock_map_release(&timer->lockdep_map);
-       local_bh_enable();
+       local_irq_restore(flags);
 #endif
        /*
         * don't use it in hardirq context, because it
@@ -1293,19 +1324,6 @@ void run_local_timers(void)
        raise_softirq(TIMER_SOFTIRQ);
 }
 
-/*
- * The 64-bit jiffies value is not atomic - you MUST NOT read it
- * without sampling the sequence number in xtime_lock.
- * jiffies is defined in the linker script...
- */
-
-void do_timer(unsigned long ticks)
-{
-       jiffies_64 += ticks;
-       update_wall_time();
-       calc_global_load(ticks);
-}
-
 #ifdef __ARCH_WANT_SYS_ALARM
 
 /*
index 153562d..cbafed7 100644 (file)
@@ -138,6 +138,13 @@ void __trace_note_message(struct blk_trace *bt, const char *fmt, ...)
                     !blk_tracer_enabled))
                return;
 
+       /*
+        * If the BLK_TC_NOTIFY action mask isn't set, don't send any note
+        * message to the trace.
+        */
+       if (!(bt->act_mask & BLK_TC_NOTIFY))
+               return;
+
        local_irq_save(flags);
        buf = per_cpu_ptr(bt->msg_data, smp_processor_id());
        va_start(args, fmt);
@@ -1820,21 +1827,5 @@ void blk_fill_rwbs(char *rwbs, u32 rw, int bytes)
        rwbs[i] = '\0';
 }
 
-void blk_fill_rwbs_rq(char *rwbs, struct request *rq)
-{
-       int rw = rq->cmd_flags & 0x03;
-       int bytes;
-
-       if (rq->cmd_flags & REQ_DISCARD)
-               rw |= REQ_DISCARD;
-
-       if (rq->cmd_flags & REQ_SECURE)
-               rw |= REQ_SECURE;
-
-       bytes = blk_rq_bytes(rq);
-
-       blk_fill_rwbs(rwbs, rw, bytes);
-}
-
 #endif /* CONFIG_EVENT_TRACING */
 
index f3dadae..888b611 100644 (file)
@@ -3328,7 +3328,7 @@ static int start_graph_tracing(void)
        /* The cpu_boot init_task->ret_stack will never be freed */
        for_each_online_cpu(cpu) {
                if (!idle_task(cpu)->ret_stack)
-                       ftrace_graph_init_task(idle_task(cpu));
+                       ftrace_graph_init_idle_task(idle_task(cpu), cpu);
        }
 
        do {
@@ -3418,6 +3418,49 @@ void unregister_ftrace_graph(void)
        mutex_unlock(&ftrace_lock);
 }
 
+static DEFINE_PER_CPU(struct ftrace_ret_stack *, idle_ret_stack);
+
+static void
+graph_init_task(struct task_struct *t, struct ftrace_ret_stack *ret_stack)
+{
+       atomic_set(&t->tracing_graph_pause, 0);
+       atomic_set(&t->trace_overrun, 0);
+       t->ftrace_timestamp = 0;
+       /* make curr_ret_stack visable before we add the ret_stack */
+       smp_wmb();
+       t->ret_stack = ret_stack;
+}
+
+/*
+ * Allocate a return stack for the idle task. May be the first
+ * time through, or it may be done by CPU hotplug online.
+ */
+void ftrace_graph_init_idle_task(struct task_struct *t, int cpu)
+{
+       t->curr_ret_stack = -1;
+       /*
+        * The idle task has no parent, it either has its own
+        * stack or no stack at all.
+        */
+       if (t->ret_stack)
+               WARN_ON(t->ret_stack != per_cpu(idle_ret_stack, cpu));
+
+       if (ftrace_graph_active) {
+               struct ftrace_ret_stack *ret_stack;
+
+               ret_stack = per_cpu(idle_ret_stack, cpu);
+               if (!ret_stack) {
+                       ret_stack = kmalloc(FTRACE_RETFUNC_DEPTH
+                                           * sizeof(struct ftrace_ret_stack),
+                                           GFP_KERNEL);
+                       if (!ret_stack)
+                               return;
+                       per_cpu(idle_ret_stack, cpu) = ret_stack;
+               }
+               graph_init_task(t, ret_stack);
+       }
+}
+
 /* Allocate a return stack for newly created task */
 void ftrace_graph_init_task(struct task_struct *t)
 {
@@ -3433,12 +3476,7 @@ void ftrace_graph_init_task(struct task_struct *t)
                                GFP_KERNEL);
                if (!ret_stack)
                        return;
-               atomic_set(&t->tracing_graph_pause, 0);
-               atomic_set(&t->trace_overrun, 0);
-               t->ftrace_timestamp = 0;
-               /* make curr_ret_stack visable before we add the ret_stack */
-               smp_wmb();
-               t->ret_stack = ret_stack;
+               graph_init_task(t, ret_stack);
        }
 }
 
index bd1c35a..db7b439 100644 (file)
@@ -5,7 +5,6 @@
  */
 #include <linux/ring_buffer.h>
 #include <linux/trace_clock.h>
-#include <linux/ftrace_irq.h>
 #include <linux/spinlock.h>
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
@@ -1429,6 +1428,17 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size)
 }
 EXPORT_SYMBOL_GPL(ring_buffer_resize);
 
+void ring_buffer_change_overwrite(struct ring_buffer *buffer, int val)
+{
+       mutex_lock(&buffer->mutex);
+       if (val)
+               buffer->flags |= RB_FL_OVERWRITE;
+       else
+               buffer->flags &= ~RB_FL_OVERWRITE;
+       mutex_unlock(&buffer->mutex);
+}
+EXPORT_SYMBOL_GPL(ring_buffer_change_overwrite);
+
 static inline void *
 __rb_data_page_index(struct buffer_data_page *bpage, unsigned index)
 {
@@ -2162,11 +2172,19 @@ rb_reserve_next_event(struct ring_buffer *buffer,
        if (likely(ts >= cpu_buffer->write_stamp)) {
                delta = diff;
                if (unlikely(test_time_stamp(delta))) {
+                       int local_clock_stable = 1;
+#ifdef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK
+                       local_clock_stable = sched_clock_stable;
+#endif
                        WARN_ONCE(delta > (1ULL << 59),
-                                 KERN_WARNING "Delta way too big! %llu ts=%llu write stamp = %llu\n",
+                                 KERN_WARNING "Delta way too big! %llu ts=%llu write stamp = %llu\n%s",
                                  (unsigned long long)delta,
                                  (unsigned long long)ts,
-                                 (unsigned long long)cpu_buffer->write_stamp);
+                                 (unsigned long long)cpu_buffer->write_stamp,
+                                 local_clock_stable ? "" :
+                                 "If you just came from a suspend/resume,\n"
+                                 "please switch to the trace global clock:\n"
+                                 "  echo global > /sys/kernel/debug/tracing/trace_clock\n");
                        add_timestamp = 1;
                }
        }
index dc53ecb..9541c27 100644 (file)
@@ -41,8 +41,6 @@
 #include "trace.h"
 #include "trace_output.h"
 
-#define TRACE_BUFFER_FLAGS     (RB_FL_OVERWRITE)
-
 /*
  * On boot up, the ring buffer is set to the minimum size, so that
  * we do not waste memory on systems that are not using tracing.
@@ -340,7 +338,7 @@ static DECLARE_WAIT_QUEUE_HEAD(trace_wait);
 /* trace_flags holds trace_options default values */
 unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK |
        TRACE_ITER_ANNOTATE | TRACE_ITER_CONTEXT_INFO | TRACE_ITER_SLEEP_TIME |
-       TRACE_ITER_GRAPH_TIME | TRACE_ITER_RECORD_CMD;
+       TRACE_ITER_GRAPH_TIME | TRACE_ITER_RECORD_CMD | TRACE_ITER_OVERWRITE;
 
 static int trace_stop_count;
 static DEFINE_SPINLOCK(tracing_start_lock);
@@ -425,6 +423,7 @@ static const char *trace_options[] = {
        "sleep-time",
        "graph-time",
        "record-cmd",
+       "overwrite",
        NULL
 };
 
@@ -780,6 +779,11 @@ __acquires(kernel_lock)
                tracing_reset_online_cpus(tr);
 
                current_trace = type;
+
+               /* If we expanded the buffers, make sure the max is expanded too */
+               if (ring_buffer_expanded && type->use_max_tr)
+                       ring_buffer_resize(max_tr.buffer, trace_buf_size);
+
                /* the test is responsible for initializing and enabling */
                pr_info("Testing tracer %s: ", type->name);
                ret = type->selftest(type, tr);
@@ -792,6 +796,10 @@ __acquires(kernel_lock)
                /* Only reset on passing, to avoid touching corrupted buffers */
                tracing_reset_online_cpus(tr);
 
+               /* Shrink the max buffer again */
+               if (ring_buffer_expanded && type->use_max_tr)
+                       ring_buffer_resize(max_tr.buffer, 1);
+
                printk(KERN_CONT "PASSED\n");
        }
 #endif
@@ -1102,7 +1110,6 @@ tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags,
 
        entry->preempt_count            = pc & 0xff;
        entry->pid                      = (tsk) ? tsk->pid : 0;
-       entry->lock_depth               = (tsk) ? tsk->lock_depth : 0;
        entry->flags =
 #ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT
                (irqs_disabled_flags(flags) ? TRACE_FLAG_IRQS_OFF : 0) |
@@ -1749,10 +1756,9 @@ static void print_lat_help_header(struct seq_file *m)
        seq_puts(m, "#                | / _----=> need-resched    \n");
        seq_puts(m, "#                || / _---=> hardirq/softirq \n");
        seq_puts(m, "#                ||| / _--=> preempt-depth   \n");
-       seq_puts(m, "#                |||| /_--=> lock-depth       \n");
-       seq_puts(m, "#                |||||/     delay             \n");
-       seq_puts(m, "#  cmd     pid   |||||| time  |   caller      \n");
-       seq_puts(m, "#     \\   /      ||||||   \\   |   /           \n");
+       seq_puts(m, "#                |||| /     delay             \n");
+       seq_puts(m, "#  cmd     pid   ||||| time  |   caller      \n");
+       seq_puts(m, "#     \\   /      |||||  \\    |   /           \n");
 }
 
 static void print_func_help_header(struct seq_file *m)
@@ -2529,6 +2535,9 @@ static void set_tracer_flags(unsigned int mask, int enabled)
 
        if (mask == TRACE_ITER_RECORD_CMD)
                trace_event_enable_cmd_record(enabled);
+
+       if (mask == TRACE_ITER_OVERWRITE)
+               ring_buffer_change_overwrite(global_trace.buffer, enabled);
 }
 
 static ssize_t
@@ -2710,6 +2719,10 @@ tracing_ctrl_write(struct file *filp, const char __user *ubuf,
 
        mutex_lock(&trace_types_lock);
        if (tracer_enabled ^ val) {
+
+               /* Only need to warn if this is used to change the state */
+               WARN_ONCE(1, "tracing_enabled is deprecated. Use tracing_on");
+
                if (val) {
                        tracer_enabled = 1;
                        if (current_trace->start)
@@ -4551,9 +4564,11 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
 __init static int tracer_alloc_buffers(void)
 {
        int ring_buf_size;
+       enum ring_buffer_flags rb_flags;
        int i;
        int ret = -ENOMEM;
 
+
        if (!alloc_cpumask_var(&tracing_buffer_mask, GFP_KERNEL))
                goto out;
 
@@ -4566,12 +4581,13 @@ __init static int tracer_alloc_buffers(void)
        else
                ring_buf_size = 1;
 
+       rb_flags = trace_flags & TRACE_ITER_OVERWRITE ? RB_FL_OVERWRITE : 0;
+
        cpumask_copy(tracing_buffer_mask, cpu_possible_mask);
        cpumask_copy(tracing_cpumask, cpu_all_mask);
 
        /* TODO: make the number of buffers hot pluggable with CPUS */
-       global_trace.buffer = ring_buffer_alloc(ring_buf_size,
-                                                  TRACE_BUFFER_FLAGS);
+       global_trace.buffer = ring_buffer_alloc(ring_buf_size, rb_flags);
        if (!global_trace.buffer) {
                printk(KERN_ERR "tracer: failed to allocate ring buffer!\n");
                WARN_ON(1);
@@ -4581,7 +4597,7 @@ __init static int tracer_alloc_buffers(void)
 
 
 #ifdef CONFIG_TRACER_MAX_TRACE
-       max_tr.buffer = ring_buffer_alloc(1, TRACE_BUFFER_FLAGS);
+       max_tr.buffer = ring_buffer_alloc(1, rb_flags);
        if (!max_tr.buffer) {
                printk(KERN_ERR "tracer: failed to allocate max ring buffer!\n");
                WARN_ON(1);
index 9021f8c..5e9dfc6 100644 (file)
@@ -272,8 +272,8 @@ struct tracer {
        /* If you handled the flag setting, return 0 */
        int                     (*set_flag)(u32 old_flags, u32 bit, int set);
        struct tracer           *next;
-       int                     print_max;
        struct tracer_flags     *flags;
+       int                     print_max;
        int                     use_max_tr;
 };
 
@@ -606,6 +606,7 @@ enum trace_iterator_flags {
        TRACE_ITER_SLEEP_TIME           = 0x40000,
        TRACE_ITER_GRAPH_TIME           = 0x80000,
        TRACE_ITER_RECORD_CMD           = 0x100000,
+       TRACE_ITER_OVERWRITE            = 0x200000,
 };
 
 /*
@@ -661,8 +662,10 @@ struct ftrace_event_field {
 };
 
 struct event_filter {
-       int                     n_preds;
-       struct filter_pred      **preds;
+       int                     n_preds;        /* Number assigned */
+       int                     a_preds;        /* allocated */
+       struct filter_pred      *preds;
+       struct filter_pred      *root;
        char                    *filter_string;
 };
 
@@ -674,11 +677,23 @@ struct event_subsystem {
        int                     nr_events;
 };
 
+#define FILTER_PRED_INVALID    ((unsigned short)-1)
+#define FILTER_PRED_IS_RIGHT   (1 << 15)
+#define FILTER_PRED_FOLD       (1 << 15)
+
+/*
+ * The max preds is the size of unsigned short with
+ * two flags at the MSBs. One bit is used for both the IS_RIGHT
+ * and FOLD flags. The other is reserved.
+ *
+ * 2^14 preds is way more than enough.
+ */
+#define MAX_FILTER_PRED                16384
+
 struct filter_pred;
 struct regex;
 
-typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event,
-                                int val1, int val2);
+typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event);
 
 typedef int (*regex_match_func)(char *str, struct regex *r, int len);
 
@@ -700,11 +715,23 @@ struct filter_pred {
        filter_pred_fn_t        fn;
        u64                     val;
        struct regex            regex;
-       char                    *field_name;
+       /*
+        * Leaf nodes use field_name, ops is used by AND and OR
+        * nodes. The field_name is always freed when freeing a pred.
+        * We can overload field_name for ops and have it freed
+        * as well.
+        */
+       union {
+               char            *field_name;
+               unsigned short  *ops;
+       };
        int                     offset;
        int                     not;
        int                     op;
-       int                     pop_n;
+       unsigned short          index;
+       unsigned short          parent;
+       unsigned short          left;
+       unsigned short          right;
 };
 
 extern struct list_head ftrace_common_fields;
index 6cf2237..1516cb3 100644 (file)
@@ -109,12 +109,12 @@ FTRACE_ENTRY(funcgraph_exit, ftrace_graph_ret_entry,
  */
 #define FTRACE_CTX_FIELDS                                      \
        __field(        unsigned int,   prev_pid        )       \
+       __field(        unsigned int,   next_pid        )       \
+       __field(        unsigned int,   next_cpu        )       \
        __field(        unsigned char,  prev_prio       )       \
        __field(        unsigned char,  prev_state      )       \
-       __field(        unsigned int,   next_pid        )       \
        __field(        unsigned char,  next_prio       )       \
-       __field(        unsigned char,  next_state      )       \
-       __field(        unsigned int,   next_cpu        )
+       __field(        unsigned char,  next_state      )
 
 FTRACE_ENTRY(context_switch, ctx_switch_entry,
 
index 35fde09..e88f74f 100644 (file)
@@ -116,7 +116,6 @@ static int trace_define_common_fields(void)
        __common_field(unsigned char, flags);
        __common_field(unsigned char, preempt_count);
        __common_field(int, pid);
-       __common_field(int, lock_depth);
 
        return ret;
 }
@@ -326,6 +325,7 @@ int trace_set_clr_event(const char *system, const char *event, int set)
 {
        return __ftrace_set_clr_event(NULL, system, event, set);
 }
+EXPORT_SYMBOL_GPL(trace_set_clr_event);
 
 /* 128 should be much more than enough */
 #define EVENT_BUF_SIZE         127
@@ -1284,7 +1284,7 @@ trace_create_file_ops(struct module *mod)
 static void trace_module_add_events(struct module *mod)
 {
        struct ftrace_module_file_ops *file_ops = NULL;
-       struct ftrace_event_call *call, *start, *end;
+       struct ftrace_event_call **call, **start, **end;
 
        start = mod->trace_events;
        end = mod->trace_events + mod->num_trace_events;
@@ -1297,7 +1297,7 @@ static void trace_module_add_events(struct module *mod)
                return;
 
        for_each_event(call, start, end) {
-               __trace_add_event_call(call, mod,
+               __trace_add_event_call(*call, mod,
                                       &file_ops->id, &file_ops->enable,
                                       &file_ops->filter, &file_ops->format);
        }
@@ -1367,8 +1367,8 @@ static struct notifier_block trace_module_nb = {
        .priority = 0,
 };
 
-extern struct ftrace_event_call __start_ftrace_events[];
-extern struct ftrace_event_call __stop_ftrace_events[];
+extern struct ftrace_event_call *__start_ftrace_events[];
+extern struct ftrace_event_call *__stop_ftrace_events[];
 
 static char bootup_event_buf[COMMAND_LINE_SIZE] __initdata;
 
@@ -1384,7 +1384,7 @@ __setup("trace_event=", setup_trace_event);
 
 static __init int event_trace_init(void)
 {
-       struct ftrace_event_call *call;
+       struct ftrace_event_call **call;
        struct dentry *d_tracer;
        struct dentry *entry;
        struct dentry *d_events;
@@ -1430,7 +1430,7 @@ static __init int event_trace_init(void)
                pr_warning("tracing: Failed to allocate common fields");
 
        for_each_event(call, __start_ftrace_events, __stop_ftrace_events) {
-               __trace_add_event_call(call, NULL, &ftrace_event_id_fops,
+               __trace_add_event_call(*call, NULL, &ftrace_event_id_fops,
                                       &ftrace_enable_fops,
                                       &ftrace_event_filter_fops,
                                       &ftrace_event_format_fops);
index 36d4010..3249b4f 100644 (file)
@@ -123,9 +123,13 @@ struct filter_parse_state {
        } operand;
 };
 
+struct pred_stack {
+       struct filter_pred      **preds;
+       int                     index;
+};
+
 #define DEFINE_COMPARISON_PRED(type)                                   \
-static int filter_pred_##type(struct filter_pred *pred, void *event,   \
-                             int val1, int val2)                       \
+static int filter_pred_##type(struct filter_pred *pred, void *event)   \
 {                                                                      \
        type *addr = (type *)(event + pred->offset);                    \
        type val = (type)pred->val;                                     \
@@ -152,8 +156,7 @@ static int filter_pred_##type(struct filter_pred *pred, void *event,        \
 }
 
 #define DEFINE_EQUALITY_PRED(size)                                     \
-static int filter_pred_##size(struct filter_pred *pred, void *event,   \
-                             int val1, int val2)                       \
+static int filter_pred_##size(struct filter_pred *pred, void *event)   \
 {                                                                      \
        u##size *addr = (u##size *)(event + pred->offset);              \
        u##size val = (u##size)pred->val;                               \
@@ -178,23 +181,8 @@ DEFINE_EQUALITY_PRED(32);
 DEFINE_EQUALITY_PRED(16);
 DEFINE_EQUALITY_PRED(8);
 
-static int filter_pred_and(struct filter_pred *pred __attribute((unused)),
-                          void *event __attribute((unused)),
-                          int val1, int val2)
-{
-       return val1 && val2;
-}
-
-static int filter_pred_or(struct filter_pred *pred __attribute((unused)),
-                         void *event __attribute((unused)),
-                         int val1, int val2)
-{
-       return val1 || val2;
-}
-
 /* Filter predicate for fixed sized arrays of characters */
-static int filter_pred_string(struct filter_pred *pred, void *event,
-                             int val1, int val2)
+static int filter_pred_string(struct filter_pred *pred, void *event)
 {
        char *addr = (char *)(event + pred->offset);
        int cmp, match;
@@ -207,8 +195,7 @@ static int filter_pred_string(struct filter_pred *pred, void *event,
 }
 
 /* Filter predicate for char * pointers */
-static int filter_pred_pchar(struct filter_pred *pred, void *event,
-                            int val1, int val2)
+static int filter_pred_pchar(struct filter_pred *pred, void *event)
 {
        char **addr = (char **)(event + pred->offset);
        int cmp, match;
@@ -231,8 +218,7 @@ static int filter_pred_pchar(struct filter_pred *pred, void *event,
  * and add it to the address of the entry, and at last we have
  * the address of the string.
  */
-static int filter_pred_strloc(struct filter_pred *pred, void *event,
-                             int val1, int val2)
+static int filter_pred_strloc(struct filter_pred *pred, void *event)
 {
        u32 str_item = *(u32 *)(event + pred->offset);
        int str_loc = str_item & 0xffff;
@@ -247,8 +233,7 @@ static int filter_pred_strloc(struct filter_pred *pred, void *event,
        return match;
 }
 
-static int filter_pred_none(struct filter_pred *pred, void *event,
-                           int val1, int val2)
+static int filter_pred_none(struct filter_pred *pred, void *event)
 {
        return 0;
 }
@@ -377,32 +362,147 @@ static void filter_build_regex(struct filter_pred *pred)
        pred->not ^= not;
 }
 
+enum move_type {
+       MOVE_DOWN,
+       MOVE_UP_FROM_LEFT,
+       MOVE_UP_FROM_RIGHT
+};
+
+static struct filter_pred *
+get_pred_parent(struct filter_pred *pred, struct filter_pred *preds,
+               int index, enum move_type *move)
+{
+       if (pred->parent & FILTER_PRED_IS_RIGHT)
+               *move = MOVE_UP_FROM_RIGHT;
+       else
+               *move = MOVE_UP_FROM_LEFT;
+       pred = &preds[pred->parent & ~FILTER_PRED_IS_RIGHT];
+
+       return pred;
+}
+
+/*
+ * A series of AND or ORs where found together. Instead of
+ * climbing up and down the tree branches, an array of the
+ * ops were made in order of checks. We can just move across
+ * the array and short circuit if needed.
+ */
+static int process_ops(struct filter_pred *preds,
+                      struct filter_pred *op, void *rec)
+{
+       struct filter_pred *pred;
+       int type;
+       int match;
+       int i;
+
+       /*
+        * Micro-optimization: We set type to true if op
+        * is an OR and false otherwise (AND). Then we
+        * just need to test if the match is equal to
+        * the type, and if it is, we can short circuit the
+        * rest of the checks:
+        *
+        * if ((match && op->op == OP_OR) ||
+        *     (!match && op->op == OP_AND))
+        *        return match;
+        */
+       type = op->op == OP_OR;
+
+       for (i = 0; i < op->val; i++) {
+               pred = &preds[op->ops[i]];
+               match = pred->fn(pred, rec);
+               if (!!match == type)
+                       return match;
+       }
+       return match;
+}
+
 /* return 1 if event matches, 0 otherwise (discard) */
 int filter_match_preds(struct event_filter *filter, void *rec)
 {
-       int match, top = 0, val1 = 0, val2 = 0;
-       int stack[MAX_FILTER_PRED];
+       int match = -1;
+       enum move_type move = MOVE_DOWN;
+       struct filter_pred *preds;
        struct filter_pred *pred;
-       int i;
+       struct filter_pred *root;
+       int n_preds;
+       int done = 0;
+
+       /* no filter is considered a match */
+       if (!filter)
+               return 1;
+
+       n_preds = filter->n_preds;
+
+       if (!n_preds)
+               return 1;
+
+       /*
+        * n_preds, root and filter->preds are protect with preemption disabled.
+        */
+       preds = rcu_dereference_sched(filter->preds);
+       root = rcu_dereference_sched(filter->root);
+       if (!root)
+               return 1;
+
+       pred = root;
 
-       for (i = 0; i < filter->n_preds; i++) {
-               pred = filter->preds[i];
-               if (!pred->pop_n) {
-                       match = pred->fn(pred, rec, val1, val2);
-                       stack[top++] = match;
+       /* match is currently meaningless */
+       match = -1;
+
+       do {
+               switch (move) {
+               case MOVE_DOWN:
+                       /* only AND and OR have children */
+                       if (pred->left != FILTER_PRED_INVALID) {
+                               /* If ops is set, then it was folded. */
+                               if (!pred->ops) {
+                                       /* keep going to down the left side */
+                                       pred = &preds[pred->left];
+                                       continue;
+                               }
+                               /* We can treat folded ops as a leaf node */
+                               match = process_ops(preds, pred, rec);
+                       } else
+                               match = pred->fn(pred, rec);
+                       /* If this pred is the only pred */
+                       if (pred == root)
+                               break;
+                       pred = get_pred_parent(pred, preds,
+                                              pred->parent, &move);
+                       continue;
+               case MOVE_UP_FROM_LEFT:
+                       /*
+                        * Check for short circuits.
+                        *
+                        * Optimization: !!match == (pred->op == OP_OR)
+                        *   is the same as:
+                        * if ((match && pred->op == OP_OR) ||
+                        *     (!match && pred->op == OP_AND))
+                        */
+                       if (!!match == (pred->op == OP_OR)) {
+                               if (pred == root)
+                                       break;
+                               pred = get_pred_parent(pred, preds,
+                                                      pred->parent, &move);
+                               continue;
+                       }
+                       /* now go down the right side of the tree. */
+                       pred = &preds[pred->right];
+                       move = MOVE_DOWN;
+                       continue;
+               case MOVE_UP_FROM_RIGHT:
+                       /* We finished this equation. */
+                       if (pred == root)
+                               break;
+                       pred = get_pred_parent(pred, preds,
+                                              pred->parent, &move);
                        continue;
                }
-               if (pred->pop_n > top) {
-                       WARN_ON_ONCE(1);
-                       return 0;
-               }
-               val1 = stack[--top];
-               val2 = stack[--top];
-               match = pred->fn(pred, rec, val1, val2);
-               stack[top++] = match;
-       }
+               done = 1;
+       } while (!done);
 
-       return stack[--top];
+       return match;
 }
 EXPORT_SYMBOL_GPL(filter_match_preds);
 
@@ -414,6 +514,9 @@ static void parse_error(struct filter_parse_state *ps, int err, int pos)
 
 static void remove_filter_string(struct event_filter *filter)
 {
+       if (!filter)
+               return;
+
        kfree(filter->filter_string);
        filter->filter_string = NULL;
 }
@@ -473,9 +576,10 @@ static void append_filter_err(struct filter_parse_state *ps,
 
 void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s)
 {
-       struct event_filter *filter = call->filter;
+       struct event_filter *filter;
 
        mutex_lock(&event_mutex);
+       filter = call->filter;
        if (filter && filter->filter_string)
                trace_seq_printf(s, "%s\n", filter->filter_string);
        else
@@ -486,9 +590,10 @@ void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s)
 void print_subsystem_event_filter(struct event_subsystem *system,
                                  struct trace_seq *s)
 {
-       struct event_filter *filter = system->filter;
+       struct event_filter *filter;
 
        mutex_lock(&event_mutex);
+       filter = system->filter;
        if (filter && filter->filter_string)
                trace_seq_printf(s, "%s\n", filter->filter_string);
        else
@@ -539,10 +644,58 @@ static void filter_clear_pred(struct filter_pred *pred)
        pred->regex.len = 0;
 }
 
-static int filter_set_pred(struct filter_pred *dest,
+static int __alloc_pred_stack(struct pred_stack *stack, int n_preds)
+{
+       stack->preds = kzalloc(sizeof(*stack->preds)*(n_preds + 1), GFP_KERNEL);
+       if (!stack->preds)
+               return -ENOMEM;
+       stack->index = n_preds;
+       return 0;
+}
+
+static void __free_pred_stack(struct pred_stack *stack)
+{
+       kfree(stack->preds);
+       stack->index = 0;
+}
+
+static int __push_pred_stack(struct pred_stack *stack,
+                            struct filter_pred *pred)
+{
+       int index = stack->index;
+
+       if (WARN_ON(index == 0))
+               return -ENOSPC;
+
+       stack->preds[--index] = pred;
+       stack->index = index;
+       return 0;
+}
+
+static struct filter_pred *
+__pop_pred_stack(struct pred_stack *stack)
+{
+       struct filter_pred *pred;
+       int index = stack->index;
+
+       pred = stack->preds[index++];
+       if (!pred)
+               return NULL;
+
+       stack->index = index;
+       return pred;
+}
+
+static int filter_set_pred(struct event_filter *filter,
+                          int idx,
+                          struct pred_stack *stack,
                           struct filter_pred *src,
                           filter_pred_fn_t fn)
 {
+       struct filter_pred *dest = &filter->preds[idx];
+       struct filter_pred *left;
+       struct filter_pred *right;
+
        *dest = *src;
        if (src->field_name) {
                dest->field_name = kstrdup(src->field_name, GFP_KERNEL);
@@ -550,116 +703,140 @@ static int filter_set_pred(struct filter_pred *dest,
                        return -ENOMEM;
        }
        dest->fn = fn;
+       dest->index = idx;
 
-       return 0;
+       if (dest->op == OP_OR || dest->op == OP_AND) {
+               right = __pop_pred_stack(stack);
+               left = __pop_pred_stack(stack);
+               if (!left || !right)
+                       return -EINVAL;
+               /*
+                * If both children can be folded
+                * and they are the same op as this op or a leaf,
+                * then this op can be folded.
+                */
+               if (left->index & FILTER_PRED_FOLD &&
+                   (left->op == dest->op ||
+                    left->left == FILTER_PRED_INVALID) &&
+                   right->index & FILTER_PRED_FOLD &&
+                   (right->op == dest->op ||
+                    right->left == FILTER_PRED_INVALID))
+                       dest->index |= FILTER_PRED_FOLD;
+
+               dest->left = left->index & ~FILTER_PRED_FOLD;
+               dest->right = right->index & ~FILTER_PRED_FOLD;
+               left->parent = dest->index & ~FILTER_PRED_FOLD;
+               right->parent = dest->index | FILTER_PRED_IS_RIGHT;
+       } else {
+               /*
+                * Make dest->left invalid to be used as a quick
+                * way to know this is a leaf node.
+                */
+               dest->left = FILTER_PRED_INVALID;
+
+               /* All leafs allow folding the parent ops. */
+               dest->index |= FILTER_PRED_FOLD;
+       }
+
+       return __push_pred_stack(stack, dest);
 }
 
-static void filter_disable_preds(struct ftrace_event_call *call)
+static void __free_preds(struct event_filter *filter)
 {
-       struct event_filter *filter = call->filter;
        int i;
 
-       call->flags &= ~TRACE_EVENT_FL_FILTERED;
+       if (filter->preds) {
+               for (i = 0; i < filter->a_preds; i++)
+                       kfree(filter->preds[i].field_name);
+               kfree(filter->preds);
+               filter->preds = NULL;
+       }
+       filter->a_preds = 0;
        filter->n_preds = 0;
-
-       for (i = 0; i < MAX_FILTER_PRED; i++)
-               filter->preds[i]->fn = filter_pred_none;
 }
 
-static void __free_preds(struct event_filter *filter)
+static void filter_disable(struct ftrace_event_call *call)
 {
-       int i;
+       call->flags &= ~TRACE_EVENT_FL_FILTERED;
+}
 
+static void __free_filter(struct event_filter *filter)
+{
        if (!filter)
                return;
 
-       for (i = 0; i < MAX_FILTER_PRED; i++) {
-               if (filter->preds[i])
-                       filter_free_pred(filter->preds[i]);
-       }
-       kfree(filter->preds);
+       __free_preds(filter);
        kfree(filter->filter_string);
        kfree(filter);
 }
 
+/*
+ * Called when destroying the ftrace_event_call.
+ * The call is being freed, so we do not need to worry about
+ * the call being currently used. This is for module code removing
+ * the tracepoints from within it.
+ */
 void destroy_preds(struct ftrace_event_call *call)
 {
-       __free_preds(call->filter);
+       __free_filter(call->filter);
        call->filter = NULL;
-       call->flags &= ~TRACE_EVENT_FL_FILTERED;
 }
 
-static struct event_filter *__alloc_preds(void)
+static struct event_filter *__alloc_filter(void)
 {
        struct event_filter *filter;
+
+       filter = kzalloc(sizeof(*filter), GFP_KERNEL);
+       return filter;
+}
+
+static int __alloc_preds(struct event_filter *filter, int n_preds)
+{
        struct filter_pred *pred;
        int i;
 
-       filter = kzalloc(sizeof(*filter), GFP_KERNEL);
-       if (!filter)
-               return ERR_PTR(-ENOMEM);
+       if (filter->preds)
+               __free_preds(filter);
 
-       filter->n_preds = 0;
+       filter->preds =
+               kzalloc(sizeof(*filter->preds) * n_preds, GFP_KERNEL);
 
-       filter->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), GFP_KERNEL);
        if (!filter->preds)
-               goto oom;
+               return -ENOMEM;
 
-       for (i = 0; i < MAX_FILTER_PRED; i++) {
-               pred = kzalloc(sizeof(*pred), GFP_KERNEL);
-               if (!pred)
-                       goto oom;
+       filter->a_preds = n_preds;
+       filter->n_preds = 0;
+
+       for (i = 0; i < n_preds; i++) {
+               pred = &filter->preds[i];
                pred->fn = filter_pred_none;
-               filter->preds[i] = pred;
        }
 
-       return filter;
-
-oom:
-       __free_preds(filter);
-       return ERR_PTR(-ENOMEM);
-}
-
-static int init_preds(struct ftrace_event_call *call)
-{
-       if (call->filter)
-               return 0;
-
-       call->flags &= ~TRACE_EVENT_FL_FILTERED;
-       call->filter = __alloc_preds();
-       if (IS_ERR(call->filter))
-               return PTR_ERR(call->filter);
-
        return 0;
 }
 
-static int init_subsystem_preds(struct event_subsystem *system)
+static void filter_free_subsystem_preds(struct event_subsystem *system)
 {
        struct ftrace_event_call *call;
-       int err;
 
        list_for_each_entry(call, &ftrace_events, list) {
                if (strcmp(call->class->system, system->name) != 0)
                        continue;
 
-               err = init_preds(call);
-               if (err)
-                       return err;
+               filter_disable(call);
+               remove_filter_string(call->filter);
        }
-
-       return 0;
 }
 
-static void filter_free_subsystem_preds(struct event_subsystem *system)
+static void filter_free_subsystem_filters(struct event_subsystem *system)
 {
        struct ftrace_event_call *call;
 
        list_for_each_entry(call, &ftrace_events, list) {
                if (strcmp(call->class->system, system->name) != 0)
                        continue;
-
-               filter_disable_preds(call);
-               remove_filter_string(call->filter);
+               __free_filter(call->filter);
+               call->filter = NULL;
        }
 }
 
@@ -667,18 +844,19 @@ static int filter_add_pred_fn(struct filter_parse_state *ps,
                              struct ftrace_event_call *call,
                              struct event_filter *filter,
                              struct filter_pred *pred,
+                             struct pred_stack *stack,
                              filter_pred_fn_t fn)
 {
        int idx, err;
 
-       if (filter->n_preds == MAX_FILTER_PRED) {
+       if (WARN_ON(filter->n_preds == filter->a_preds)) {
                parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0);
                return -ENOSPC;
        }
 
        idx = filter->n_preds;
-       filter_clear_pred(filter->preds[idx]);
-       err = filter_set_pred(filter->preds[idx], pred, fn);
+       filter_clear_pred(&filter->preds[idx]);
+       err = filter_set_pred(filter, idx, stack, pred, fn);
        if (err)
                return err;
 
@@ -763,6 +941,7 @@ static int filter_add_pred(struct filter_parse_state *ps,
                           struct ftrace_event_call *call,
                           struct event_filter *filter,
                           struct filter_pred *pred,
+                          struct pred_stack *stack,
                           bool dry_run)
 {
        struct ftrace_event_field *field;
@@ -770,17 +949,12 @@ static int filter_add_pred(struct filter_parse_state *ps,
        unsigned long long val;
        int ret;
 
-       pred->fn = filter_pred_none;
+       fn = pred->fn = filter_pred_none;
 
-       if (pred->op == OP_AND) {
-               pred->pop_n = 2;
-               fn = filter_pred_and;
+       if (pred->op == OP_AND)
                goto add_pred_fn;
-       } else if (pred->op == OP_OR) {
-               pred->pop_n = 2;
-               fn = filter_pred_or;
+       else if (pred->op == OP_OR)
                goto add_pred_fn;
-       }
 
        field = find_event_field(call, pred->field_name);
        if (!field) {
@@ -829,7 +1003,7 @@ static int filter_add_pred(struct filter_parse_state *ps,
 
 add_pred_fn:
        if (!dry_run)
-               return filter_add_pred_fn(ps, call, filter, pred, fn);
+               return filter_add_pred_fn(ps, call, filter, pred, stack, fn);
        return 0;
 }
 
@@ -1187,6 +1361,234 @@ static int check_preds(struct filter_parse_state *ps)
        return 0;
 }
 
+static int count_preds(struct filter_parse_state *ps)
+{
+       struct postfix_elt *elt;
+       int n_preds = 0;
+
+       list_for_each_entry(elt, &ps->postfix, list) {
+               if (elt->op == OP_NONE)
+                       continue;
+               n_preds++;
+       }
+
+       return n_preds;
+}
+
+/*
+ * The tree is walked at filtering of an event. If the tree is not correctly
+ * built, it may cause an infinite loop. Check here that the tree does
+ * indeed terminate.
+ */
+static int check_pred_tree(struct event_filter *filter,
+                          struct filter_pred *root)
+{
+       struct filter_pred *preds;
+       struct filter_pred *pred;
+       enum move_type move = MOVE_DOWN;
+       int count = 0;
+       int done = 0;
+       int max;
+
+       /*
+        * The max that we can hit a node is three times.
+        * Once going down, once coming up from left, and
+        * once coming up from right. This is more than enough
+        * since leafs are only hit a single time.
+        */
+       max = 3 * filter->n_preds;
+
+       preds = filter->preds;
+       if  (!preds)
+               return -EINVAL;
+       pred = root;
+
+       do {
+               if (WARN_ON(count++ > max))
+                       return -EINVAL;
+
+               switch (move) {
+               case MOVE_DOWN:
+                       if (pred->left != FILTER_PRED_INVALID) {
+                               pred = &preds[pred->left];
+                               continue;
+                       }
+                       /* A leaf at the root is just a leaf in the tree */
+                       if (pred == root)
+                               break;
+                       pred = get_pred_parent(pred, preds,
+                                              pred->parent, &move);
+                       continue;
+               case MOVE_UP_FROM_LEFT:
+                       pred = &preds[pred->right];
+                       move = MOVE_DOWN;
+                       continue;
+               case MOVE_UP_FROM_RIGHT:
+                       if (pred == root)
+                               break;
+                       pred = get_pred_parent(pred, preds,
+                                              pred->parent, &move);
+                       continue;
+               }
+               done = 1;
+       } while (!done);
+
+       /* We are fine. */
+       return 0;
+}
+
+static int count_leafs(struct filter_pred *preds, struct filter_pred *root)
+{
+       struct filter_pred *pred;
+       enum move_type move = MOVE_DOWN;
+       int count = 0;
+       int done = 0;
+
+       pred = root;
+
+       do {
+               switch (move) {
+               case MOVE_DOWN:
+                       if (pred->left != FILTER_PRED_INVALID) {
+                               pred = &preds[pred->left];
+                               continue;
+                       }
+                       /* A leaf at the root is just a leaf in the tree */
+                       if (pred == root)
+                               return 1;
+                       count++;
+                       pred = get_pred_parent(pred, preds,
+                                              pred->parent, &move);
+                       continue;
+               case MOVE_UP_FROM_LEFT:
+                       pred = &preds[pred->right];
+                       move = MOVE_DOWN;
+                       continue;
+               case MOVE_UP_FROM_RIGHT:
+                       if (pred == root)
+                               break;
+                       pred = get_pred_parent(pred, preds,
+                                              pred->parent, &move);
+                       continue;
+               }
+               done = 1;
+       } while (!done);
+
+       return count;
+}
+
+static int fold_pred(struct filter_pred *preds, struct filter_pred *root)
+{
+       struct filter_pred *pred;
+       enum move_type move = MOVE_DOWN;
+       int count = 0;
+       int children;
+       int done = 0;
+
+       /* No need to keep the fold flag */
+       root->index &= ~FILTER_PRED_FOLD;
+
+       /* If the root is a leaf then do nothing */
+       if (root->left == FILTER_PRED_INVALID)
+               return 0;
+
+       /* count the children */
+       children = count_leafs(preds, &preds[root->left]);
+       children += count_leafs(preds, &preds[root->right]);
+
+       root->ops = kzalloc(sizeof(*root->ops) * children, GFP_KERNEL);
+       if (!root->ops)
+               return -ENOMEM;
+
+       root->val = children;
+
+       pred = root;
+       do {
+               switch (move) {
+               case MOVE_DOWN:
+                       if (pred->left != FILTER_PRED_INVALID) {
+                               pred = &preds[pred->left];
+                               continue;
+                       }
+                       if (WARN_ON(count == children))
+                               return -EINVAL;
+                       pred->index &= ~FILTER_PRED_FOLD;
+                       root->ops[count++] = pred->index;
+                       pred = get_pred_parent(pred, preds,
+                                              pred->parent, &move);
+                       continue;
+               case MOVE_UP_FROM_LEFT:
+                       pred = &preds[pred->right];
+                       move = MOVE_DOWN;
+                       continue;
+               case MOVE_UP_FROM_RIGHT:
+                       if (pred == root)
+                               break;
+                       pred = get_pred_parent(pred, preds,
+                                              pred->parent, &move);
+                       continue;
+               }
+               done = 1;
+       } while (!done);
+
+       return 0;
+}
+
+/*
+ * To optimize the processing of the ops, if we have several "ors" or
+ * "ands" together, we can put them in an array and process them all
+ * together speeding up the filter logic.
+ */
+static int fold_pred_tree(struct event_filter *filter,
+                          struct filter_pred *root)
+{
+       struct filter_pred *preds;
+       struct filter_pred *pred;
+       enum move_type move = MOVE_DOWN;
+       int done = 0;
+       int err;
+
+       preds = filter->preds;
+       if  (!preds)
+               return -EINVAL;
+       pred = root;
+
+       do {
+               switch (move) {
+               case MOVE_DOWN:
+                       if (pred->index & FILTER_PRED_FOLD) {
+                               err = fold_pred(preds, pred);
+                               if (err)
+                                       return err;
+                               /* Folded nodes are like leafs */
+                       } else if (pred->left != FILTER_PRED_INVALID) {
+                               pred = &preds[pred->left];
+                               continue;
+                       }
+
+                       /* A leaf at the root is just a leaf in the tree */
+                       if (pred == root)
+                               break;
+                       pred = get_pred_parent(pred, preds,
+                                              pred->parent, &move);
+                       continue;
+               case MOVE_UP_FROM_LEFT:
+                       pred = &preds[pred->right];
+                       move = MOVE_DOWN;
+                       continue;
+               case MOVE_UP_FROM_RIGHT:
+                       if (pred == root)
+                               break;
+                       pred = get_pred_parent(pred, preds,
+                                              pred->parent, &move);
+                       continue;
+               }
+               done = 1;
+       } while (!done);
+
+       return 0;
+}
+
 static int replace_preds(struct ftrace_event_call *call,
                         struct event_filter *filter,
                         struct filter_parse_state *ps,
@@ -1195,14 +1597,32 @@ static int replace_preds(struct ftrace_event_call *call,
 {
        char *operand1 = NULL, *operand2 = NULL;
        struct filter_pred *pred;
+       struct filter_pred *root;
        struct postfix_elt *elt;
+       struct pred_stack stack = { }; /* init to NULL */
        int err;
        int n_preds = 0;
 
+       n_preds = count_preds(ps);
+       if (n_preds >= MAX_FILTER_PRED) {
+               parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0);
+               return -ENOSPC;
+       }
+
        err = check_preds(ps);
        if (err)
                return err;
 
+       if (!dry_run) {
+               err = __alloc_pred_stack(&stack, n_preds);
+               if (err)
+                       return err;
+               err = __alloc_preds(filter, n_preds);
+               if (err)
+                       goto fail;
+       }
+
+       n_preds = 0;
        list_for_each_entry(elt, &ps->postfix, list) {
                if (elt->op == OP_NONE) {
                        if (!operand1)
@@ -1211,14 +1631,16 @@ static int replace_preds(struct ftrace_event_call *call,
                                operand2 = elt->operand;
                        else {
                                parse_error(ps, FILT_ERR_TOO_MANY_OPERANDS, 0);
-                               return -EINVAL;
+                               err = -EINVAL;
+                               goto fail;
                        }
                        continue;
                }
 
-               if (n_preds++ == MAX_FILTER_PRED) {
+               if (WARN_ON(n_preds++ == MAX_FILTER_PRED)) {
                        parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0);
-                       return -ENOSPC;
+                       err = -ENOSPC;
+                       goto fail;
                }
 
                if (elt->op == OP_AND || elt->op == OP_OR) {
@@ -1228,76 +1650,181 @@ static int replace_preds(struct ftrace_event_call *call,
 
                if (!operand1 || !operand2) {
                        parse_error(ps, FILT_ERR_MISSING_FIELD, 0);
-                       return -EINVAL;
+                       err = -EINVAL;
+                       goto fail;
                }
 
                pred = create_pred(elt->op, operand1, operand2);
 add_pred:
-               if (!pred)
-                       return -ENOMEM;
-               err = filter_add_pred(ps, call, filter, pred, dry_run);
+               if (!pred) {
+                       err = -ENOMEM;
+                       goto fail;
+               }
+               err = filter_add_pred(ps, call, filter, pred, &stack, dry_run);
                filter_free_pred(pred);
                if (err)
-                       return err;
+                       goto fail;
 
                operand1 = operand2 = NULL;
        }
 
-       return 0;
+       if (!dry_run) {
+               /* We should have one item left on the stack */
+               pred = __pop_pred_stack(&stack);
+               if (!pred)
+                       return -EINVAL;
+               /* This item is where we start from in matching */
+               root = pred;
+               /* Make sure the stack is empty */
+               pred = __pop_pred_stack(&stack);
+               if (WARN_ON(pred)) {
+                       err = -EINVAL;
+                       filter->root = NULL;
+                       goto fail;
+               }
+               err = check_pred_tree(filter, root);
+               if (err)
+                       goto fail;
+
+               /* Optimize the tree */
+               err = fold_pred_tree(filter, root);
+               if (err)
+                       goto fail;
+
+               /* We don't set root until we know it works */
+               barrier();
+               filter->root = root;
+       }
+
+       err = 0;
+fail:
+       __free_pred_stack(&stack);
+       return err;
 }
 
+struct filter_list {
+       struct list_head        list;
+       struct event_filter     *filter;
+};
+
 static int replace_system_preds(struct event_subsystem *system,
                                struct filter_parse_state *ps,
                                char *filter_string)
 {
        struct ftrace_event_call *call;
+       struct filter_list *filter_item;
+       struct filter_list *tmp;
+       LIST_HEAD(filter_list);
        bool fail = true;
        int err;
 
        list_for_each_entry(call, &ftrace_events, list) {
-               struct event_filter *filter = call->filter;
 
                if (strcmp(call->class->system, system->name) != 0)
                        continue;
 
-               /* try to see if the filter can be applied */
-               err = replace_preds(call, filter, ps, filter_string, true);
+               /*
+                * Try to see if the filter can be applied
+                *  (filter arg is ignored on dry_run)
+                */
+               err = replace_preds(call, NULL, ps, filter_string, true);
                if (err)
+                       goto fail;
+       }
+
+       list_for_each_entry(call, &ftrace_events, list) {
+               struct event_filter *filter;
+
+               if (strcmp(call->class->system, system->name) != 0)
                        continue;
 
-               /* really apply the filter */
-               filter_disable_preds(call);
-               err = replace_preds(call, filter, ps, filter_string, false);
+               filter_item = kzalloc(sizeof(*filter_item), GFP_KERNEL);
+               if (!filter_item)
+                       goto fail_mem;
+
+               list_add_tail(&filter_item->list, &filter_list);
+
+               filter_item->filter = __alloc_filter();
+               if (!filter_item->filter)
+                       goto fail_mem;
+               filter = filter_item->filter;
+
+               /* Can only fail on no memory */
+               err = replace_filter_string(filter, filter_string);
                if (err)
-                       filter_disable_preds(call);
-               else {
+                       goto fail_mem;
+
+               err = replace_preds(call, filter, ps, filter_string, false);
+               if (err) {
+                       filter_disable(call);
+                       parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0);
+                       append_filter_err(ps, filter);
+               } else
                        call->flags |= TRACE_EVENT_FL_FILTERED;
-                       replace_filter_string(filter, filter_string);
-               }
+               /*
+                * Regardless of if this returned an error, we still
+                * replace the filter for the call.
+                */
+               filter = call->filter;
+               call->filter = filter_item->filter;
+               filter_item->filter = filter;
+
                fail = false;
        }
 
-       if (fail) {
-               parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0);
-               return -EINVAL;
+       if (fail)
+               goto fail;
+
+       /*
+        * The calls can still be using the old filters.
+        * Do a synchronize_sched() to ensure all calls are
+        * done with them before we free them.
+        */
+       synchronize_sched();
+       list_for_each_entry_safe(filter_item, tmp, &filter_list, list) {
+               __free_filter(filter_item->filter);
+               list_del(&filter_item->list);
+               kfree(filter_item);
        }
        return 0;
+ fail:
+       /* No call succeeded */
+       list_for_each_entry_safe(filter_item, tmp, &filter_list, list) {
+               list_del(&filter_item->list);
+               kfree(filter_item);
+       }
+       parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0);
+       return -EINVAL;
+ fail_mem:
+       /* If any call succeeded, we still need to sync */
+       if (!fail)
+               synchronize_sched();
+       list_for_each_entry_safe(filter_item, tmp, &filter_list, list) {
+               __free_filter(filter_item->filter);
+               list_del(&filter_item->list);
+               kfree(filter_item);
+       }
+       return -ENOMEM;
 }
 
 int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
 {
-       int err;
        struct filter_parse_state *ps;
+       struct event_filter *filter;
+       struct event_filter *tmp;
+       int err = 0;
 
        mutex_lock(&event_mutex);
 
-       err = init_preds(call);
-       if (err)
-               goto out_unlock;
-
        if (!strcmp(strstrip(filter_string), "0")) {
-               filter_disable_preds(call);
-               remove_filter_string(call->filter);
+               filter_disable(call);
+               filter = call->filter;
+               if (!filter)
+                       goto out_unlock;
+               call->filter = NULL;
+               /* Make sure the filter is not being used */
+               synchronize_sched();
+               __free_filter(filter);
                goto out_unlock;
        }
 
@@ -1306,22 +1833,41 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
        if (!ps)
                goto out_unlock;
 
-       filter_disable_preds(call);
-       replace_filter_string(call->filter, filter_string);
+       filter = __alloc_filter();
+       if (!filter) {
+               kfree(ps);
+               goto out_unlock;
+       }
+
+       replace_filter_string(filter, filter_string);
 
        parse_init(ps, filter_ops, filter_string);
        err = filter_parse(ps);
        if (err) {
-               append_filter_err(ps, call->filter);
+               append_filter_err(ps, filter);
                goto out;
        }
 
-       err = replace_preds(call, call->filter, ps, filter_string, false);
-       if (err)
-               append_filter_err(ps, call->filter);
-       else
+       err = replace_preds(call, filter, ps, filter_string, false);
+       if (err) {
+               filter_disable(call);
+               append_filter_err(ps, filter);
+       } else
                call->flags |= TRACE_EVENT_FL_FILTERED;
 out:
+       /*
+        * Always swap the call filter with the new filter
+        * even if there was an error. If there was an error
+        * in the filter, we disable the filter and show the error
+        * string
+        */
+       tmp = call->filter;
+       call->filter = filter;
+       if (tmp) {
+               /* Make sure the call is done with the filter */
+               synchronize_sched();
+               __free_filter(tmp);
+       }
        filter_opstack_clear(ps);
        postfix_clear(ps);
        kfree(ps);
@@ -1334,18 +1880,21 @@ out_unlock:
 int apply_subsystem_event_filter(struct event_subsystem *system,
                                 char *filter_string)
 {
-       int err;
        struct filter_parse_state *ps;
+       struct event_filter *filter;
+       int err = 0;
 
        mutex_lock(&event_mutex);
 
-       err = init_subsystem_preds(system);
-       if (err)
-               goto out_unlock;
-
        if (!strcmp(strstrip(filter_string), "0")) {
                filter_free_subsystem_preds(system);
                remove_filter_string(system->filter);
+               filter = system->filter;
+               system->filter = NULL;
+               /* Ensure all filters are no longer used */
+               synchronize_sched();
+               filter_free_subsystem_filters(system);
+               __free_filter(filter);
                goto out_unlock;
        }
 
@@ -1354,7 +1903,17 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
        if (!ps)
                goto out_unlock;
 
-       replace_filter_string(system->filter, filter_string);
+       filter = __alloc_filter();
+       if (!filter)
+               goto out;
+
+       replace_filter_string(filter, filter_string);
+       /*
+        * No event actually uses the system filter
+        * we can free it without synchronize_sched().
+        */
+       __free_filter(system->filter);
+       system->filter = filter;
 
        parse_init(ps, filter_ops, filter_string);
        err = filter_parse(ps);
@@ -1384,7 +1943,7 @@ void ftrace_profile_free_filter(struct perf_event *event)
        struct event_filter *filter = event->filter;
 
        event->filter = NULL;
-       __free_preds(filter);
+       __free_filter(filter);
 }
 
 int ftrace_profile_set_filter(struct perf_event *event, int event_id,
@@ -1410,8 +1969,8 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id,
        if (event->filter)
                goto out_unlock;
 
-       filter = __alloc_preds();
-       if (IS_ERR(filter)) {
+       filter = __alloc_filter();
+       if (!filter) {
                err = PTR_ERR(filter);
                goto out_unlock;
        }
@@ -1419,7 +1978,7 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id,
        err = -ENOMEM;
        ps = kzalloc(sizeof(*ps), GFP_KERNEL);
        if (!ps)
-               goto free_preds;
+               goto free_filter;
 
        parse_init(ps, filter_ops, filter_str);
        err = filter_parse(ps);
@@ -1435,9 +1994,9 @@ free_ps:
        postfix_clear(ps);
        kfree(ps);
 
-free_preds:
+free_filter:
        if (err)
-               __free_preds(filter);
+               __free_filter(filter);
 
 out_unlock:
        mutex_unlock(&event_mutex);
index 4b74d71..bbeec31 100644 (file)
@@ -161,13 +161,13 @@ struct ftrace_event_class event_class_ftrace_##call = {                   \
        .fields                 = LIST_HEAD_INIT(event_class_ftrace_##call.fields),\
 };                                                                     \
                                                                        \
-struct ftrace_event_call __used                                                \
-__attribute__((__aligned__(4)))                                                \
-__attribute__((section("_ftrace_events"))) event_##call = {            \
+struct ftrace_event_call __used event_##call = {                       \
        .name                   = #call,                                \
        .event.type             = etype,                                \
        .class                  = &event_class_ftrace_##call,           \
        .print_fmt              = print,                                \
 };                                                                     \
+struct ftrace_event_call __used                                                \
+__attribute__((section("_ftrace_events"))) *__event_##call = &event_##call;
 
 #include "trace_entries.h"
index 2dec9bc..8435b43 100644 (file)
@@ -353,6 +353,43 @@ static __kprobes void free_deref_fetch_param(struct deref_fetch_param *data)
        kfree(data);
 }
 
+/* Bitfield fetch function */
+struct bitfield_fetch_param {
+       struct fetch_param orig;
+       unsigned char hi_shift;
+       unsigned char low_shift;
+};
+
+#define DEFINE_FETCH_bitfield(type)                                    \
+static __kprobes void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs,\
+                                           void *data, void *dest)     \
+{                                                                      \
+       struct bitfield_fetch_param *bprm = data;                       \
+       type buf = 0;                                                   \
+       call_fetch(&bprm->orig, regs, &buf);                            \
+       if (buf) {                                                      \
+               buf <<= bprm->hi_shift;                                 \
+               buf >>= bprm->low_shift;                                \
+       }                                                               \
+       *(type *)dest = buf;                                            \
+}
+DEFINE_BASIC_FETCH_FUNCS(bitfield)
+#define fetch_bitfield_string NULL
+#define fetch_bitfield_string_size NULL
+
+static __kprobes void
+free_bitfield_fetch_param(struct bitfield_fetch_param *data)
+{
+       /*
+        * Don't check the bitfield itself, because this must be the
+        * last fetch function.
+        */
+       if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
+               free_deref_fetch_param(data->orig.data);
+       else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
+               free_symbol_cache(data->orig.data);
+       kfree(data);
+}
 /* Default (unsigned long) fetch type */
 #define __DEFAULT_FETCH_TYPE(t) u##t
 #define _DEFAULT_FETCH_TYPE(t) __DEFAULT_FETCH_TYPE(t)
@@ -367,6 +404,7 @@ enum {
        FETCH_MTD_memory,
        FETCH_MTD_symbol,
        FETCH_MTD_deref,
+       FETCH_MTD_bitfield,
        FETCH_MTD_END,
 };
 
@@ -387,6 +425,7 @@ ASSIGN_FETCH_FUNC(retval, ftype),                   \
 ASSIGN_FETCH_FUNC(memory, ftype),                      \
 ASSIGN_FETCH_FUNC(symbol, ftype),                      \
 ASSIGN_FETCH_FUNC(deref, ftype),                       \
+ASSIGN_FETCH_FUNC(bitfield, ftype),                    \
          }                                             \
        }
 
@@ -430,9 +469,33 @@ static const struct fetch_type *find_fetch_type(const char *type)
        if (!type)
                type = DEFAULT_FETCH_TYPE_STR;
 
+       /* Special case: bitfield */
+       if (*type == 'b') {
+               unsigned long bs;
+               type = strchr(type, '/');
+               if (!type)
+                       goto fail;
+               type++;
+               if (strict_strtoul(type, 0, &bs))
+                       goto fail;
+               switch (bs) {
+               case 8:
+                       return find_fetch_type("u8");
+               case 16:
+                       return find_fetch_type("u16");
+               case 32:
+                       return find_fetch_type("u32");
+               case 64:
+                       return find_fetch_type("u64");
+               default:
+                       goto fail;
+               }
+       }
+
        for (i = 0; i < ARRAY_SIZE(fetch_type_table); i++)
                if (strcmp(type, fetch_type_table[i].name) == 0)
                        return &fetch_type_table[i];
+fail:
        return NULL;
 }
 
@@ -586,7 +649,9 @@ error:
 
 static void free_probe_arg(struct probe_arg *arg)
 {
-       if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn))
+       if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn))
+               free_bitfield_fetch_param(arg->fetch.data);
+       else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn))
                free_deref_fetch_param(arg->fetch.data);
        else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn))
                free_symbol_cache(arg->fetch.data);
@@ -767,16 +832,15 @@ static int __parse_probe_arg(char *arg, const struct fetch_type *t,
                }
                break;
        case '+':       /* deref memory */
+               arg++;  /* Skip '+', because strict_strtol() rejects it. */
        case '-':
                tmp = strchr(arg, '(');
                if (!tmp)
                        break;
                *tmp = '\0';
-               ret = strict_strtol(arg + 1, 0, &offset);
+               ret = strict_strtol(arg, 0, &offset);
                if (ret)
                        break;
-               if (arg[0] == '-')
-                       offset = -offset;
                arg = tmp + 1;
                tmp = strrchr(arg, ')');
                if (tmp) {
@@ -807,6 +871,41 @@ static int __parse_probe_arg(char *arg, const struct fetch_type *t,
        return ret;
 }
 
+#define BYTES_TO_BITS(nb)      ((BITS_PER_LONG * (nb)) / sizeof(long))
+
+/* Bitfield type needs to be parsed into a fetch function */
+static int __parse_bitfield_probe_arg(const char *bf,
+                                     const struct fetch_type *t,
+                                     struct fetch_param *f)
+{
+       struct bitfield_fetch_param *bprm;
+       unsigned long bw, bo;
+       char *tail;
+
+       if (*bf != 'b')
+               return 0;
+
+       bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
+       if (!bprm)
+               return -ENOMEM;
+       bprm->orig = *f;
+       f->fn = t->fetch[FETCH_MTD_bitfield];
+       f->data = (void *)bprm;
+
+       bw = simple_strtoul(bf + 1, &tail, 0);  /* Use simple one */
+       if (bw == 0 || *tail != '@')
+               return -EINVAL;
+
+       bf = tail + 1;
+       bo = simple_strtoul(bf, &tail, 0);
+       if (tail == bf || *tail != '/')
+               return -EINVAL;
+
+       bprm->hi_shift = BYTES_TO_BITS(t->size) - (bw + bo);
+       bprm->low_shift = bprm->hi_shift + bo;
+       return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0;
+}
+
 /* String length checking wrapper */
 static int parse_probe_arg(char *arg, struct trace_probe *tp,
                           struct probe_arg *parg, int is_return)
@@ -836,6 +935,8 @@ static int parse_probe_arg(char *arg, struct trace_probe *tp,
        parg->offset = tp->size;
        tp->size += parg->type->size;
        ret = __parse_probe_arg(arg, parg->type, &parg->fetch, is_return);
+       if (ret >= 0 && t != NULL)
+               ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch);
        if (ret >= 0) {
                parg->fetch_size.fn = get_fetch_size_function(parg->type,
                                                              parg->fetch.fn);
@@ -1130,7 +1231,7 @@ static int command_trace_probe(const char *buf)
        return ret;
 }
 
-#define WRITE_BUFSIZE 128
+#define WRITE_BUFSIZE 4096
 
 static ssize_t probes_write(struct file *file, const char __user *buffer,
                            size_t count, loff_t *ppos)
index 02272ba..456be90 100644 (file)
@@ -529,24 +529,34 @@ seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags)
  * @entry: The trace entry field from the ring buffer
  *
  * Prints the generic fields of irqs off, in hard or softirq, preempt
- * count and lock depth.
+ * count.
  */
 int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry)
 {
-       int hardirq, softirq;
+       char hardsoft_irq;
+       char need_resched;
+       char irqs_off;
+       int hardirq;
+       int softirq;
        int ret;
 
        hardirq = entry->flags & TRACE_FLAG_HARDIRQ;
        softirq = entry->flags & TRACE_FLAG_SOFTIRQ;
 
+       irqs_off =
+               (entry->flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
+               (entry->flags & TRACE_FLAG_IRQS_NOSUPPORT) ? 'X' :
+               '.';
+       need_resched =
+               (entry->flags & TRACE_FLAG_NEED_RESCHED) ? 'N' : '.';
+       hardsoft_irq =
+               (hardirq && softirq) ? 'H' :
+               hardirq ? 'h' :
+               softirq ? 's' :
+               '.';
+
        if (!trace_seq_printf(s, "%c%c%c",
-                             (entry->flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
-                               (entry->flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
-                                 'X' : '.',
-                             (entry->flags & TRACE_FLAG_NEED_RESCHED) ?
-                               'N' : '.',
-                             (hardirq && softirq) ? 'H' :
-                               hardirq ? 'h' : softirq ? 's' : '.'))
+                             irqs_off, need_resched, hardsoft_irq))
                return 0;
 
        if (entry->preempt_count)
@@ -554,13 +564,7 @@ int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry)
        else
                ret = trace_seq_putc(s, '.');
 
-       if (!ret)
-               return 0;
-
-       if (entry->lock_depth < 0)
-               return trace_seq_putc(s, '.');
-
-       return trace_seq_printf(s, "%d", entry->lock_depth);
+       return ret;
 }
 
 static int
index 8f758d0..7e62c0a 100644 (file)
@@ -247,51 +247,3 @@ void tracing_sched_switch_assign_trace(struct trace_array *tr)
        ctx_trace = tr;
 }
 
-static void stop_sched_trace(struct trace_array *tr)
-{
-       tracing_stop_sched_switch_record();
-}
-
-static int sched_switch_trace_init(struct trace_array *tr)
-{
-       ctx_trace = tr;
-       tracing_reset_online_cpus(tr);
-       tracing_start_sched_switch_record();
-       return 0;
-}
-
-static void sched_switch_trace_reset(struct trace_array *tr)
-{
-       if (sched_ref)
-               stop_sched_trace(tr);
-}
-
-static void sched_switch_trace_start(struct trace_array *tr)
-{
-       sched_stopped = 0;
-}
-
-static void sched_switch_trace_stop(struct trace_array *tr)
-{
-       sched_stopped = 1;
-}
-
-static struct tracer sched_switch_trace __read_mostly =
-{
-       .name           = "sched_switch",
-       .init           = sched_switch_trace_init,
-       .reset          = sched_switch_trace_reset,
-       .start          = sched_switch_trace_start,
-       .stop           = sched_switch_trace_stop,
-       .wait_pipe      = poll_wait_pipe,
-#ifdef CONFIG_FTRACE_SELFTEST
-       .selftest    = trace_selftest_startup_sched_switch,
-#endif
-};
-
-__init static int init_sched_switch_trace(void)
-{
-       return register_tracer(&sched_switch_trace);
-}
-device_initcall(init_sched_switch_trace);
-
index b706529..ee7b5a0 100644 (file)
@@ -55,31 +55,42 @@ struct ftrace_event_class event_class_syscall_exit = {
        .raw_init       = init_syscall_trace,
 };
 
-extern unsigned long __start_syscalls_metadata[];
-extern unsigned long __stop_syscalls_metadata[];
+extern struct syscall_metadata *__start_syscalls_metadata[];
+extern struct syscall_metadata *__stop_syscalls_metadata[];
 
 static struct syscall_metadata **syscalls_metadata;
 
-static struct syscall_metadata *find_syscall_meta(unsigned long syscall)
+#ifndef ARCH_HAS_SYSCALL_MATCH_SYM_NAME
+static inline bool arch_syscall_match_sym_name(const char *sym, const char *name)
 {
-       struct syscall_metadata *start;
-       struct syscall_metadata *stop;
+       /*
+        * Only compare after the "sys" prefix. Archs that use
+        * syscall wrappers may have syscalls symbols aliases prefixed
+        * with "SyS" instead of "sys", leading to an unwanted
+        * mismatch.
+        */
+       return !strcmp(sym + 3, name + 3);
+}
+#endif
+
+static __init struct syscall_metadata *
+find_syscall_meta(unsigned long syscall)
+{
+       struct syscall_metadata **start;
+       struct syscall_metadata **stop;
        char str[KSYM_SYMBOL_LEN];
 
 
-       start = (struct syscall_metadata *)__start_syscalls_metadata;
-       stop = (struct syscall_metadata *)__stop_syscalls_metadata;
+       start = __start_syscalls_metadata;
+       stop = __stop_syscalls_metadata;
        kallsyms_lookup(syscall, NULL, NULL, NULL, str);
 
+       if (arch_syscall_match_sym_name(str, "sys_ni_syscall"))
+               return NULL;
+
        for ( ; start < stop; start++) {
-               /*
-                * Only compare after the "sys" prefix. Archs that use
-                * syscall wrappers may have syscalls symbols aliases prefixed
-                * with "SyS" instead of "sys", leading to an unwanted
-                * mismatch.
-                */
-               if (start->name && !strcmp(start->name + 3, str + 3))
-                       return start;
+               if ((*start)->name && arch_syscall_match_sym_name(str, (*start)->name))
+                       return *start;
        }
        return NULL;
 }
@@ -358,7 +369,7 @@ int reg_event_syscall_enter(struct ftrace_event_call *call)
        int num;
 
        num = ((struct syscall_metadata *)call->data)->syscall_nr;
-       if (num < 0 || num >= NR_syscalls)
+       if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
                return -ENOSYS;
        mutex_lock(&syscall_trace_lock);
        if (!sys_refcount_enter)
@@ -376,7 +387,7 @@ void unreg_event_syscall_enter(struct ftrace_event_call *call)
        int num;
 
        num = ((struct syscall_metadata *)call->data)->syscall_nr;
-       if (num < 0 || num >= NR_syscalls)
+       if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
                return;
        mutex_lock(&syscall_trace_lock);
        sys_refcount_enter--;
@@ -392,7 +403,7 @@ int reg_event_syscall_exit(struct ftrace_event_call *call)
        int num;
 
        num = ((struct syscall_metadata *)call->data)->syscall_nr;
-       if (num < 0 || num >= NR_syscalls)
+       if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
                return -ENOSYS;
        mutex_lock(&syscall_trace_lock);
        if (!sys_refcount_exit)
@@ -410,7 +421,7 @@ void unreg_event_syscall_exit(struct ftrace_event_call *call)
        int num;
 
        num = ((struct syscall_metadata *)call->data)->syscall_nr;
-       if (num < 0 || num >= NR_syscalls)
+       if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
                return;
        mutex_lock(&syscall_trace_lock);
        sys_refcount_exit--;
@@ -423,6 +434,14 @@ void unreg_event_syscall_exit(struct ftrace_event_call *call)
 int init_syscall_trace(struct ftrace_event_call *call)
 {
        int id;
+       int num;
+
+       num = ((struct syscall_metadata *)call->data)->syscall_nr;
+       if (num < 0 || num >= NR_syscalls) {
+               pr_debug("syscall %s metadata not mapped, disabling ftrace event\n",
+                               ((struct syscall_metadata *)call->data)->name);
+               return -ENOSYS;
+       }
 
        if (set_syscall_print_fmt(call) < 0)
                return -ENOMEM;
@@ -437,7 +456,7 @@ int init_syscall_trace(struct ftrace_event_call *call)
        return id;
 }
 
-unsigned long __init arch_syscall_addr(int nr)
+unsigned long __init __weak arch_syscall_addr(int nr)
 {
        return (unsigned long)sys_call_table[nr];
 }
index e95ee7f..68187af 100644 (file)
@@ -27,8 +27,8 @@
 #include <linux/sched.h>
 #include <linux/jump_label.h>
 
-extern struct tracepoint __start___tracepoints[];
-extern struct tracepoint __stop___tracepoints[];
+extern struct tracepoint * const __start___tracepoints_ptrs[];
+extern struct tracepoint * const __stop___tracepoints_ptrs[];
 
 /* Set to 1 to enable tracepoint debug output */
 static const int tracepoint_debug;
@@ -298,10 +298,10 @@ static void disable_tracepoint(struct tracepoint *elem)
  *
  * Updates the probe callback corresponding to a range of tracepoints.
  */
-void
-tracepoint_update_probe_range(struct tracepoint *begin, struct tracepoint *end)
+void tracepoint_update_probe_range(struct tracepoint * const *begin,
+                                  struct tracepoint * const *end)
 {
-       struct tracepoint *iter;
+       struct tracepoint * const *iter;
        struct tracepoint_entry *mark_entry;
 
        if (!begin)
@@ -309,12 +309,12 @@ tracepoint_update_probe_range(struct tracepoint *begin, struct tracepoint *end)
 
        mutex_lock(&tracepoints_mutex);
        for (iter = begin; iter < end; iter++) {
-               mark_entry = get_tracepoint(iter->name);
+               mark_entry = get_tracepoint((*iter)->name);
                if (mark_entry) {
-                       set_tracepoint(&mark_entry, iter,
+                       set_tracepoint(&mark_entry, *iter,
                                        !!mark_entry->refcount);
                } else {
-                       disable_tracepoint(iter);
+                       disable_tracepoint(*iter);
                }
        }
        mutex_unlock(&tracepoints_mutex);
@@ -326,8 +326,8 @@ tracepoint_update_probe_range(struct tracepoint *begin, struct tracepoint *end)
 static void tracepoint_update_probes(void)
 {
        /* Core kernel tracepoints */
-       tracepoint_update_probe_range(__start___tracepoints,
-               __stop___tracepoints);
+       tracepoint_update_probe_range(__start___tracepoints_ptrs,
+               __stop___tracepoints_ptrs);
        /* tracepoints in modules. */
        module_update_tracepoints();
 }
@@ -514,8 +514,8 @@ EXPORT_SYMBOL_GPL(tracepoint_probe_update_all);
  * Will return the first tracepoint in the range if the input tracepoint is
  * NULL.
  */
-int tracepoint_get_iter_range(struct tracepoint **tracepoint,
-       struct tracepoint *begin, struct tracepoint *end)
+int tracepoint_get_iter_range(struct tracepoint * const **tracepoint,
+       struct tracepoint * const *begin, struct tracepoint * const *end)
 {
        if (!*tracepoint && begin != end) {
                *tracepoint = begin;
@@ -534,7 +534,8 @@ static void tracepoint_get_iter(struct tracepoint_iter *iter)
        /* Core kernel tracepoints */
        if (!iter->module) {
                found = tracepoint_get_iter_range(&iter->tracepoint,
-                               __start___tracepoints, __stop___tracepoints);
+                               __start___tracepoints_ptrs,
+                               __stop___tracepoints_ptrs);
                if (found)
                        goto end;
        }
@@ -585,8 +586,8 @@ int tracepoint_module_notify(struct notifier_block *self,
        switch (val) {
        case MODULE_STATE_COMING:
        case MODULE_STATE_GOING:
-               tracepoint_update_probe_range(mod->tracepoints,
-                       mod->tracepoints + mod->num_tracepoints);
+               tracepoint_update_probe_range(mod->tracepoints_ptrs,
+                       mod->tracepoints_ptrs + mod->num_tracepoints);
                break;
        }
        return 0;
index d7ebdf4..18bb157 100644 (file)
@@ -27,7 +27,7 @@
 #include <asm/irq_regs.h>
 #include <linux/perf_event.h>
 
-int watchdog_enabled;
+int watchdog_enabled = 1;
 int __read_mostly softlockup_thresh = 60;
 
 static DEFINE_PER_CPU(unsigned long, watchdog_touch_ts);
@@ -43,9 +43,6 @@ static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
 static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);
 #endif
 
-static int no_watchdog;
-
-
 /* boot commands */
 /*
  * Should we panic when a soft-lockup or hard-lockup occurs:
@@ -58,7 +55,7 @@ static int __init hardlockup_panic_setup(char *str)
        if (!strncmp(str, "panic", 5))
                hardlockup_panic = 1;
        else if (!strncmp(str, "0", 1))
-               no_watchdog = 1;
+               watchdog_enabled = 0;
        return 1;
 }
 __setup("nmi_watchdog=", hardlockup_panic_setup);
@@ -77,7 +74,7 @@ __setup("softlockup_panic=", softlockup_panic_setup);
 
 static int __init nowatchdog_setup(char *str)
 {
-       no_watchdog = 1;
+       watchdog_enabled = 0;
        return 1;
 }
 __setup("nowatchdog", nowatchdog_setup);
@@ -85,7 +82,7 @@ __setup("nowatchdog", nowatchdog_setup);
 /* deprecated */
 static int __init nosoftlockup_setup(char *str)
 {
-       no_watchdog = 1;
+       watchdog_enabled = 0;
        return 1;
 }
 __setup("nosoftlockup", nosoftlockup_setup);
@@ -366,8 +363,14 @@ static int watchdog_nmi_enable(int cpu)
                goto out_save;
        }
 
-       printk(KERN_ERR "NMI watchdog disabled for cpu%i: unable to create perf event: %ld\n",
-              cpu, PTR_ERR(event));
+
+       /* vary the KERN level based on the returned errno */
+       if (PTR_ERR(event) == -EOPNOTSUPP)
+               printk(KERN_INFO "NMI watchdog disabled (cpu%i): not supported (no LAPIC?)\n", cpu);
+       else if (PTR_ERR(event) == -ENOENT)
+               printk(KERN_WARNING "NMI watchdog disabled (cpu%i): hardware events not enabled\n", cpu);
+       else
+               printk(KERN_ERR "NMI watchdog disabled (cpu%i): unable to create perf event: %ld\n", cpu, PTR_ERR(event));
        return PTR_ERR(event);
 
        /* success path */
@@ -432,9 +435,6 @@ static int watchdog_enable(int cpu)
                wake_up_process(p);
        }
 
-       /* if any cpu succeeds, watchdog is considered enabled for the system */
-       watchdog_enabled = 1;
-
        return 0;
 }
 
@@ -462,12 +462,16 @@ static void watchdog_disable(int cpu)
 static void watchdog_enable_all_cpus(void)
 {
        int cpu;
-       int result = 0;
+
+       watchdog_enabled = 0;
 
        for_each_online_cpu(cpu)
-               result += watchdog_enable(cpu);
+               if (!watchdog_enable(cpu))
+                       /* if any cpu succeeds, watchdog is considered
+                          enabled for the system */
+                       watchdog_enabled = 1;
 
-       if (result)
+       if (!watchdog_enabled)
                printk(KERN_ERR "watchdog: failed to be enabled on some cpus\n");
 
 }
@@ -476,9 +480,6 @@ static void watchdog_disable_all_cpus(void)
 {
        int cpu;
 
-       if (no_watchdog)
-               return;
-
        for_each_online_cpu(cpu)
                watchdog_disable(cpu);
 
@@ -498,10 +499,12 @@ int proc_dowatchdog_enabled(struct ctl_table *table, int write,
 {
        proc_dointvec(table, write, buffer, length, ppos);
 
-       if (watchdog_enabled)
-               watchdog_enable_all_cpus();
-       else
-               watchdog_disable_all_cpus();
+       if (write) {
+               if (watchdog_enabled)
+                       watchdog_enable_all_cpus();
+               else
+                       watchdog_disable_all_cpus();
+       }
        return 0;
 }
 
@@ -530,7 +533,8 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
                break;
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
-               err = watchdog_enable(hotcpu);
+               if (watchdog_enabled)
+                       err = watchdog_enable(hotcpu);
                break;
 #ifdef CONFIG_HOTPLUG_CPU
        case CPU_UP_CANCELED:
@@ -555,9 +559,6 @@ void __init lockup_detector_init(void)
        void *cpu = (void *)(long)smp_processor_id();
        int err;
 
-       if (no_watchdog)
-               return;
-
        err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
        WARN_ON(notifier_to_errno(err));
 
index 11869fa..5ca7ce9 100644 (file)
@@ -79,7 +79,9 @@ enum {
        MAX_IDLE_WORKERS_RATIO  = 4,            /* 1/4 of busy can be idle */
        IDLE_WORKER_TIMEOUT     = 300 * HZ,     /* keep idle ones for 5 mins */
 
-       MAYDAY_INITIAL_TIMEOUT  = HZ / 100,     /* call for help after 10ms */
+       MAYDAY_INITIAL_TIMEOUT  = HZ / 100 >= 2 ? HZ / 100 : 2,
+                                               /* call for help after 10ms
+                                                  (min two ticks) */
        MAYDAY_INTERVAL         = HZ / 10,      /* and then every 100ms */
        CREATE_COOLDOWN         = HZ,           /* time to breath after fail */
        TRUSTEE_COOLDOWN        = HZ / 10,      /* for trustee draining */
@@ -249,10 +251,12 @@ struct workqueue_struct *system_wq __read_mostly;
 struct workqueue_struct *system_long_wq __read_mostly;
 struct workqueue_struct *system_nrt_wq __read_mostly;
 struct workqueue_struct *system_unbound_wq __read_mostly;
+struct workqueue_struct *system_freezable_wq __read_mostly;
 EXPORT_SYMBOL_GPL(system_wq);
 EXPORT_SYMBOL_GPL(system_long_wq);
 EXPORT_SYMBOL_GPL(system_nrt_wq);
 EXPORT_SYMBOL_GPL(system_unbound_wq);
+EXPORT_SYMBOL_GPL(system_freezable_wq);
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/workqueue.h>
@@ -314,6 +318,11 @@ static inline int __next_wq_cpu(int cpu, const struct cpumask *mask,
 
 static struct debug_obj_descr work_debug_descr;
 
+static void *work_debug_hint(void *addr)
+{
+       return ((struct work_struct *) addr)->func;
+}
+
 /*
  * fixup_init is called when:
  * - an active object is initialized
@@ -385,6 +394,7 @@ static int work_fixup_free(void *addr, enum debug_obj_state state)
 
 static struct debug_obj_descr work_debug_descr = {
        .name           = "work_struct",
+       .debug_hint     = work_debug_hint,
        .fixup_init     = work_fixup_init,
        .fixup_activate = work_fixup_activate,
        .fixup_free     = work_fixup_free,
@@ -2047,6 +2057,15 @@ repeat:
                                move_linked_works(work, scheduled, &n);
 
                process_scheduled_works(rescuer);
+
+               /*
+                * Leave this gcwq.  If keep_working() is %true, notify a
+                * regular worker; otherwise, we end up with 0 concurrency
+                * and stalling the execution.
+                */
+               if (keep_working(gcwq))
+                       wake_up_worker(gcwq);
+
                spin_unlock_irq(&gcwq->lock);
        }
 
@@ -2956,7 +2975,7 @@ struct workqueue_struct *__alloc_workqueue_key(const char *name,
         */
        spin_lock(&workqueue_lock);
 
-       if (workqueue_freezing && wq->flags & WQ_FREEZEABLE)
+       if (workqueue_freezing && wq->flags & WQ_FREEZABLE)
                for_each_cwq_cpu(cpu, wq)
                        get_cwq(cpu, wq)->max_active = 0;
 
@@ -3068,7 +3087,7 @@ void workqueue_set_max_active(struct workqueue_struct *wq, int max_active)
 
                spin_lock_irq(&gcwq->lock);
 
-               if (!(wq->flags & WQ_FREEZEABLE) ||
+               if (!(wq->flags & WQ_FREEZABLE) ||
                    !(gcwq->flags & GCWQ_FREEZING))
                        get_cwq(gcwq->cpu, wq)->max_active = max_active;
 
@@ -3318,7 +3337,7 @@ static int __cpuinit trustee_thread(void *__gcwq)
         * want to get it over with ASAP - spam rescuers, wake up as
         * many idlers as necessary and create new ones till the
         * worklist is empty.  Note that if the gcwq is frozen, there
-        * may be frozen works in freezeable cwqs.  Don't declare
+        * may be frozen works in freezable cwqs.  Don't declare
         * completion while frozen.
         */
        while (gcwq->nr_workers != gcwq->nr_idle ||
@@ -3576,9 +3595,9 @@ EXPORT_SYMBOL_GPL(work_on_cpu);
 /**
  * freeze_workqueues_begin - begin freezing workqueues
  *
- * Start freezing workqueues.  After this function returns, all
- * freezeable workqueues will queue new works to their frozen_works
- * list instead of gcwq->worklist.
+ * Start freezing workqueues.  After this function returns, all freezable
+ * workqueues will queue new works to their frozen_works list instead of
+ * gcwq->worklist.
  *
  * CONTEXT:
  * Grabs and releases workqueue_lock and gcwq->lock's.
@@ -3604,7 +3623,7 @@ void freeze_workqueues_begin(void)
                list_for_each_entry(wq, &workqueues, list) {
                        struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
 
-                       if (cwq && wq->flags & WQ_FREEZEABLE)
+                       if (cwq && wq->flags & WQ_FREEZABLE)
                                cwq->max_active = 0;
                }
 
@@ -3615,7 +3634,7 @@ void freeze_workqueues_begin(void)
 }
 
 /**
- * freeze_workqueues_busy - are freezeable workqueues still busy?
+ * freeze_workqueues_busy - are freezable workqueues still busy?
  *
  * Check whether freezing is complete.  This function must be called
  * between freeze_workqueues_begin() and thaw_workqueues().
@@ -3624,8 +3643,8 @@ void freeze_workqueues_begin(void)
  * Grabs and releases workqueue_lock.
  *
  * RETURNS:
- * %true if some freezeable workqueues are still busy.  %false if
- * freezing is complete.
+ * %true if some freezable workqueues are still busy.  %false if freezing
+ * is complete.
  */
 bool freeze_workqueues_busy(void)
 {
@@ -3645,7 +3664,7 @@ bool freeze_workqueues_busy(void)
                list_for_each_entry(wq, &workqueues, list) {
                        struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
 
-                       if (!cwq || !(wq->flags & WQ_FREEZEABLE))
+                       if (!cwq || !(wq->flags & WQ_FREEZABLE))
                                continue;
 
                        BUG_ON(cwq->nr_active < 0);
@@ -3690,7 +3709,7 @@ void thaw_workqueues(void)
                list_for_each_entry(wq, &workqueues, list) {
                        struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
 
-                       if (!cwq || !(wq->flags & WQ_FREEZEABLE))
+                       if (!cwq || !(wq->flags & WQ_FREEZABLE))
                                continue;
 
                        /* restore max_active and repopulate worklist */
@@ -3764,8 +3783,10 @@ static int __init init_workqueues(void)
        system_nrt_wq = alloc_workqueue("events_nrt", WQ_NON_REENTRANT, 0);
        system_unbound_wq = alloc_workqueue("events_unbound", WQ_UNBOUND,
                                            WQ_UNBOUND_MAX_ACTIVE);
+       system_freezable_wq = alloc_workqueue("events_freezable",
+                                             WQ_FREEZABLE, 0);
        BUG_ON(!system_wq || !system_long_wq || !system_nrt_wq ||
-              !system_unbound_wq);
+              !system_unbound_wq || !system_freezable_wq);
        return 0;
 }
 early_initcall(init_workqueues);
index 3967c23..2b97418 100644 (file)
@@ -805,7 +805,7 @@ config ARCH_WANT_FRAME_POINTERS
 config FRAME_POINTER
        bool "Compile the kernel with frame pointers"
        depends on DEBUG_KERNEL && \
-               (CRIS || M68K || M68KNOMMU || FRV || UML || \
+               (CRIS || M68K || FRV || UML || \
                 AVR32 || SUPERH || BLACKFIN || MN10300) || \
                ARCH_WANT_FRAME_POINTERS
        default y if (DEBUG_INFO && UML) || ARCH_WANT_FRAME_POINTERS
index deebcc5..9d86e45 100644 (file)
@@ -249,14 +249,17 @@ static struct debug_bucket *get_bucket(unsigned long addr)
 
 static void debug_print_object(struct debug_obj *obj, char *msg)
 {
+       struct debug_obj_descr *descr = obj->descr;
        static int limit;
 
-       if (limit < 5 && obj->descr != descr_test) {
+       if (limit < 5 && descr != descr_test) {
+               void *hint = descr->debug_hint ?
+                       descr->debug_hint(obj->object) : NULL;
                limit++;
                WARN(1, KERN_ERR "ODEBUG: %s %s (active state %u) "
-                                "object type: %s\n",
+                                "object type: %s hint: %pS\n",
                        msg, obj_states[obj->state], obj->astate,
-                       obj->descr->name);
+                       descr->name, hint);
        }
        debug_objects_warnings++;
 }
index 344c710..b8029a5 100644 (file)
@@ -35,6 +35,31 @@ void __list_add(struct list_head *new,
 }
 EXPORT_SYMBOL(__list_add);
 
+void __list_del_entry(struct list_head *entry)
+{
+       struct list_head *prev, *next;
+
+       prev = entry->prev;
+       next = entry->next;
+
+       if (WARN(next == LIST_POISON1,
+               "list_del corruption, %p->next is LIST_POISON1 (%p)\n",
+               entry, LIST_POISON1) ||
+           WARN(prev == LIST_POISON2,
+               "list_del corruption, %p->prev is LIST_POISON2 (%p)\n",
+               entry, LIST_POISON2) ||
+           WARN(prev->next != entry,
+               "list_del corruption. prev->next should be %p, "
+               "but was %p\n", entry, prev->next) ||
+           WARN(next->prev != entry,
+               "list_del corruption. next->prev should be %p, "
+               "but was %p\n", entry, next->prev))
+               return;
+
+       __list_del(prev, next);
+}
+EXPORT_SYMBOL(__list_del_entry);
+
 /**
  * list_del - deletes entry from list.
  * @entry: the element to delete from the list.
@@ -43,19 +68,7 @@ EXPORT_SYMBOL(__list_add);
  */
 void list_del(struct list_head *entry)
 {
-       WARN(entry->next == LIST_POISON1,
-               "list_del corruption, next is LIST_POISON1 (%p)\n",
-               LIST_POISON1);
-       WARN(entry->next != LIST_POISON1 && entry->prev == LIST_POISON2,
-               "list_del corruption, prev is LIST_POISON2 (%p)\n",
-               LIST_POISON2);
-       WARN(entry->prev->next != entry,
-               "list_del corruption. prev->next should be %p, "
-               "but was %p\n", entry, entry->prev->next);
-       WARN(entry->next->prev != entry,
-               "list_del corruption. next->prev should be %p, "
-               "but was %p\n", entry, entry->next->prev);
-       __list_del(entry->prev, entry->next);
+       __list_del_entry(entry);
        entry->next = LIST_POISON1;
        entry->prev = LIST_POISON2;
 }
index 5021cbc..ac09f22 100644 (file)
@@ -148,7 +148,7 @@ nla_policy_len(const struct nla_policy *p, int n)
 {
        int i, len = 0;
 
-       for (i = 0; i < n; i++) {
+       for (i = 0; i < n; i++, p++) {
                if (p->len)
                        len += nla_total_size(p->len);
                else if (nla_attr_minlen[p->type])
index 1471988..0ae7e64 100644 (file)
@@ -28,6 +28,8 @@
 
 #ifdef CONFIG_DEBUG_PI_LIST
 
+static struct plist_head test_head;
+
 static void plist_check_prev_next(struct list_head *t, struct list_head *p,
                                  struct list_head *n)
 {
@@ -54,12 +56,13 @@ static void plist_check_list(struct list_head *top)
 
 static void plist_check_head(struct plist_head *head)
 {
-       WARN_ON(!head->rawlock && !head->spinlock);
+       WARN_ON(head != &test_head && !head->rawlock && !head->spinlock);
        if (head->rawlock)
                WARN_ON_SMP(!raw_spin_is_locked(head->rawlock));
        if (head->spinlock)
                WARN_ON_SMP(!spin_is_locked(head->spinlock));
-       plist_check_list(&head->prio_list);
+       if (!plist_head_empty(head))
+               plist_check_list(&plist_first(head)->prio_list);
        plist_check_list(&head->node_list);
 }
 
@@ -75,25 +78,33 @@ static void plist_check_head(struct plist_head *head)
  */
 void plist_add(struct plist_node *node, struct plist_head *head)
 {
-       struct plist_node *iter;
+       struct plist_node *first, *iter, *prev = NULL;
+       struct list_head *node_next = &head->node_list;
 
        plist_check_head(head);
        WARN_ON(!plist_node_empty(node));
+       WARN_ON(!list_empty(&node->prio_list));
+
+       if (plist_head_empty(head))
+               goto ins_node;
 
-       list_for_each_entry(iter, &head->prio_list, plist.prio_list) {
-               if (node->prio < iter->prio)
-                       goto lt_prio;
-               else if (node->prio == iter->prio) {
-                       iter = list_entry(iter->plist.prio_list.next,
-                                       struct plist_node, plist.prio_list);
-                       goto eq_prio;
+       first = iter = plist_first(head);
+
+       do {
+               if (node->prio < iter->prio) {
+                       node_next = &iter->node_list;
+                       break;
                }
-       }
 
-lt_prio:
-       list_add_tail(&node->plist.prio_list, &iter->plist.prio_list);
-eq_prio:
-       list_add_tail(&node->plist.node_list, &iter->plist.node_list);
+               prev = iter;
+               iter = list_entry(iter->prio_list.next,
+                               struct plist_node, prio_list);
+       } while (iter != first);
+
+       if (!prev || prev->prio != node->prio)
+               list_add_tail(&node->prio_list, &iter->prio_list);
+ins_node:
+       list_add_tail(&node->node_list, node_next);
 
        plist_check_head(head);
 }
@@ -108,14 +119,98 @@ void plist_del(struct plist_node *node, struct plist_head *head)
 {
        plist_check_head(head);
 
-       if (!list_empty(&node->plist.prio_list)) {
-               struct plist_node *next = plist_first(&node->plist);
+       if (!list_empty(&node->prio_list)) {
+               if (node->node_list.next != &head->node_list) {
+                       struct plist_node *next;
+
+                       next = list_entry(node->node_list.next,
+                                       struct plist_node, node_list);
 
-               list_move_tail(&next->plist.prio_list, &node->plist.prio_list);
-               list_del_init(&node->plist.prio_list);
+                       /* add the next plist_node into prio_list */
+                       if (list_empty(&next->prio_list))
+                               list_add(&next->prio_list, &node->prio_list);
+               }
+               list_del_init(&node->prio_list);
        }
 
-       list_del_init(&node->plist.node_list);
+       list_del_init(&node->node_list);
 
        plist_check_head(head);
 }
+
+#ifdef CONFIG_DEBUG_PI_LIST
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+static struct plist_node __initdata test_node[241];
+
+static void __init plist_test_check(int nr_expect)
+{
+       struct plist_node *first, *prio_pos, *node_pos;
+
+       if (plist_head_empty(&test_head)) {
+               BUG_ON(nr_expect != 0);
+               return;
+       }
+
+       prio_pos = first = plist_first(&test_head);
+       plist_for_each(node_pos, &test_head) {
+               if (nr_expect-- < 0)
+                       break;
+               if (node_pos == first)
+                       continue;
+               if (node_pos->prio == prio_pos->prio) {
+                       BUG_ON(!list_empty(&node_pos->prio_list));
+                       continue;
+               }
+
+               BUG_ON(prio_pos->prio > node_pos->prio);
+               BUG_ON(prio_pos->prio_list.next != &node_pos->prio_list);
+               prio_pos = node_pos;
+       }
+
+       BUG_ON(nr_expect != 0);
+       BUG_ON(prio_pos->prio_list.next != &first->prio_list);
+}
+
+static int  __init plist_test(void)
+{
+       int nr_expect = 0, i, loop;
+       unsigned int r = local_clock();
+
+       printk(KERN_INFO "start plist test\n");
+       plist_head_init(&test_head, NULL);
+       for (i = 0; i < ARRAY_SIZE(test_node); i++)
+               plist_node_init(test_node + i, 0);
+
+       for (loop = 0; loop < 1000; loop++) {
+               r = r * 193939 % 47629;
+               i = r % ARRAY_SIZE(test_node);
+               if (plist_node_empty(test_node + i)) {
+                       r = r * 193939 % 47629;
+                       test_node[i].prio = r % 99;
+                       plist_add(test_node + i, &test_head);
+                       nr_expect++;
+               } else {
+                       plist_del(test_node + i, &test_head);
+                       nr_expect--;
+               }
+               plist_test_check(nr_expect);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(test_node); i++) {
+               if (plist_node_empty(test_node + i))
+                       continue;
+               plist_del(test_node + i, &test_head);
+               nr_expect--;
+               plist_test_check(nr_expect);
+       }
+
+       printk(KERN_INFO "end plist test\n");
+       return 0;
+}
+
+module_init(plist_test);
+
+#endif
index 5086bb9..7ea2e03 100644 (file)
@@ -736,10 +736,11 @@ next:
                }
        }
        /*
-        * The iftag must have been set somewhere because otherwise
-        * we would return immediated at the beginning of the function
+        * We need not to tag the root tag if there is no tag which is set with
+        * settag within the range from *first_indexp to last_index.
         */
-       root_tag_set(root, settag);
+       if (tagged > 0)
+               root_tag_set(root, settag);
        *first_indexp = index;
 
        return tagged;
index 4693f79..a16be19 100644 (file)
@@ -315,6 +315,7 @@ void rb_augment_insert(struct rb_node *node, rb_augment_f func, void *data)
 
        rb_augment_path(node, func, data);
 }
+EXPORT_SYMBOL(rb_augment_insert);
 
 /*
  * before removing the node, find the deepest node on the rebalance path
@@ -340,6 +341,7 @@ struct rb_node *rb_augment_erase_begin(struct rb_node *node)
 
        return deepest;
 }
+EXPORT_SYMBOL(rb_augment_erase_begin);
 
 /*
  * after removal, update the tree to account for the removed entry
@@ -350,6 +352,7 @@ void rb_augment_erase_end(struct rb_node *node, rb_augment_f func, void *data)
        if (node)
                rb_augment_path(node, func, data);
 }
+EXPORT_SYMBOL(rb_augment_erase_end);
 
 /*
  * This function returns the first node (in sort order) of the tree.
index f236d7c..aa7c305 100644 (file)
@@ -222,8 +222,7 @@ rwsem_down_failed_common(struct rw_semaphore *sem,
 /*
  * wait for the read lock to be granted
  */
-asmregparm struct rw_semaphore __sched *
-rwsem_down_read_failed(struct rw_semaphore *sem)
+struct rw_semaphore __sched *rwsem_down_read_failed(struct rw_semaphore *sem)
 {
        return rwsem_down_failed_common(sem, RWSEM_WAITING_FOR_READ,
                                        -RWSEM_ACTIVE_READ_BIAS);
@@ -232,8 +231,7 @@ rwsem_down_read_failed(struct rw_semaphore *sem)
 /*
  * wait for the write lock to be granted
  */
-asmregparm struct rw_semaphore __sched *
-rwsem_down_write_failed(struct rw_semaphore *sem)
+struct rw_semaphore __sched *rwsem_down_write_failed(struct rw_semaphore *sem)
 {
        return rwsem_down_failed_common(sem, RWSEM_WAITING_FOR_WRITE,
                                        -RWSEM_ACTIVE_WRITE_BIAS);
@@ -243,7 +241,7 @@ rwsem_down_write_failed(struct rw_semaphore *sem)
  * handle waking up a waiter on the semaphore
  * - up_read/up_write has decremented the active part of count if we come here
  */
-asmregparm struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem)
+struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem)
 {
        unsigned long flags;
 
@@ -263,7 +261,7 @@ asmregparm struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem)
  * - caller incremented waiting part of count and discovered it still negative
  * - just wake up any readers at the front of the queue
  */
-asmregparm struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem)
+struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem)
 {
        unsigned long flags;
 
index c47bbe1..93ca08b 100644 (file)
@@ -686,8 +686,10 @@ dma_addr_t swiotlb_map_page(struct device *dev, struct page *page,
        /*
         * Ensure that the address returned is DMA'ble
         */
-       if (!dma_capable(dev, dev_addr, size))
-               panic("map_single: bounce buffer is not DMA'ble");
+       if (!dma_capable(dev, dev_addr, size)) {
+               swiotlb_tbl_unmap_single(dev, map, size, dir);
+               dev_addr = swiotlb_virt_to_bus(dev, io_tlb_overflow_buffer);
+       }
 
        return dev_addr;
 }
index d608331..e0cc014 100644 (file)
@@ -13,7 +13,7 @@
  *
  * INTRODUCTION
  *
- *   The textsearch infrastructure provides text searching facitilies for
+ *   The textsearch infrastructure provides text searching facilities for
  *   both linear and non-linear data. Individual search algorithms are
  *   implemented in modules and chosen by the user.
  *
@@ -43,7 +43,7 @@
  *       to the algorithm to store persistent variables.
  *   (4) Core eventually resets the search offset and forwards the find()
  *       request to the algorithm.
- *   (5) Algorithm calls get_next_block() provided by the user continously
+ *   (5) Algorithm calls get_next_block() provided by the user continuously
  *       to fetch the data to be searched in block by block.
  *   (6) Algorithm invokes finish() after the last call to get_next_block
  *       to clean up any leftovers from get_next_block. (Optional)
  *   the pattern to look for and flags. As a flag, you can set TS_IGNORECASE
  *   to perform case insensitive matching. But it might slow down
  *   performance of algorithm, so you should use it at own your risk.
- *   The returned configuration may then be used for an arbitary
+ *   The returned configuration may then be used for an arbitrary
  *   amount of times and even in parallel as long as a separate struct
  *   ts_state variable is provided to every instance.
  *
  *   The actual search is performed by either calling textsearch_find_-
  *   continuous() for linear data or by providing an own get_next_block()
  *   implementation and calling textsearch_find(). Both functions return
- *   the position of the first occurrence of the patern or UINT_MAX if
- *   no match was found. Subsequent occurences can be found by calling
+ *   the position of the first occurrence of the pattern or UINT_MAX if
+ *   no match was found. Subsequent occurrences can be found by calling
  *   textsearch_next() regardless of the linearity of the data.
  *
  *   Once you're done using a configuration it must be given back via
index 3ad483b..e9c0c61 100644 (file)
@@ -179,7 +179,7 @@ config SPLIT_PTLOCK_CPUS
 config COMPACTION
        bool "Allow for memory compaction"
        select MIGRATION
-       depends on EXPERIMENTAL && HUGETLB_PAGE && MMU
+       depends on MMU
        help
          Allows the compaction of memory for the allocation of huge pages.
 
index 2b1b575..42a8326 100644 (file)
@@ -7,7 +7,7 @@ mmu-$(CONFIG_MMU)       := fremap.o highmem.o madvise.o memory.o mincore.o \
                           mlock.o mmap.o mprotect.o mremap.o msync.o rmap.o \
                           vmalloc.o pagewalk.o pgtable-generic.o
 
-obj-y                  := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \
+obj-y                  := filemap.o mempool.o oom_kill.o fadvise.o \
                           maccess.o page_alloc.o page-writeback.o \
                           readahead.o swap.o truncate.o vmscan.o shmem.o \
                           prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \
@@ -15,6 +15,12 @@ obj-y                        := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \
                           $(mmu-y)
 obj-y += init-mm.o
 
+ifdef CONFIG_NO_BOOTMEM
+       obj-y           += nobootmem.o
+else
+       obj-y           += bootmem.o
+endif
+
 obj-$(CONFIG_HAVE_MEMBLOCK) += memblock.o
 
 obj-$(CONFIG_BOUNCE)   += bounce.o
index 13b0caa..07aeb89 100644 (file)
 
 #include "internal.h"
 
+#ifndef CONFIG_NEED_MULTIPLE_NODES
+struct pglist_data __refdata contig_page_data = {
+       .bdata = &bootmem_node_data[0]
+};
+EXPORT_SYMBOL(contig_page_data);
+#endif
+
 unsigned long max_low_pfn;
 unsigned long min_low_pfn;
 unsigned long max_pfn;
@@ -35,7 +42,6 @@ unsigned long max_pfn;
 unsigned long saved_max_pfn;
 #endif
 
-#ifndef CONFIG_NO_BOOTMEM
 bootmem_data_t bootmem_node_data[MAX_NUMNODES] __initdata;
 
 static struct list_head bdata_list __initdata = LIST_HEAD_INIT(bdata_list);
@@ -146,7 +152,7 @@ unsigned long __init init_bootmem(unsigned long start, unsigned long pages)
        min_low_pfn = start;
        return init_bootmem_core(NODE_DATA(0)->bdata, start, 0, pages);
 }
-#endif
+
 /*
  * free_bootmem_late - free bootmem pages directly to page allocator
  * @addr: starting address of the range
@@ -171,53 +177,6 @@ void __init free_bootmem_late(unsigned long addr, unsigned long size)
        }
 }
 
-#ifdef CONFIG_NO_BOOTMEM
-static void __init __free_pages_memory(unsigned long start, unsigned long end)
-{
-       int i;
-       unsigned long start_aligned, end_aligned;
-       int order = ilog2(BITS_PER_LONG);
-
-       start_aligned = (start + (BITS_PER_LONG - 1)) & ~(BITS_PER_LONG - 1);
-       end_aligned = end & ~(BITS_PER_LONG - 1);
-
-       if (end_aligned <= start_aligned) {
-               for (i = start; i < end; i++)
-                       __free_pages_bootmem(pfn_to_page(i), 0);
-
-               return;
-       }
-
-       for (i = start; i < start_aligned; i++)
-               __free_pages_bootmem(pfn_to_page(i), 0);
-
-       for (i = start_aligned; i < end_aligned; i += BITS_PER_LONG)
-               __free_pages_bootmem(pfn_to_page(i), order);
-
-       for (i = end_aligned; i < end; i++)
-               __free_pages_bootmem(pfn_to_page(i), 0);
-}
-
-unsigned long __init free_all_memory_core_early(int nodeid)
-{
-       int i;
-       u64 start, end;
-       unsigned long count = 0;
-       struct range *range = NULL;
-       int nr_range;
-
-       nr_range = get_free_all_memory_range(&range, nodeid);
-
-       for (i = 0; i < nr_range; i++) {
-               start = range[i].start;
-               end = range[i].end;
-               count += end - start;
-               __free_pages_memory(start, end);
-       }
-
-       return count;
-}
-#else
 static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
 {
        int aligned;
@@ -278,7 +237,6 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
 
        return count;
 }
-#endif
 
 /**
  * free_all_bootmem_node - release a node's free pages to the buddy allocator
@@ -289,12 +247,7 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
 unsigned long __init free_all_bootmem_node(pg_data_t *pgdat)
 {
        register_page_bootmem_info_node(pgdat);
-#ifdef CONFIG_NO_BOOTMEM
-       /* free_all_memory_core_early(MAX_NUMNODES) will be called later */
-       return 0;
-#else
        return free_all_bootmem_core(pgdat->bdata);
-#endif
 }
 
 /**
@@ -304,16 +257,6 @@ unsigned long __init free_all_bootmem_node(pg_data_t *pgdat)
  */
 unsigned long __init free_all_bootmem(void)
 {
-#ifdef CONFIG_NO_BOOTMEM
-       /*
-        * We need to use MAX_NUMNODES instead of NODE_DATA(0)->node_id
-        *  because in some case like Node0 doesnt have RAM installed
-        *  low ram will be on Node1
-        * Use MAX_NUMNODES will make sure all ranges in early_node_map[]
-        *  will be used instead of only Node0 related
-        */
-       return free_all_memory_core_early(MAX_NUMNODES);
-#else
        unsigned long total_pages = 0;
        bootmem_data_t *bdata;
 
@@ -321,10 +264,8 @@ unsigned long __init free_all_bootmem(void)
                total_pages += free_all_bootmem_core(bdata);
 
        return total_pages;
-#endif
 }
 
-#ifndef CONFIG_NO_BOOTMEM
 static void __init __free(bootmem_data_t *bdata,
                        unsigned long sidx, unsigned long eidx)
 {
@@ -419,7 +360,6 @@ static int __init mark_bootmem(unsigned long start, unsigned long end,
        }
        BUG();
 }
-#endif
 
 /**
  * free_bootmem_node - mark a page range as usable
@@ -434,10 +374,6 @@ static int __init mark_bootmem(unsigned long start, unsigned long end,
 void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
                              unsigned long size)
 {
-#ifdef CONFIG_NO_BOOTMEM
-       kmemleak_free_part(__va(physaddr), size);
-       memblock_x86_free_range(physaddr, physaddr + size);
-#else
        unsigned long start, end;
 
        kmemleak_free_part(__va(physaddr), size);
@@ -446,7 +382,6 @@ void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
        end = PFN_DOWN(physaddr + size);
 
        mark_bootmem_node(pgdat->bdata, start, end, 0, 0);
-#endif
 }
 
 /**
@@ -460,10 +395,6 @@ void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
  */
 void __init free_bootmem(unsigned long addr, unsigned long size)
 {
-#ifdef CONFIG_NO_BOOTMEM
-       kmemleak_free_part(__va(addr), size);
-       memblock_x86_free_range(addr, addr + size);
-#else
        unsigned long start, end;
 
        kmemleak_free_part(__va(addr), size);
@@ -472,7 +403,6 @@ void __init free_bootmem(unsigned long addr, unsigned long size)
        end = PFN_DOWN(addr + size);
 
        mark_bootmem(start, end, 0, 0);
-#endif
 }
 
 /**
@@ -489,17 +419,12 @@ void __init free_bootmem(unsigned long addr, unsigned long size)
 int __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
                                 unsigned long size, int flags)
 {
-#ifdef CONFIG_NO_BOOTMEM
-       panic("no bootmem");
-       return 0;
-#else
        unsigned long start, end;
 
        start = PFN_DOWN(physaddr);
        end = PFN_UP(physaddr + size);
 
        return mark_bootmem_node(pgdat->bdata, start, end, 1, flags);
-#endif
 }
 
 /**
@@ -515,20 +440,14 @@ int __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
 int __init reserve_bootmem(unsigned long addr, unsigned long size,
                            int flags)
 {
-#ifdef CONFIG_NO_BOOTMEM
-       panic("no bootmem");
-       return 0;
-#else
        unsigned long start, end;
 
        start = PFN_DOWN(addr);
        end = PFN_UP(addr + size);
 
        return mark_bootmem(start, end, 1, flags);
-#endif
 }
 
-#ifndef CONFIG_NO_BOOTMEM
 int __weak __init reserve_bootmem_generic(unsigned long phys, unsigned long len,
                                   int flags)
 {
@@ -685,33 +604,12 @@ static void * __init alloc_arch_preferred_bootmem(bootmem_data_t *bdata,
 #endif
        return NULL;
 }
-#endif
 
 static void * __init ___alloc_bootmem_nopanic(unsigned long size,
                                        unsigned long align,
                                        unsigned long goal,
                                        unsigned long limit)
 {
-#ifdef CONFIG_NO_BOOTMEM
-       void *ptr;
-
-       if (WARN_ON_ONCE(slab_is_available()))
-               return kzalloc(size, GFP_NOWAIT);
-
-restart:
-
-       ptr = __alloc_memory_core_early(MAX_NUMNODES, size, align, goal, limit);
-
-       if (ptr)
-               return ptr;
-
-       if (goal != 0) {
-               goal = 0;
-               goto restart;
-       }
-
-       return NULL;
-#else
        bootmem_data_t *bdata;
        void *region;
 
@@ -737,7 +635,6 @@ restart:
        }
 
        return NULL;
-#endif
 }
 
 /**
@@ -758,10 +655,6 @@ void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align,
 {
        unsigned long limit = 0;
 
-#ifdef CONFIG_NO_BOOTMEM
-       limit = -1UL;
-#endif
-
        return ___alloc_bootmem_nopanic(size, align, goal, limit);
 }
 
@@ -798,14 +691,9 @@ void * __init __alloc_bootmem(unsigned long size, unsigned long align,
 {
        unsigned long limit = 0;
 
-#ifdef CONFIG_NO_BOOTMEM
-       limit = -1UL;
-#endif
-
        return ___alloc_bootmem(size, align, goal, limit);
 }
 
-#ifndef CONFIG_NO_BOOTMEM
 static void * __init ___alloc_bootmem_node(bootmem_data_t *bdata,
                                unsigned long size, unsigned long align,
                                unsigned long goal, unsigned long limit)
@@ -822,7 +710,6 @@ static void * __init ___alloc_bootmem_node(bootmem_data_t *bdata,
 
        return ___alloc_bootmem(size, align, goal, limit);
 }
-#endif
 
 /**
  * __alloc_bootmem_node - allocate boot memory from a specific node
@@ -842,24 +729,10 @@ static void * __init ___alloc_bootmem_node(bootmem_data_t *bdata,
 void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size,
                                   unsigned long align, unsigned long goal)
 {
-       void *ptr;
-
        if (WARN_ON_ONCE(slab_is_available()))
                return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
 
-#ifdef CONFIG_NO_BOOTMEM
-       ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
-                                        goal, -1ULL);
-       if (ptr)
-               return ptr;
-
-       ptr = __alloc_memory_core_early(MAX_NUMNODES, size, align,
-                                        goal, -1ULL);
-#else
-       ptr = ___alloc_bootmem_node(pgdat->bdata, size, align, goal, 0);
-#endif
-
-       return ptr;
+       return  ___alloc_bootmem_node(pgdat->bdata, size, align, goal, 0);
 }
 
 void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size,
@@ -880,13 +753,8 @@ void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size,
                unsigned long new_goal;
 
                new_goal = MAX_DMA32_PFN << PAGE_SHIFT;
-#ifdef CONFIG_NO_BOOTMEM
-               ptr =  __alloc_memory_core_early(pgdat->node_id, size, align,
-                                                new_goal, -1ULL);
-#else
                ptr = alloc_bootmem_core(pgdat->bdata, size, align,
                                                 new_goal, 0);
-#endif
                if (ptr)
                        return ptr;
        }
@@ -907,16 +775,6 @@ void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size,
 void * __init alloc_bootmem_section(unsigned long size,
                                    unsigned long section_nr)
 {
-#ifdef CONFIG_NO_BOOTMEM
-       unsigned long pfn, goal, limit;
-
-       pfn = section_nr_to_pfn(section_nr);
-       goal = pfn << PAGE_SHIFT;
-       limit = section_nr_to_pfn(section_nr + 1) << PAGE_SHIFT;
-
-       return __alloc_memory_core_early(early_pfn_to_nid(pfn), size,
-                                        SMP_CACHE_BYTES, goal, limit);
-#else
        bootmem_data_t *bdata;
        unsigned long pfn, goal, limit;
 
@@ -926,7 +784,6 @@ void * __init alloc_bootmem_section(unsigned long size,
        bdata = &bootmem_node_data[early_pfn_to_nid(pfn)];
 
        return alloc_bootmem_core(bdata, size, SMP_CACHE_BYTES, goal, limit);
-#endif
 }
 #endif
 
@@ -938,16 +795,11 @@ void * __init __alloc_bootmem_node_nopanic(pg_data_t *pgdat, unsigned long size,
        if (WARN_ON_ONCE(slab_is_available()))
                return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
 
-#ifdef CONFIG_NO_BOOTMEM
-       ptr =  __alloc_memory_core_early(pgdat->node_id, size, align,
-                                                goal, -1ULL);
-#else
        ptr = alloc_arch_preferred_bootmem(pgdat->bdata, size, align, goal, 0);
        if (ptr)
                return ptr;
 
        ptr = alloc_bootmem_core(pgdat->bdata, size, align, goal, 0);
-#endif
        if (ptr)
                return ptr;
 
@@ -995,21 +847,9 @@ void * __init __alloc_bootmem_low(unsigned long size, unsigned long align,
 void * __init __alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size,
                                       unsigned long align, unsigned long goal)
 {
-       void *ptr;
-
        if (WARN_ON_ONCE(slab_is_available()))
                return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
 
-#ifdef CONFIG_NO_BOOTMEM
-       ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
+       return ___alloc_bootmem_node(pgdat->bdata, size, align,
                                goal, ARCH_LOW_ADDRESS_LIMIT);
-       if (ptr)
-               return ptr;
-       ptr = __alloc_memory_core_early(MAX_NUMNODES, size, align,
-                               goal, ARCH_LOW_ADDRESS_LIMIT);
-#else
-       ptr = ___alloc_bootmem_node(pgdat->bdata, size, align,
-                               goal, ARCH_LOW_ADDRESS_LIMIT);
-#endif
-       return ptr;
 }
index e187454..113e35c 100644 (file)
@@ -650,10 +650,10 @@ static inline gfp_t alloc_hugepage_gfpmask(int defrag)
 
 static inline struct page *alloc_hugepage_vma(int defrag,
                                              struct vm_area_struct *vma,
-                                             unsigned long haddr)
+                                             unsigned long haddr, int nd)
 {
        return alloc_pages_vma(alloc_hugepage_gfpmask(defrag),
-                              HPAGE_PMD_ORDER, vma, haddr);
+                              HPAGE_PMD_ORDER, vma, haddr, nd);
 }
 
 #ifndef CONFIG_NUMA
@@ -678,7 +678,7 @@ int do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
                if (unlikely(khugepaged_enter(vma)))
                        return VM_FAULT_OOM;
                page = alloc_hugepage_vma(transparent_hugepage_defrag(vma),
-                                         vma, haddr);
+                                         vma, haddr, numa_node_id());
                if (unlikely(!page))
                        goto out;
                if (unlikely(mem_cgroup_newpage_charge(page, mm, GFP_KERNEL))) {
@@ -799,8 +799,8 @@ static int do_huge_pmd_wp_page_fallback(struct mm_struct *mm,
        }
 
        for (i = 0; i < HPAGE_PMD_NR; i++) {
-               pages[i] = alloc_page_vma(GFP_HIGHUSER_MOVABLE,
-                                         vma, address);
+               pages[i] = alloc_page_vma_node(GFP_HIGHUSER_MOVABLE,
+                                              vma, address, page_to_nid(page));
                if (unlikely(!pages[i] ||
                             mem_cgroup_newpage_charge(pages[i], mm,
                                                       GFP_KERNEL))) {
@@ -902,7 +902,7 @@ int do_huge_pmd_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
        if (transparent_hugepage_enabled(vma) &&
            !transparent_hugepage_debug_cow())
                new_page = alloc_hugepage_vma(transparent_hugepage_defrag(vma),
-                                             vma, haddr);
+                                             vma, haddr, numa_node_id());
        else
                new_page = NULL;
 
@@ -1162,7 +1162,12 @@ static void __split_huge_page_refcount(struct page *page)
                /* after clearing PageTail the gup refcount can be released */
                smp_mb();
 
-               page_tail->flags &= ~PAGE_FLAGS_CHECK_AT_PREP;
+               /*
+                * retain hwpoison flag of the poisoned tail page:
+                *   fix for the unsuitable process killed on Guest Machine(KVM)
+                *   by the memory-failure.
+                */
+               page_tail->flags &= ~PAGE_FLAGS_CHECK_AT_PREP | __PG_HWPOISON;
                page_tail->flags |= (page->flags &
                                     ((1L << PG_referenced) |
                                      (1L << PG_swapbacked) |
@@ -1740,7 +1745,8 @@ static void __collapse_huge_page_copy(pte_t *pte, struct page *page,
 static void collapse_huge_page(struct mm_struct *mm,
                               unsigned long address,
                               struct page **hpage,
-                              struct vm_area_struct *vma)
+                              struct vm_area_struct *vma,
+                              int node)
 {
        pgd_t *pgd;
        pud_t *pud;
@@ -1756,6 +1762,10 @@ static void collapse_huge_page(struct mm_struct *mm,
 #ifndef CONFIG_NUMA
        VM_BUG_ON(!*hpage);
        new_page = *hpage;
+       if (unlikely(mem_cgroup_newpage_charge(new_page, mm, GFP_KERNEL))) {
+               up_read(&mm->mmap_sem);
+               return;
+       }
 #else
        VM_BUG_ON(*hpage);
        /*
@@ -1768,18 +1778,19 @@ static void collapse_huge_page(struct mm_struct *mm,
         * mmap_sem in read mode is good idea also to allow greater
         * scalability.
         */
-       new_page = alloc_hugepage_vma(khugepaged_defrag(), vma, address);
+       new_page = alloc_hugepage_vma(khugepaged_defrag(), vma, address,
+                                     node);
        if (unlikely(!new_page)) {
                up_read(&mm->mmap_sem);
                *hpage = ERR_PTR(-ENOMEM);
                return;
        }
-#endif
        if (unlikely(mem_cgroup_newpage_charge(new_page, mm, GFP_KERNEL))) {
                up_read(&mm->mmap_sem);
                put_page(new_page);
                return;
        }
+#endif
 
        /* after allocating the hugepage upgrade to mmap_sem write mode */
        up_read(&mm->mmap_sem);
@@ -1806,6 +1817,8 @@ static void collapse_huge_page(struct mm_struct *mm,
        /* VM_PFNMAP vmas may have vm_ops null but vm_file set */
        if (!vma->anon_vma || vma->vm_ops || vma->vm_file)
                goto out;
+       if (is_vma_temporary_stack(vma))
+               goto out;
        VM_BUG_ON(is_linear_pfn_mapping(vma) || is_pfn_mapping(vma));
 
        pgd = pgd_offset(mm, address);
@@ -1847,7 +1860,6 @@ static void collapse_huge_page(struct mm_struct *mm,
                set_pmd_at(mm, address, pmd, _pmd);
                spin_unlock(&mm->page_table_lock);
                anon_vma_unlock(vma->anon_vma);
-               mem_cgroup_uncharge_page(new_page);
                goto out;
        }
 
@@ -1893,6 +1905,7 @@ out_up_write:
        return;
 
 out:
+       mem_cgroup_uncharge_page(new_page);
 #ifdef CONFIG_NUMA
        put_page(new_page);
 #endif
@@ -1912,6 +1925,7 @@ static int khugepaged_scan_pmd(struct mm_struct *mm,
        struct page *page;
        unsigned long _address;
        spinlock_t *ptl;
+       int node = -1;
 
        VM_BUG_ON(address & ~HPAGE_PMD_MASK);
 
@@ -1942,6 +1956,13 @@ static int khugepaged_scan_pmd(struct mm_struct *mm,
                page = vm_normal_page(vma, _address, pteval);
                if (unlikely(!page))
                        goto out_unmap;
+               /*
+                * Chose the node of the first page. This could
+                * be more sophisticated and look at more pages,
+                * but isn't for now.
+                */
+               if (node == -1)
+                       node = page_to_nid(page);
                VM_BUG_ON(PageCompound(page));
                if (!PageLRU(page) || PageLocked(page) || !PageAnon(page))
                        goto out_unmap;
@@ -1958,7 +1979,7 @@ out_unmap:
        pte_unmap_unlock(pte, ptl);
        if (ret)
                /* collapse_huge_page will return with the mmap_sem released */
-               collapse_huge_page(mm, address, hpage, vma);
+               collapse_huge_page(mm, address, hpage, vma, node);
 out:
        return ret;
 }
@@ -2027,32 +2048,27 @@ static unsigned int khugepaged_scan_mm_slot(unsigned int pages,
                if ((!(vma->vm_flags & VM_HUGEPAGE) &&
                     !khugepaged_always()) ||
                    (vma->vm_flags & VM_NOHUGEPAGE)) {
+               skip:
                        progress++;
                        continue;
                }
-
                /* VM_PFNMAP vmas may have vm_ops null but vm_file set */
-               if (!vma->anon_vma || vma->vm_ops || vma->vm_file) {
-                       khugepaged_scan.address = vma->vm_end;
-                       progress++;
-                       continue;
-               }
+               if (!vma->anon_vma || vma->vm_ops || vma->vm_file)
+                       goto skip;
+               if (is_vma_temporary_stack(vma))
+                       goto skip;
+
                VM_BUG_ON(is_linear_pfn_mapping(vma) || is_pfn_mapping(vma));
 
                hstart = (vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK;
                hend = vma->vm_end & HPAGE_PMD_MASK;
-               if (hstart >= hend) {
-                       progress++;
-                       continue;
-               }
+               if (hstart >= hend)
+                       goto skip;
+               if (khugepaged_scan.address > hend)
+                       goto skip;
                if (khugepaged_scan.address < hstart)
                        khugepaged_scan.address = hstart;
-               if (khugepaged_scan.address > hend) {
-                       khugepaged_scan.address = hend + HPAGE_PMD_SIZE;
-                       progress++;
-                       continue;
-               }
-               BUG_ON(khugepaged_scan.address & ~HPAGE_PMD_MASK);
+               VM_BUG_ON(khugepaged_scan.address & ~HPAGE_PMD_MASK);
 
                while (khugepaged_scan.address < hend) {
                        int ret;
@@ -2081,7 +2097,7 @@ breakouterloop:
 breakouterloop_mmap_sem:
 
        spin_lock(&khugepaged_mm_lock);
-       BUG_ON(khugepaged_scan.mm_slot != mm_slot);
+       VM_BUG_ON(khugepaged_scan.mm_slot != mm_slot);
        /*
         * Release the current mm_slot if this mm is about to die, or
         * if we scanned all vmas of this mm.
@@ -2236,9 +2252,9 @@ static int khugepaged(void *none)
 
        for (;;) {
                mutex_unlock(&khugepaged_mutex);
-               BUG_ON(khugepaged_thread != current);
+               VM_BUG_ON(khugepaged_thread != current);
                khugepaged_loop();
-               BUG_ON(khugepaged_thread != current);
+               VM_BUG_ON(khugepaged_thread != current);
 
                mutex_lock(&khugepaged_mutex);
                if (!khugepaged_enabled())
index 177a516..ff0d977 100644 (file)
@@ -75,13 +75,11 @@ static int __init kmemleak_test_init(void)
         * after the module is removed.
         */
        for (i = 0; i < 10; i++) {
-               elem = kmalloc(sizeof(*elem), GFP_KERNEL);
-               pr_info("kmemleak: kmalloc(sizeof(*elem)) = %p\n", elem);
+               elem = kzalloc(sizeof(*elem), GFP_KERNEL);
+               pr_info("kmemleak: kzalloc(sizeof(*elem)) = %p\n", elem);
                if (!elem)
                        return -ENOMEM;
-               memset(elem, 0, sizeof(*elem));
                INIT_LIST_HEAD(&elem->list);
-
                list_add_tail(&elem->list, &test_list);
        }
 
index bd9bc21..84225f3 100644 (file)
 #define BYTES_PER_POINTER      sizeof(void *)
 
 /* GFP bitmask for kmemleak internal allocations */
-#define GFP_KMEMLEAK_MASK      (GFP_KERNEL | GFP_ATOMIC)
+#define gfp_kmemleak_mask(gfp) (((gfp) & (GFP_KERNEL | GFP_ATOMIC)) | \
+                                __GFP_NORETRY | __GFP_NOMEMALLOC | \
+                                __GFP_NOWARN)
 
 /* scanning area inside a memory block */
 struct kmemleak_scan_area {
@@ -511,9 +513,10 @@ static struct kmemleak_object *create_object(unsigned long ptr, size_t size,
        struct kmemleak_object *object;
        struct prio_tree_node *node;
 
-       object = kmem_cache_alloc(object_cache, gfp & GFP_KMEMLEAK_MASK);
+       object = kmem_cache_alloc(object_cache, gfp_kmemleak_mask(gfp));
        if (!object) {
-               kmemleak_stop("Cannot allocate a kmemleak_object structure\n");
+               pr_warning("Cannot allocate a kmemleak_object structure\n");
+               kmemleak_disable();
                return NULL;
        }
 
@@ -734,9 +737,9 @@ static void add_scan_area(unsigned long ptr, size_t size, gfp_t gfp)
                return;
        }
 
-       area = kmem_cache_alloc(scan_area_cache, gfp & GFP_KMEMLEAK_MASK);
+       area = kmem_cache_alloc(scan_area_cache, gfp_kmemleak_mask(gfp));
        if (!area) {
-               kmemleak_warn("Cannot allocate a scan area\n");
+               pr_warning("Cannot allocate a scan area\n");
                goto out;
        }
 
index bdba245..4618fda 100644 (file)
@@ -137,8 +137,6 @@ static phys_addr_t __init_memblock memblock_find_base(phys_addr_t size,
 
        BUG_ON(0 == size);
 
-       size = memblock_align_up(size, align);
-
        /* Pump up max_addr */
        if (end == MEMBLOCK_ALLOC_ACCESSIBLE)
                end = memblock.current_limit;
index db76ef7..da53a25 100644 (file)
@@ -612,8 +612,10 @@ static void mem_cgroup_charge_statistics(struct mem_cgroup *mem,
        /* pagein of a big page is an event. So, ignore page size */
        if (nr_pages > 0)
                __this_cpu_inc(mem->stat->count[MEM_CGROUP_STAT_PGPGIN_COUNT]);
-       else
+       else {
                __this_cpu_inc(mem->stat->count[MEM_CGROUP_STAT_PGPGOUT_COUNT]);
+               nr_pages = -nr_pages; /* for event */
+       }
 
        __this_cpu_add(mem->stat->count[MEM_CGROUP_EVENTS], nr_pages);
 
@@ -1111,6 +1113,23 @@ static bool mem_cgroup_check_under_limit(struct mem_cgroup *mem)
        return false;
 }
 
+/**
+ * mem_cgroup_check_margin - check if the memory cgroup allows charging
+ * @mem: memory cgroup to check
+ * @bytes: the number of bytes the caller intends to charge
+ *
+ * Returns a boolean value on whether @mem can be charged @bytes or
+ * whether this would exceed the limit.
+ */
+static bool mem_cgroup_check_margin(struct mem_cgroup *mem, unsigned long bytes)
+{
+       if (!res_counter_check_margin(&mem->res, bytes))
+               return false;
+       if (do_swap_account && !res_counter_check_margin(&mem->memsw, bytes))
+               return false;
+       return true;
+}
+
 static unsigned int get_swappiness(struct mem_cgroup *memcg)
 {
        struct cgroup *cgrp = memcg->css.cgroup;
@@ -1832,27 +1851,39 @@ static int __mem_cgroup_do_charge(struct mem_cgroup *mem, gfp_t gfp_mask,
                if (likely(!ret))
                        return CHARGE_OK;
 
+               res_counter_uncharge(&mem->res, csize);
                mem_over_limit = mem_cgroup_from_res_counter(fail_res, memsw);
                flags |= MEM_CGROUP_RECLAIM_NOSWAP;
        } else
                mem_over_limit = mem_cgroup_from_res_counter(fail_res, res);
-
-       if (csize > PAGE_SIZE) /* change csize and retry */
+       /*
+        * csize can be either a huge page (HPAGE_SIZE), a batch of
+        * regular pages (CHARGE_SIZE), or a single regular page
+        * (PAGE_SIZE).
+        *
+        * Never reclaim on behalf of optional batching, retry with a
+        * single page instead.
+        */
+       if (csize == CHARGE_SIZE)
                return CHARGE_RETRY;
 
        if (!(gfp_mask & __GFP_WAIT))
                return CHARGE_WOULDBLOCK;
 
        ret = mem_cgroup_hierarchical_reclaim(mem_over_limit, NULL,
-                                       gfp_mask, flags);
+                                             gfp_mask, flags);
+       if (mem_cgroup_check_margin(mem_over_limit, csize))
+               return CHARGE_RETRY;
        /*
-        * try_to_free_mem_cgroup_pages() might not give us a full
-        * picture of reclaim. Some pages are reclaimed and might be
-        * moved to swap cache or just unmapped from the cgroup.
-        * Check the limit again to see if the reclaim reduced the
-        * current usage of the cgroup before giving up
+        * Even though the limit is exceeded at this point, reclaim
+        * may have been able to free some pages.  Retry the charge
+        * before killing the task.
+        *
+        * Only for regular pages, though: huge pages are rather
+        * unlikely to succeed so close to the limit, and we fall back
+        * to regular pages anyway in case of failure.
         */
-       if (ret || mem_cgroup_check_under_limit(mem_over_limit))
+       if (csize == PAGE_SIZE && ret)
                return CHARGE_RETRY;
 
        /*
@@ -2144,6 +2175,8 @@ void mem_cgroup_split_huge_fixup(struct page *head, struct page *tail)
        struct page_cgroup *tail_pc = lookup_page_cgroup(tail);
        unsigned long flags;
 
+       if (mem_cgroup_disabled())
+               return;
        /*
         * We have no races with charge/uncharge but will have races with
         * page state accounting.
@@ -2233,7 +2266,12 @@ static int mem_cgroup_move_account(struct page_cgroup *pc,
 {
        int ret = -EINVAL;
        unsigned long flags;
-
+       /*
+        * The page is isolated from LRU. So, collapse function
+        * will not handle this page. But page splitting can happen.
+        * Do this check under compound_page_lock(). The caller should
+        * hold it.
+        */
        if ((charge_size > PAGE_SIZE) && !PageTransHuge(pc->page))
                return -EBUSY;
 
@@ -2265,7 +2303,7 @@ static int mem_cgroup_move_parent(struct page_cgroup *pc,
        struct cgroup *cg = child->css.cgroup;
        struct cgroup *pcg = cg->parent;
        struct mem_cgroup *parent;
-       int charge = PAGE_SIZE;
+       int page_size = PAGE_SIZE;
        unsigned long flags;
        int ret;
 
@@ -2278,23 +2316,26 @@ static int mem_cgroup_move_parent(struct page_cgroup *pc,
                goto out;
        if (isolate_lru_page(page))
                goto put;
-       /* The page is isolated from LRU and we have no race with splitting */
-       charge = PAGE_SIZE << compound_order(page);
+
+       if (PageTransHuge(page))
+               page_size = HPAGE_SIZE;
 
        parent = mem_cgroup_from_cont(pcg);
-       ret = __mem_cgroup_try_charge(NULL, gfp_mask, &parent, false, charge);
+       ret = __mem_cgroup_try_charge(NULL, gfp_mask,
+                               &parent, false, page_size);
        if (ret || !parent)
                goto put_back;
 
-       if (charge > PAGE_SIZE)
+       if (page_size > PAGE_SIZE)
                flags = compound_lock_irqsave(page);
 
-       ret = mem_cgroup_move_account(pc, child, parent, true, charge);
+       ret = mem_cgroup_move_account(pc, child, parent, true, page_size);
        if (ret)
-               mem_cgroup_cancel_charge(parent, charge);
-put_back:
-       if (charge > PAGE_SIZE)
+               mem_cgroup_cancel_charge(parent, page_size);
+
+       if (page_size > PAGE_SIZE)
                compound_unlock_irqrestore(page, flags);
+put_back:
        putback_lru_page(page);
 put:
        put_page(page);
@@ -2312,13 +2353,19 @@ static int mem_cgroup_charge_common(struct page *page, struct mm_struct *mm,
                                gfp_t gfp_mask, enum charge_type ctype)
 {
        struct mem_cgroup *mem = NULL;
+       int page_size = PAGE_SIZE;
        struct page_cgroup *pc;
+       bool oom = true;
        int ret;
-       int page_size = PAGE_SIZE;
 
        if (PageTransHuge(page)) {
                page_size <<= compound_order(page);
                VM_BUG_ON(!PageTransHuge(page));
+               /*
+                * Never OOM-kill a process for a huge page.  The
+                * fault handler will fall back to regular pages.
+                */
+               oom = false;
        }
 
        pc = lookup_page_cgroup(page);
@@ -2327,7 +2374,7 @@ static int mem_cgroup_charge_common(struct page *page, struct mm_struct *mm,
                return 0;
        prefetchw(pc);
 
-       ret = __mem_cgroup_try_charge(mm, gfp_mask, &mem, true, page_size);
+       ret = __mem_cgroup_try_charge(mm, gfp_mask, &mem, oom, page_size);
        if (ret || !mem)
                return ret;
 
@@ -5013,9 +5060,9 @@ struct cgroup_subsys mem_cgroup_subsys = {
 static int __init enable_swap_account(char *s)
 {
        /* consider enabled if no parameter or 1 is given */
-       if (!s || !strcmp(s, "1"))
+       if (!(*s) || !strcmp(s, "=1"))
                really_do_swap_account = 1;
-       else if (!strcmp(s, "0"))
+       else if (!strcmp(s, "=0"))
                really_do_swap_account = 0;
        return 1;
 }
@@ -5023,7 +5070,8 @@ __setup("swapaccount", enable_swap_account);
 
 static int __init disable_swap_account(char *s)
 {
-       enable_swap_account("0");
+       printk_once("noswapaccount is deprecated and will be removed in 2.6.40. Use swapaccount=0 instead\n");
+       enable_swap_account("=0");
        return 1;
 }
 __setup("noswapaccount", disable_swap_account);
index 548fbd7..0207c2f 100644 (file)
@@ -233,8 +233,8 @@ void shake_page(struct page *p, int access)
        }
 
        /*
-        * Only all shrink_slab here (which would also
-        * shrink other caches) if access is not potentially fatal.
+        * Only call shrink_slab here (which would also shrink other caches) if
+        * access is not potentially fatal.
         */
        if (access) {
                int nr;
@@ -386,8 +386,6 @@ static void collect_procs_anon(struct page *page, struct list_head *to_kill,
        struct task_struct *tsk;
        struct anon_vma *av;
 
-       if (!PageHuge(page) && unlikely(split_huge_page(page)))
-               return;
        read_lock(&tasklist_lock);
        av = page_lock_anon_vma(page);
        if (av == NULL) /* Not actually mapped anymore */
@@ -856,6 +854,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
        int ret;
        int kill = 1;
        struct page *hpage = compound_head(p);
+       struct page *ppage;
 
        if (PageReserved(p) || PageSlab(p))
                return SWAP_SUCCESS;
@@ -896,6 +895,44 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
                }
        }
 
+       /*
+        * ppage: poisoned page
+        *   if p is regular page(4k page)
+        *        ppage == real poisoned page;
+        *   else p is hugetlb or THP, ppage == head page.
+        */
+       ppage = hpage;
+
+       if (PageTransHuge(hpage)) {
+               /*
+                * Verify that this isn't a hugetlbfs head page, the check for
+                * PageAnon is just for avoid tripping a split_huge_page
+                * internal debug check, as split_huge_page refuses to deal with
+                * anything that isn't an anon page. PageAnon can't go away fro
+                * under us because we hold a refcount on the hpage, without a
+                * refcount on the hpage. split_huge_page can't be safely called
+                * in the first place, having a refcount on the tail isn't
+                * enough * to be safe.
+                */
+               if (!PageHuge(hpage) && PageAnon(hpage)) {
+                       if (unlikely(split_huge_page(hpage))) {
+                               /*
+                                * FIXME: if splitting THP is failed, it is
+                                * better to stop the following operation rather
+                                * than causing panic by unmapping. System might
+                                * survive if the page is freed later.
+                                */
+                               printk(KERN_INFO
+                                       "MCE %#lx: failed to split THP\n", pfn);
+
+                               BUG_ON(!PageHWPoison(p));
+                               return SWAP_FAIL;
+                       }
+                       /* THP is split, so ppage should be the real poisoned page. */
+                       ppage = p;
+               }
+       }
+
        /*
         * First collect all the processes that have the page
         * mapped in dirty form.  This has to be done before try_to_unmap,
@@ -905,12 +942,18 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
         * there's nothing that can be done.
         */
        if (kill)
-               collect_procs(hpage, &tokill);
+               collect_procs(ppage, &tokill);
+
+       if (hpage != ppage)
+               lock_page_nosync(ppage);
 
-       ret = try_to_unmap(hpage, ttu);
+       ret = try_to_unmap(ppage, ttu);
        if (ret != SWAP_SUCCESS)
                printk(KERN_ERR "MCE %#lx: failed to unmap page (mapcount=%d)\n",
-                               pfn, page_mapcount(hpage));
+                               pfn, page_mapcount(ppage));
+
+       if (hpage != ppage)
+               unlock_page(ppage);
 
        /*
         * Now that the dirty bit has been propagated to the
@@ -921,7 +964,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
         * use a more force-full uncatchable kill to prevent
         * any accesses to the poisoned memory.
         */
-       kill_procs_ao(&tokill, !!PageDirty(hpage), trapno,
+       kill_procs_ao(&tokill, !!PageDirty(ppage), trapno,
                      ret != SWAP_SUCCESS, p, pfn);
 
        return ret;
@@ -1022,19 +1065,22 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
         * The check (unnecessarily) ignores LRU pages being isolated and
         * walked by the page reclaim code, however that's not a big loss.
         */
-       if (!PageLRU(p) && !PageHuge(p))
-               shake_page(p, 0);
-       if (!PageLRU(p) && !PageHuge(p)) {
-               /*
-                * shake_page could have turned it free.
-                */
-               if (is_free_buddy_page(p)) {
-                       action_result(pfn, "free buddy, 2nd try", DELAYED);
-                       return 0;
+       if (!PageHuge(p) && !PageTransCompound(p)) {
+               if (!PageLRU(p))
+                       shake_page(p, 0);
+               if (!PageLRU(p)) {
+                       /*
+                        * shake_page could have turned it free.
+                        */
+                       if (is_free_buddy_page(p)) {
+                               action_result(pfn, "free buddy, 2nd try",
+                                               DELAYED);
+                               return 0;
+                       }
+                       action_result(pfn, "non LRU", IGNORED);
+                       put_page(p);
+                       return -EBUSY;
                }
-               action_result(pfn, "non LRU", IGNORED);
-               put_page(p);
-               return -EBUSY;
        }
 
        /*
@@ -1064,7 +1110,7 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
         * For error on the tail page, we should set PG_hwpoison
         * on the head page to show that the hugepage is hwpoisoned
         */
-       if (PageTail(p) && TestSetPageHWPoison(hpage)) {
+       if (PageHuge(p) && PageTail(p) && TestSetPageHWPoison(hpage)) {
                action_result(pfn, "hugepage already hardware poisoned",
                                IGNORED);
                unlock_page(hpage);
@@ -1295,7 +1341,10 @@ static int soft_offline_huge_page(struct page *page, int flags)
        ret = migrate_huge_pages(&pagelist, new_page, MPOL_MF_MOVE_ALL, 0,
                                true);
        if (ret) {
-               putback_lru_pages(&pagelist);
+               struct page *page1, *page2;
+               list_for_each_entry_safe(page1, page2, &pagelist, lru)
+                       put_page(page1);
+
                pr_debug("soft offline: %#lx: migration failed %d, type %lx\n",
                         pfn, ret, page->flags);
                if (ret > 0)
@@ -1419,6 +1468,7 @@ int soft_offline_page(struct page *page, int flags)
                ret = migrate_pages(&pagelist, new_page, MPOL_MF_MOVE_ALL,
                                                                0, true);
                if (ret) {
+                       putback_lru_pages(&pagelist);
                        pr_info("soft offline: %#lx: migration failed %d, type %lx\n",
                                pfn, ret, page->flags);
                        if (ret > 0)
index 31250fa..5823698 100644 (file)
@@ -2219,7 +2219,6 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
                                                         &ptl);
                        if (!pte_same(*page_table, orig_pte)) {
                                unlock_page(old_page);
-                               page_cache_release(old_page);
                                goto unlock;
                        }
                        page_cache_release(old_page);
@@ -2289,7 +2288,6 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
                                                         &ptl);
                        if (!pte_same(*page_table, orig_pte)) {
                                unlock_page(old_page);
-                               page_cache_release(old_page);
                                goto unlock;
                        }
 
@@ -2367,16 +2365,6 @@ gotten:
        }
        __SetPageUptodate(new_page);
 
-       /*
-        * Don't let another task, with possibly unlocked vma,
-        * keep the mlocked page.
-        */
-       if ((vma->vm_flags & VM_LOCKED) && old_page) {
-               lock_page(old_page);    /* for LRU manipulation */
-               clear_page_mlock(old_page);
-               unlock_page(old_page);
-       }
-
        if (mem_cgroup_newpage_charge(new_page, mm, GFP_KERNEL))
                goto oom_free_new;
 
@@ -2444,10 +2432,20 @@ gotten:
 
        if (new_page)
                page_cache_release(new_page);
-       if (old_page)
-               page_cache_release(old_page);
 unlock:
        pte_unmap_unlock(page_table, ptl);
+       if (old_page) {
+               /*
+                * Don't let another task, with possibly unlocked vma,
+                * keep the mlocked page.
+                */
+               if ((ret & VM_FAULT_WRITE) && (vma->vm_flags & VM_LOCKED)) {
+                       lock_page(old_page);    /* LRU manipulation */
+                       munlock_vma_page(old_page);
+                       unlock_page(old_page);
+               }
+               page_cache_release(old_page);
+       }
        return ret;
 oom_free_new:
        page_cache_release(new_page);
@@ -2650,6 +2648,7 @@ void unmap_mapping_range(struct address_space *mapping,
                details.last_index = ULONG_MAX;
        details.i_mmap_lock = &mapping->i_mmap_lock;
 
+       mutex_lock(&mapping->unmap_mutex);
        spin_lock(&mapping->i_mmap_lock);
 
        /* Protect against endless unmapping loops */
@@ -2666,6 +2665,7 @@ void unmap_mapping_range(struct address_space *mapping,
        if (unlikely(!list_empty(&mapping->i_mmap_nonlinear)))
                unmap_mapping_range_list(&mapping->i_mmap_nonlinear, &details);
        spin_unlock(&mapping->i_mmap_lock);
+       mutex_unlock(&mapping->unmap_mutex);
 }
 EXPORT_SYMBOL(unmap_mapping_range);
 
@@ -3053,12 +3053,6 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                                goto out;
                        }
                        charged = 1;
-                       /*
-                        * Don't let another task, with possibly unlocked vma,
-                        * keep the mlocked page.
-                        */
-                       if (vma->vm_flags & VM_LOCKED)
-                               clear_page_mlock(vmf.page);
                        copy_user_highpage(page, vmf.page, address, vma);
                        __SetPageUptodate(page);
                } else {
index 368fc9d..b53ec99 100644 (file)
@@ -1524,10 +1524,9 @@ static nodemask_t *policy_nodemask(gfp_t gfp, struct mempolicy *policy)
 }
 
 /* Return a zonelist indicated by gfp for node representing a mempolicy */
-static struct zonelist *policy_zonelist(gfp_t gfp, struct mempolicy *policy)
+static struct zonelist *policy_zonelist(gfp_t gfp, struct mempolicy *policy,
+       int nd)
 {
-       int nd = numa_node_id();
-
        switch (policy->mode) {
        case MPOL_PREFERRED:
                if (!(policy->flags & MPOL_F_LOCAL))
@@ -1679,7 +1678,7 @@ struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr,
                zl = node_zonelist(interleave_nid(*mpol, vma, addr,
                                huge_page_shift(hstate_vma(vma))), gfp_flags);
        } else {
-               zl = policy_zonelist(gfp_flags, *mpol);
+               zl = policy_zonelist(gfp_flags, *mpol, numa_node_id());
                if ((*mpol)->mode == MPOL_BIND)
                        *nodemask = &(*mpol)->v.nodes;
        }
@@ -1820,7 +1819,7 @@ static struct page *alloc_page_interleave(gfp_t gfp, unsigned order,
  */
 struct page *
 alloc_pages_vma(gfp_t gfp, int order, struct vm_area_struct *vma,
-               unsigned long addr)
+               unsigned long addr, int node)
 {
        struct mempolicy *pol = get_vma_policy(current, vma, addr);
        struct zonelist *zl;
@@ -1830,13 +1829,13 @@ alloc_pages_vma(gfp_t gfp, int order, struct vm_area_struct *vma,
        if (unlikely(pol->mode == MPOL_INTERLEAVE)) {
                unsigned nid;
 
-               nid = interleave_nid(pol, vma, addr, PAGE_SHIFT);
+               nid = interleave_nid(pol, vma, addr, PAGE_SHIFT + order);
                mpol_cond_put(pol);
                page = alloc_page_interleave(gfp, order, nid);
                put_mems_allowed();
                return page;
        }
-       zl = policy_zonelist(gfp, pol);
+       zl = policy_zonelist(gfp, pol, node);
        if (unlikely(mpol_needs_cond_ref(pol))) {
                /*
                 * slow path: ref counted shared policy
@@ -1892,7 +1891,8 @@ struct page *alloc_pages_current(gfp_t gfp, unsigned order)
                page = alloc_page_interleave(gfp, order, interleave_nodes(pol));
        else
                page = __alloc_pages_nodemask(gfp, order,
-                       policy_zonelist(gfp, pol), policy_nodemask(gfp, pol));
+                               policy_zonelist(gfp, pol, numa_node_id()),
+                               policy_nodemask(gfp, pol));
        put_mems_allowed();
        return page;
 }
index 46fe8cc..352de55 100644 (file)
@@ -772,6 +772,7 @@ uncharge:
 unlock:
        unlock_page(page);
 
+move_newpage:
        if (rc != -EAGAIN) {
                /*
                 * A page that has been migrated has all references
@@ -785,8 +786,6 @@ unlock:
                putback_lru_page(page);
        }
 
-move_newpage:
-
        /*
         * Move the new page to the LRU. If migration was not successful
         * then this will free the page.
@@ -888,7 +887,7 @@ out:
  * are movable anymore because to has become empty
  * or no retryable pages exist anymore.
  * Caller should call putback_lru_pages to return pages to the LRU
- * or free list.
+ * or free list only if ret != 0.
  *
  * Return: Number of pages not migrated or error code.
  */
@@ -981,10 +980,6 @@ int migrate_huge_pages(struct list_head *from,
        }
        rc = 0;
 out:
-
-       list_for_each_entry_safe(page, page2, from, lru)
-               put_page(page);
-
        if (rc)
                return rc;
 
@@ -1292,14 +1287,14 @@ SYSCALL_DEFINE6(move_pages, pid_t, pid, unsigned long, nr_pages,
                return -EPERM;
 
        /* Find the mm_struct */
-       read_lock(&tasklist_lock);
+       rcu_read_lock();
        task = pid ? find_task_by_vpid(pid) : current;
        if (!task) {
-               read_unlock(&tasklist_lock);
+               rcu_read_unlock();
                return -ESRCH;
        }
        mm = get_task_mm(task);
-       read_unlock(&tasklist_lock);
+       rcu_read_unlock();
 
        if (!mm)
                return -EINVAL;
index 13e81ee..c3924c7 100644 (file)
@@ -178,6 +178,13 @@ static long __mlock_vma_pages_range(struct vm_area_struct *vma,
        if ((vma->vm_flags & (VM_WRITE | VM_SHARED)) == VM_WRITE)
                gup_flags |= FOLL_WRITE;
 
+       /*
+        * We want mlock to succeed for regions that have any permissions
+        * other than PROT_NONE.
+        */
+       if (vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC))
+               gup_flags |= FOLL_FORCE;
+
        if (vma->vm_flags & VM_LOCKED)
                gup_flags |= FOLL_MLOCK;
 
index 9925b63..1de98d4 100644 (file)
@@ -94,9 +94,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
                 */
                mapping = vma->vm_file->f_mapping;
                spin_lock(&mapping->i_mmap_lock);
-               if (new_vma->vm_truncate_count &&
-                   new_vma->vm_truncate_count != vma->vm_truncate_count)
-                       new_vma->vm_truncate_count = 0;
+               new_vma->vm_truncate_count = 0;
        }
 
        /*
diff --git a/mm/nobootmem.c b/mm/nobootmem.c
new file mode 100644 (file)
index 0000000..e2bdb07
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ *  bootmem - A boot-time physical memory allocator and configurator
+ *
+ *  Copyright (C) 1999 Ingo Molnar
+ *                1999 Kanoj Sarcar, SGI
+ *                2008 Johannes Weiner
+ *
+ * Access to this subsystem has to be serialized externally (which is true
+ * for the boot process anyway).
+ */
+#include <linux/init.h>
+#include <linux/pfn.h>
+#include <linux/slab.h>
+#include <linux/bootmem.h>
+#include <linux/module.h>
+#include <linux/kmemleak.h>
+#include <linux/range.h>
+#include <linux/memblock.h>
+
+#include <asm/bug.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+
+#include "internal.h"
+
+#ifndef CONFIG_NEED_MULTIPLE_NODES
+struct pglist_data __refdata contig_page_data;
+EXPORT_SYMBOL(contig_page_data);
+#endif
+
+unsigned long max_low_pfn;
+unsigned long min_low_pfn;
+unsigned long max_pfn;
+
+#ifdef CONFIG_CRASH_DUMP
+/*
+ * If we have booted due to a crash, max_pfn will be a very low value. We need
+ * to know the amount of memory that the previous kernel used.
+ */
+unsigned long saved_max_pfn;
+#endif
+
+static void * __init __alloc_memory_core_early(int nid, u64 size, u64 align,
+                                       u64 goal, u64 limit)
+{
+       void *ptr;
+       u64 addr;
+
+       if (limit > memblock.current_limit)
+               limit = memblock.current_limit;
+
+       addr = find_memory_core_early(nid, size, align, goal, limit);
+
+       if (addr == MEMBLOCK_ERROR)
+               return NULL;
+
+       ptr = phys_to_virt(addr);
+       memset(ptr, 0, size);
+       memblock_x86_reserve_range(addr, addr + size, "BOOTMEM");
+       /*
+        * The min_count is set to 0 so that bootmem allocated blocks
+        * are never reported as leaks.
+        */
+       kmemleak_alloc(ptr, size, 0, 0);
+       return ptr;
+}
+
+/*
+ * free_bootmem_late - free bootmem pages directly to page allocator
+ * @addr: starting address of the range
+ * @size: size of the range in bytes
+ *
+ * This is only useful when the bootmem allocator has already been torn
+ * down, but we are still initializing the system.  Pages are given directly
+ * to the page allocator, no bootmem metadata is updated because it is gone.
+ */
+void __init free_bootmem_late(unsigned long addr, unsigned long size)
+{
+       unsigned long cursor, end;
+
+       kmemleak_free_part(__va(addr), size);
+
+       cursor = PFN_UP(addr);
+       end = PFN_DOWN(addr + size);
+
+       for (; cursor < end; cursor++) {
+               __free_pages_bootmem(pfn_to_page(cursor), 0);
+               totalram_pages++;
+       }
+}
+
+static void __init __free_pages_memory(unsigned long start, unsigned long end)
+{
+       int i;
+       unsigned long start_aligned, end_aligned;
+       int order = ilog2(BITS_PER_LONG);
+
+       start_aligned = (start + (BITS_PER_LONG - 1)) & ~(BITS_PER_LONG - 1);
+       end_aligned = end & ~(BITS_PER_LONG - 1);
+
+       if (end_aligned <= start_aligned) {
+               for (i = start; i < end; i++)
+                       __free_pages_bootmem(pfn_to_page(i), 0);
+
+               return;
+       }
+
+       for (i = start; i < start_aligned; i++)
+               __free_pages_bootmem(pfn_to_page(i), 0);
+
+       for (i = start_aligned; i < end_aligned; i += BITS_PER_LONG)
+               __free_pages_bootmem(pfn_to_page(i), order);
+
+       for (i = end_aligned; i < end; i++)
+               __free_pages_bootmem(pfn_to_page(i), 0);
+}
+
+unsigned long __init free_all_memory_core_early(int nodeid)
+{
+       int i;
+       u64 start, end;
+       unsigned long count = 0;
+       struct range *range = NULL;
+       int nr_range;
+
+       nr_range = get_free_all_memory_range(&range, nodeid);
+
+       for (i = 0; i < nr_range; i++) {
+               start = range[i].start;
+               end = range[i].end;
+               count += end - start;
+               __free_pages_memory(start, end);
+       }
+
+       return count;
+}
+
+/**
+ * free_all_bootmem_node - release a node's free pages to the buddy allocator
+ * @pgdat: node to be released
+ *
+ * Returns the number of pages actually released.
+ */
+unsigned long __init free_all_bootmem_node(pg_data_t *pgdat)
+{
+       register_page_bootmem_info_node(pgdat);
+
+       /* free_all_memory_core_early(MAX_NUMNODES) will be called later */
+       return 0;
+}
+
+/**
+ * free_all_bootmem - release free pages to the buddy allocator
+ *
+ * Returns the number of pages actually released.
+ */
+unsigned long __init free_all_bootmem(void)
+{
+       /*
+        * We need to use MAX_NUMNODES instead of NODE_DATA(0)->node_id
+        *  because in some case like Node0 doesnt have RAM installed
+        *  low ram will be on Node1
+        * Use MAX_NUMNODES will make sure all ranges in early_node_map[]
+        *  will be used instead of only Node0 related
+        */
+       return free_all_memory_core_early(MAX_NUMNODES);
+}
+
+/**
+ * free_bootmem_node - mark a page range as usable
+ * @pgdat: node the range resides on
+ * @physaddr: starting address of the range
+ * @size: size of the range in bytes
+ *
+ * Partial pages will be considered reserved and left as they are.
+ *
+ * The range must reside completely on the specified node.
+ */
+void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
+                             unsigned long size)
+{
+       kmemleak_free_part(__va(physaddr), size);
+       memblock_x86_free_range(physaddr, physaddr + size);
+}
+
+/**
+ * free_bootmem - mark a page range as usable
+ * @addr: starting address of the range
+ * @size: size of the range in bytes
+ *
+ * Partial pages will be considered reserved and left as they are.
+ *
+ * The range must be contiguous but may span node boundaries.
+ */
+void __init free_bootmem(unsigned long addr, unsigned long size)
+{
+       kmemleak_free_part(__va(addr), size);
+       memblock_x86_free_range(addr, addr + size);
+}
+
+static void * __init ___alloc_bootmem_nopanic(unsigned long size,
+                                       unsigned long align,
+                                       unsigned long goal,
+                                       unsigned long limit)
+{
+       void *ptr;
+
+       if (WARN_ON_ONCE(slab_is_available()))
+               return kzalloc(size, GFP_NOWAIT);
+
+restart:
+
+       ptr = __alloc_memory_core_early(MAX_NUMNODES, size, align, goal, limit);
+
+       if (ptr)
+               return ptr;
+
+       if (goal != 0) {
+               goal = 0;
+               goto restart;
+       }
+
+       return NULL;
+}
+
+/**
+ * __alloc_bootmem_nopanic - allocate boot memory without panicking
+ * @size: size of the request in bytes
+ * @align: alignment of the region
+ * @goal: preferred starting address of the region
+ *
+ * The goal is dropped if it can not be satisfied and the allocation will
+ * fall back to memory below @goal.
+ *
+ * Allocation may happen on any node in the system.
+ *
+ * Returns NULL on failure.
+ */
+void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align,
+                                       unsigned long goal)
+{
+       unsigned long limit = -1UL;
+
+       return ___alloc_bootmem_nopanic(size, align, goal, limit);
+}
+
+static void * __init ___alloc_bootmem(unsigned long size, unsigned long align,
+                                       unsigned long goal, unsigned long limit)
+{
+       void *mem = ___alloc_bootmem_nopanic(size, align, goal, limit);
+
+       if (mem)
+               return mem;
+       /*
+        * Whoops, we cannot satisfy the allocation request.
+        */
+       printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size);
+       panic("Out of memory");
+       return NULL;
+}
+
+/**
+ * __alloc_bootmem - allocate boot memory
+ * @size: size of the request in bytes
+ * @align: alignment of the region
+ * @goal: preferred starting address of the region
+ *
+ * The goal is dropped if it can not be satisfied and the allocation will
+ * fall back to memory below @goal.
+ *
+ * Allocation may happen on any node in the system.
+ *
+ * The function panics if the request can not be satisfied.
+ */
+void * __init __alloc_bootmem(unsigned long size, unsigned long align,
+                             unsigned long goal)
+{
+       unsigned long limit = -1UL;
+
+       return ___alloc_bootmem(size, align, goal, limit);
+}
+
+/**
+ * __alloc_bootmem_node - allocate boot memory from a specific node
+ * @pgdat: node to allocate from
+ * @size: size of the request in bytes
+ * @align: alignment of the region
+ * @goal: preferred starting address of the region
+ *
+ * The goal is dropped if it can not be satisfied and the allocation will
+ * fall back to memory below @goal.
+ *
+ * Allocation may fall back to any node in the system if the specified node
+ * can not hold the requested memory.
+ *
+ * The function panics if the request can not be satisfied.
+ */
+void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size,
+                                  unsigned long align, unsigned long goal)
+{
+       void *ptr;
+
+       if (WARN_ON_ONCE(slab_is_available()))
+               return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
+
+       ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
+                                        goal, -1ULL);
+       if (ptr)
+               return ptr;
+
+       return __alloc_memory_core_early(MAX_NUMNODES, size, align,
+                                        goal, -1ULL);
+}
+
+void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size,
+                                  unsigned long align, unsigned long goal)
+{
+#ifdef MAX_DMA32_PFN
+       unsigned long end_pfn;
+
+       if (WARN_ON_ONCE(slab_is_available()))
+               return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
+
+       /* update goal according ...MAX_DMA32_PFN */
+       end_pfn = pgdat->node_start_pfn + pgdat->node_spanned_pages;
+
+       if (end_pfn > MAX_DMA32_PFN + (128 >> (20 - PAGE_SHIFT)) &&
+           (goal >> PAGE_SHIFT) < MAX_DMA32_PFN) {
+               void *ptr;
+               unsigned long new_goal;
+
+               new_goal = MAX_DMA32_PFN << PAGE_SHIFT;
+               ptr =  __alloc_memory_core_early(pgdat->node_id, size, align,
+                                                new_goal, -1ULL);
+               if (ptr)
+                       return ptr;
+       }
+#endif
+
+       return __alloc_bootmem_node(pgdat, size, align, goal);
+
+}
+
+#ifdef CONFIG_SPARSEMEM
+/**
+ * alloc_bootmem_section - allocate boot memory from a specific section
+ * @size: size of the request in bytes
+ * @section_nr: sparse map section to allocate from
+ *
+ * Return NULL on failure.
+ */
+void * __init alloc_bootmem_section(unsigned long size,
+                                   unsigned long section_nr)
+{
+       unsigned long pfn, goal, limit;
+
+       pfn = section_nr_to_pfn(section_nr);
+       goal = pfn << PAGE_SHIFT;
+       limit = section_nr_to_pfn(section_nr + 1) << PAGE_SHIFT;
+
+       return __alloc_memory_core_early(early_pfn_to_nid(pfn), size,
+                                        SMP_CACHE_BYTES, goal, limit);
+}
+#endif
+
+void * __init __alloc_bootmem_node_nopanic(pg_data_t *pgdat, unsigned long size,
+                                  unsigned long align, unsigned long goal)
+{
+       void *ptr;
+
+       if (WARN_ON_ONCE(slab_is_available()))
+               return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
+
+       ptr =  __alloc_memory_core_early(pgdat->node_id, size, align,
+                                                goal, -1ULL);
+       if (ptr)
+               return ptr;
+
+       return __alloc_bootmem_nopanic(size, align, goal);
+}
+
+#ifndef ARCH_LOW_ADDRESS_LIMIT
+#define ARCH_LOW_ADDRESS_LIMIT 0xffffffffUL
+#endif
+
+/**
+ * __alloc_bootmem_low - allocate low boot memory
+ * @size: size of the request in bytes
+ * @align: alignment of the region
+ * @goal: preferred starting address of the region
+ *
+ * The goal is dropped if it can not be satisfied and the allocation will
+ * fall back to memory below @goal.
+ *
+ * Allocation may happen on any node in the system.
+ *
+ * The function panics if the request can not be satisfied.
+ */
+void * __init __alloc_bootmem_low(unsigned long size, unsigned long align,
+                                 unsigned long goal)
+{
+       return ___alloc_bootmem(size, align, goal, ARCH_LOW_ADDRESS_LIMIT);
+}
+
+/**
+ * __alloc_bootmem_low_node - allocate low boot memory from a specific node
+ * @pgdat: node to allocate from
+ * @size: size of the request in bytes
+ * @align: alignment of the region
+ * @goal: preferred starting address of the region
+ *
+ * The goal is dropped if it can not be satisfied and the allocation will
+ * fall back to memory below @goal.
+ *
+ * Allocation may fall back to any node in the system if the specified node
+ * can not hold the requested memory.
+ *
+ * The function panics if the request can not be satisfied.
+ */
+void * __init __alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size,
+                                      unsigned long align, unsigned long goal)
+{
+       void *ptr;
+
+       if (WARN_ON_ONCE(slab_is_available()))
+               return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
+
+       ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
+                               goal, ARCH_LOW_ADDRESS_LIMIT);
+       if (ptr)
+               return ptr;
+
+       return  __alloc_memory_core_early(MAX_NUMNODES, size, align,
+                               goal, ARCH_LOW_ADDRESS_LIMIT);
+}
index 90c1439..bd76256 100644 (file)
@@ -1088,8 +1088,10 @@ static void drain_pages(unsigned int cpu)
                pset = per_cpu_ptr(zone->pageset, cpu);
 
                pcp = &pset->pcp;
-               free_pcppages_bulk(zone, pcp->count, pcp);
-               pcp->count = 0;
+               if (pcp->count) {
+                       free_pcppages_bulk(zone, pcp->count, pcp);
+                       pcp->count = 0;
+               }
                local_irq_restore(flags);
        }
 }
@@ -2034,6 +2036,14 @@ restart:
         */
        alloc_flags = gfp_to_alloc_flags(gfp_mask);
 
+       /*
+        * Find the true preferred zone if the allocation is unconstrained by
+        * cpusets.
+        */
+       if (!(alloc_flags & ALLOC_CPUSET) && !nodemask)
+               first_zones_zonelist(zonelist, high_zoneidx, NULL,
+                                       &preferred_zone);
+
        /* This is the last chance, in general, before the goto nopage. */
        page = get_page_from_freelist(gfp_mask, nodemask, order, zonelist,
                        high_zoneidx, alloc_flags & ~ALLOC_NO_WATERMARKS,
@@ -2192,7 +2202,9 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
 
        get_mems_allowed();
        /* The preferred zone is used for statistics later */
-       first_zones_zonelist(zonelist, high_zoneidx, nodemask, &preferred_zone);
+       first_zones_zonelist(zonelist, high_zoneidx,
+                               nodemask ? : &cpuset_current_mems_allowed,
+                               &preferred_zone);
        if (!preferred_zone) {
                put_mems_allowed();
                return NULL;
@@ -3687,13 +3699,45 @@ void __init free_bootmem_with_active_regions(int nid,
 }
 
 #ifdef CONFIG_HAVE_MEMBLOCK
+/*
+ * Basic iterator support. Return the last range of PFNs for a node
+ * Note: nid == MAX_NUMNODES returns last region regardless of node
+ */
+static int __meminit last_active_region_index_in_nid(int nid)
+{
+       int i;
+
+       for (i = nr_nodemap_entries - 1; i >= 0; i--)
+               if (nid == MAX_NUMNODES || early_node_map[i].nid == nid)
+                       return i;
+
+       return -1;
+}
+
+/*
+ * Basic iterator support. Return the previous active range of PFNs for a node
+ * Note: nid == MAX_NUMNODES returns next region regardless of node
+ */
+static int __meminit previous_active_region_index_in_nid(int index, int nid)
+{
+       for (index = index - 1; index >= 0; index--)
+               if (nid == MAX_NUMNODES || early_node_map[index].nid == nid)
+                       return index;
+
+       return -1;
+}
+
+#define for_each_active_range_index_in_nid_reverse(i, nid) \
+       for (i = last_active_region_index_in_nid(nid); i != -1; \
+                               i = previous_active_region_index_in_nid(i, nid))
+
 u64 __init find_memory_core_early(int nid, u64 size, u64 align,
                                        u64 goal, u64 limit)
 {
        int i;
 
        /* Need to go over early_node_map to find out good range for node */
-       for_each_active_range_index_in_nid(i, nid) {
+       for_each_active_range_index_in_nid_reverse(i, nid) {
                u64 addr;
                u64 ei_start, ei_last;
                u64 final_start, final_end;
@@ -3736,34 +3780,6 @@ int __init add_from_early_node_map(struct range *range, int az,
        return nr_range;
 }
 
-#ifdef CONFIG_NO_BOOTMEM
-void * __init __alloc_memory_core_early(int nid, u64 size, u64 align,
-                                       u64 goal, u64 limit)
-{
-       void *ptr;
-       u64 addr;
-
-       if (limit > memblock.current_limit)
-               limit = memblock.current_limit;
-
-       addr = find_memory_core_early(nid, size, align, goal, limit);
-
-       if (addr == MEMBLOCK_ERROR)
-               return NULL;
-
-       ptr = phys_to_virt(addr);
-       memset(ptr, 0, size);
-       memblock_x86_reserve_range(addr, addr + size, "BOOTMEM");
-       /*
-        * The min_count is set to 0 so that bootmem allocated blocks
-        * are never reported as leaks.
-        */
-       kmemleak_alloc(ptr, size, 0, 0);
-       return ptr;
-}
-#endif
-
-
 void __init work_with_active_regions(int nid, work_fn_t work_fn, void *data)
 {
        int i;
@@ -4797,15 +4813,6 @@ void __init set_dma_reserve(unsigned long new_dma_reserve)
        dma_reserve = new_dma_reserve;
 }
 
-#ifndef CONFIG_NEED_MULTIPLE_NODES
-struct pglist_data __refdata contig_page_data = {
-#ifndef CONFIG_NO_BOOTMEM
- .bdata = &bootmem_node_data[0]
-#endif
- };
-EXPORT_SYMBOL(contig_page_data);
-#endif
-
 void __init free_area_init(unsigned long *zones_size)
 {
        free_area_init_node(0, zones_size,
@@ -5364,10 +5371,9 @@ __count_immobile_pages(struct zone *zone, struct page *page, int count)
        for (found = 0, iter = 0; iter < pageblock_nr_pages; iter++) {
                unsigned long check = pfn + iter;
 
-               if (!pfn_valid_within(check)) {
-                       iter++;
+               if (!pfn_valid_within(check))
                        continue;
-               }
+
                page = pfn_to_page(check);
                if (!page_count(page)) {
                        if (PageBuddy(page))
index 0369f5b..eb663fb 100644 (file)
@@ -6,6 +6,7 @@
  *  Copyright (C) 2010  Linus Torvalds
  */
 
+#include <linux/pagemap.h>
 #include <asm/tlb.h>
 #include <asm-generic/pgtable.h>
 
index f21f4a1..941bf82 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -497,41 +497,51 @@ int page_referenced_one(struct page *page, struct vm_area_struct *vma,
        struct mm_struct *mm = vma->vm_mm;
        int referenced = 0;
 
-       /*
-        * Don't want to elevate referenced for mlocked page that gets this far,
-        * in order that it progresses to try_to_unmap and is moved to the
-        * unevictable list.
-        */
-       if (vma->vm_flags & VM_LOCKED) {
-               *mapcount = 0;  /* break early from loop */
-               *vm_flags |= VM_LOCKED;
-               goto out;
-       }
-
-       /* Pretend the page is referenced if the task has the
-          swap token and is in the middle of a page fault. */
-       if (mm != current->mm && has_swap_token(mm) &&
-                       rwsem_is_locked(&mm->mmap_sem))
-               referenced++;
-
        if (unlikely(PageTransHuge(page))) {
                pmd_t *pmd;
 
                spin_lock(&mm->page_table_lock);
+               /*
+                * rmap might return false positives; we must filter
+                * these out using page_check_address_pmd().
+                */
                pmd = page_check_address_pmd(page, mm, address,
                                             PAGE_CHECK_ADDRESS_PMD_FLAG);
-               if (pmd && !pmd_trans_splitting(*pmd) &&
-                   pmdp_clear_flush_young_notify(vma, address, pmd))
+               if (!pmd) {
+                       spin_unlock(&mm->page_table_lock);
+                       goto out;
+               }
+
+               if (vma->vm_flags & VM_LOCKED) {
+                       spin_unlock(&mm->page_table_lock);
+                       *mapcount = 0;  /* break early from loop */
+                       *vm_flags |= VM_LOCKED;
+                       goto out;
+               }
+
+               /* go ahead even if the pmd is pmd_trans_splitting() */
+               if (pmdp_clear_flush_young_notify(vma, address, pmd))
                        referenced++;
                spin_unlock(&mm->page_table_lock);
        } else {
                pte_t *pte;
                spinlock_t *ptl;
 
+               /*
+                * rmap might return false positives; we must filter
+                * these out using page_check_address().
+                */
                pte = page_check_address(page, mm, address, &ptl, 0);
                if (!pte)
                        goto out;
 
+               if (vma->vm_flags & VM_LOCKED) {
+                       pte_unmap_unlock(pte, ptl);
+                       *mapcount = 0;  /* break early from loop */
+                       *vm_flags |= VM_LOCKED;
+                       goto out;
+               }
+
                if (ptep_clear_flush_young_notify(vma, address, pte)) {
                        /*
                         * Don't treat a reference through a sequentially read
@@ -546,6 +556,12 @@ int page_referenced_one(struct page *page, struct vm_area_struct *vma,
                pte_unmap_unlock(pte, ptl);
        }
 
+       /* Pretend the page is referenced if the task has the
+          swap token and is in the middle of a page fault. */
+       if (mm != current->mm && has_swap_token(mm) &&
+                       rwsem_is_locked(&mm->mmap_sem))
+               referenced++;
+
        (*mapcount)--;
 
        if (referenced)
index 5ee67c9..3437b65 100644 (file)
@@ -2144,8 +2144,10 @@ static int shmem_encode_fh(struct dentry *dentry, __u32 *fh, int *len,
 {
        struct inode *inode = dentry->d_inode;
 
-       if (*len < 3)
+       if (*len < 3) {
+               *len = 3;
                return 255;
+       }
 
        if (inode_unhashed(inode)) {
                /* Unfortunately insert_inode_hash is not idempotent,
index 07a458d..0341c57 100644 (file)
@@ -1940,7 +1940,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
 
        error = -EINVAL;
        if (S_ISBLK(inode->i_mode)) {
-               bdev = I_BDEV(inode);
+               bdev = bdgrab(I_BDEV(inode));
                error = blkdev_get(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL,
                                   sys_swapon);
                if (error < 0) {
index 49feb46..d64296b 100644 (file)
@@ -225,6 +225,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
        next = start;
        while (next <= end &&
               pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) {
+               mem_cgroup_uncharge_start();
                for (i = 0; i < pagevec_count(&pvec); i++) {
                        struct page *page = pvec.pages[i];
                        pgoff_t page_index = page->index;
@@ -247,6 +248,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
                        unlock_page(page);
                }
                pagevec_release(&pvec);
+               mem_cgroup_uncharge_end();
                cond_resched();
        }
 
index f5d90de..6771ea7 100644 (file)
@@ -1841,16 +1841,28 @@ static inline bool should_continue_reclaim(struct zone *zone,
        if (!(sc->reclaim_mode & RECLAIM_MODE_COMPACTION))
                return false;
 
-       /*
-        * If we failed to reclaim and have scanned the full list, stop.
-        * NOTE: Checking just nr_reclaimed would exit reclaim/compaction far
-        *       faster but obviously would be less likely to succeed
-        *       allocation. If this is desirable, use GFP_REPEAT to decide
-        *       if both reclaimed and scanned should be checked or just
-        *       reclaimed
-        */
-       if (!nr_reclaimed && !nr_scanned)
-               return false;
+       /* Consider stopping depending on scan and reclaim activity */
+       if (sc->gfp_mask & __GFP_REPEAT) {
+               /*
+                * For __GFP_REPEAT allocations, stop reclaiming if the
+                * full LRU list has been scanned and we are still failing
+                * to reclaim pages. This full LRU scan is potentially
+                * expensive but a __GFP_REPEAT caller really wants to succeed
+                */
+               if (!nr_reclaimed && !nr_scanned)
+                       return false;
+       } else {
+               /*
+                * For non-__GFP_REPEAT allocations which can presumably
+                * fail without consequence, stop if we failed to reclaim
+                * any pages from the last SWAP_CLUSTER_MAX number of
+                * pages that were scanned. This will return to the
+                * caller faster at the risk reclaim/compaction and
+                * the resulting allocation attempt fails
+                */
+               if (!nr_reclaimed)
+                       return false;
+       }
 
        /*
         * If we have not reclaimed enough pages for compaction and the
@@ -1882,12 +1894,12 @@ static void shrink_zone(int priority, struct zone *zone,
        unsigned long nr[NR_LRU_LISTS];
        unsigned long nr_to_scan;
        enum lru_list l;
-       unsigned long nr_reclaimed;
+       unsigned long nr_reclaimed, nr_scanned;
        unsigned long nr_to_reclaim = sc->nr_to_reclaim;
-       unsigned long nr_scanned = sc->nr_scanned;
 
 restart:
        nr_reclaimed = 0;
+       nr_scanned = sc->nr_scanned;
        get_scan_count(zone, sc, nr, priority);
 
        while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] ||
@@ -2083,7 +2095,8 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
                        struct zone *preferred_zone;
 
                        first_zones_zonelist(zonelist, gfp_zone(sc->gfp_mask),
-                                                       NULL, &preferred_zone);
+                                               &cpuset_current_mems_allowed,
+                                               &preferred_zone);
                        wait_iff_congested(preferred_zone, BLK_RW_ASYNC, HZ/10);
                }
        }
index 078eb16..a30471e 100644 (file)
@@ -153,10 +153,11 @@ struct p9_conn {
        unsigned long wsched;
 };
 
+static void p9_poll_workfn(struct work_struct *work);
+
 static DEFINE_SPINLOCK(p9_poll_lock);
 static LIST_HEAD(p9_poll_pending_list);
-static struct workqueue_struct *p9_mux_wq;
-static struct task_struct *p9_poll_task;
+static DECLARE_WORK(p9_poll_work, p9_poll_workfn);
 
 static void p9_mux_poll_stop(struct p9_conn *m)
 {
@@ -384,7 +385,7 @@ static void p9_read_work(struct work_struct *work)
 
                if (n & POLLIN) {
                        P9_DPRINTK(P9_DEBUG_TRANS, "sched read work %p\n", m);
-                       queue_work(p9_mux_wq, &m->rq);
+                       schedule_work(&m->rq);
                } else
                        clear_bit(Rworksched, &m->wsched);
        } else
@@ -497,7 +498,7 @@ static void p9_write_work(struct work_struct *work)
 
                if (n & POLLOUT) {
                        P9_DPRINTK(P9_DEBUG_TRANS, "sched write work %p\n", m);
-                       queue_work(p9_mux_wq, &m->wq);
+                       schedule_work(&m->wq);
                } else
                        clear_bit(Wworksched, &m->wsched);
        } else
@@ -516,15 +517,14 @@ static int p9_pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
                container_of(wait, struct p9_poll_wait, wait);
        struct p9_conn *m = pwait->conn;
        unsigned long flags;
-       DECLARE_WAITQUEUE(dummy_wait, p9_poll_task);
 
        spin_lock_irqsave(&p9_poll_lock, flags);
        if (list_empty(&m->poll_pending_link))
                list_add_tail(&m->poll_pending_link, &p9_poll_pending_list);
        spin_unlock_irqrestore(&p9_poll_lock, flags);
 
-       /* perform the default wake up operation */
-       return default_wake_function(&dummy_wait, mode, sync, key);
+       schedule_work(&p9_poll_work);
+       return 1;
 }
 
 /**
@@ -629,7 +629,7 @@ static void p9_poll_mux(struct p9_conn *m)
                P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can read\n", m);
                if (!test_and_set_bit(Rworksched, &m->wsched)) {
                        P9_DPRINTK(P9_DEBUG_TRANS, "sched read work %p\n", m);
-                       queue_work(p9_mux_wq, &m->rq);
+                       schedule_work(&m->rq);
                }
        }
 
@@ -639,7 +639,7 @@ static void p9_poll_mux(struct p9_conn *m)
                if ((m->wsize || !list_empty(&m->unsent_req_list)) &&
                    !test_and_set_bit(Wworksched, &m->wsched)) {
                        P9_DPRINTK(P9_DEBUG_TRANS, "sched write work %p\n", m);
-                       queue_work(p9_mux_wq, &m->wq);
+                       schedule_work(&m->wq);
                }
        }
 }
@@ -677,7 +677,7 @@ static int p9_fd_request(struct p9_client *client, struct p9_req_t *req)
                n = p9_fd_poll(m->client, NULL);
 
        if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched))
-               queue_work(p9_mux_wq, &m->wq);
+               schedule_work(&m->wq);
 
        return 0;
 }
@@ -1047,12 +1047,12 @@ static struct p9_trans_module p9_fd_trans = {
  *
  */
 
-static int p9_poll_proc(void *a)
+static void p9_poll_workfn(struct work_struct *work)
 {
        unsigned long flags;
 
        P9_DPRINTK(P9_DEBUG_TRANS, "start %p\n", current);
- repeat:
+
        spin_lock_irqsave(&p9_poll_lock, flags);
        while (!list_empty(&p9_poll_pending_list)) {
                struct p9_conn *conn = list_first_entry(&p9_poll_pending_list,
@@ -1067,35 +1067,11 @@ static int p9_poll_proc(void *a)
        }
        spin_unlock_irqrestore(&p9_poll_lock, flags);
 
-       set_current_state(TASK_INTERRUPTIBLE);
-       if (list_empty(&p9_poll_pending_list)) {
-               P9_DPRINTK(P9_DEBUG_TRANS, "sleeping...\n");
-               schedule();
-       }
-       __set_current_state(TASK_RUNNING);
-
-       if (!kthread_should_stop())
-               goto repeat;
-
        P9_DPRINTK(P9_DEBUG_TRANS, "finish\n");
-       return 0;
 }
 
 int p9_trans_fd_init(void)
 {
-       p9_mux_wq = create_workqueue("v9fs");
-       if (!p9_mux_wq) {
-               printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n");
-               return -ENOMEM;
-       }
-
-       p9_poll_task = kthread_run(p9_poll_proc, NULL, "v9fs-poll");
-       if (IS_ERR(p9_poll_task)) {
-               destroy_workqueue(p9_mux_wq);
-               printk(KERN_WARNING "v9fs: mux: creating poll task failed\n");
-               return PTR_ERR(p9_poll_task);
-       }
-
        v9fs_register_trans(&p9_tcp_trans);
        v9fs_register_trans(&p9_unix_trans);
        v9fs_register_trans(&p9_fd_trans);
@@ -1105,10 +1081,8 @@ int p9_trans_fd_init(void)
 
 void p9_trans_fd_exit(void)
 {
-       kthread_stop(p9_poll_task);
+       flush_work_sync(&p9_poll_work);
        v9fs_unregister_trans(&p9_tcp_trans);
        v9fs_unregister_trans(&p9_unix_trans);
        v9fs_unregister_trans(&p9_fd_trans);
-
-       destroy_workqueue(p9_mux_wq);
 }
index a3330eb..a51d946 100644 (file)
@@ -19,9 +19,7 @@ obj-$(CONFIG_NETFILTER)               += netfilter/
 obj-$(CONFIG_INET)             += ipv4/
 obj-$(CONFIG_XFRM)             += xfrm/
 obj-$(CONFIG_UNIX)             += unix/
-ifneq ($(CONFIG_IPV6),)
-obj-y                          += ipv6/
-endif
+obj-$(CONFIG_NET)              += ipv6/
 obj-$(CONFIG_PACKET)           += packet/
 obj-$(CONFIG_NET_KEY)          += key/
 obj-$(CONFIG_BRIDGE)           += bridge/
index ee41fef..d1a6113 100644 (file)
@@ -50,12 +50,12 @@ static struct sk_buff *frag_merge_packet(struct list_head *head,
                skb = tfp->skb;
        }
 
+       if (skb_linearize(skb) < 0 || skb_linearize(tmp_skb) < 0)
+               goto err;
+
        skb_pull(tmp_skb, sizeof(struct unicast_frag_packet));
-       if (pskb_expand_head(skb, 0, tmp_skb->len, GFP_ATOMIC) < 0) {
-               /* free buffered skb, skb will be freed later */
-               kfree_skb(tfp->skb);
-               return NULL;
-       }
+       if (pskb_expand_head(skb, 0, tmp_skb->len, GFP_ATOMIC) < 0)
+               goto err;
 
        /* move free entry to end */
        tfp->skb = NULL;
@@ -70,6 +70,11 @@ static struct sk_buff *frag_merge_packet(struct list_head *head,
        unicast_packet->packet_type = BAT_UNICAST;
 
        return skb;
+
+err:
+       /* free buffered skb, skb will be freed later */
+       kfree_skb(tfp->skb);
+       return NULL;
 }
 
 static void frag_create_entry(struct list_head *head, struct sk_buff *skb)
index cd4c423..de1022c 100644 (file)
@@ -64,6 +64,7 @@ static void free_info(struct kref *ref)
 
        spin_unlock_bh(&bat_priv->vis_list_lock);
        kfree_skb(info->skb_packet);
+       kfree(info);
 }
 
 /* Compare two vis packets, used by the hashing algorithm */
@@ -268,10 +269,10 @@ int vis_seq_print_text(struct seq_file *seq, void *offset)
                                buff_pos += sprintf(buff + buff_pos, "%pM,",
                                                entry->addr);
 
-                               for (i = 0; i < packet->entries; i++)
+                               for (j = 0; j < packet->entries; j++)
                                        buff_pos += vis_data_read_entry(
                                                        buff + buff_pos,
-                                                       &entries[i],
+                                                       &entries[j],
                                                        entry->addr,
                                                        entry->primary);
 
@@ -444,7 +445,7 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv,
                              info);
        if (hash_added < 0) {
                /* did not work (for some reason) */
-               kref_put(&old_info->refcount, free_info);
+               kref_put(&info->refcount, free_info);
                info = NULL;
        }
 
@@ -815,7 +816,7 @@ static void send_vis_packets(struct work_struct *work)
                container_of(work, struct delayed_work, work);
        struct bat_priv *bat_priv =
                container_of(delayed_work, struct bat_priv, vis_work);
-       struct vis_info *info, *temp;
+       struct vis_info *info;
 
        spin_lock_bh(&bat_priv->vis_hash_lock);
        purge_vis_packets(bat_priv);
@@ -825,8 +826,9 @@ static void send_vis_packets(struct work_struct *work)
                send_list_add(bat_priv, bat_priv->my_vis_info);
        }
 
-       list_for_each_entry_safe(info, temp, &bat_priv->vis_send_list,
-                                send_list) {
+       while (!list_empty(&bat_priv->vis_send_list)) {
+               info = list_first_entry(&bat_priv->vis_send_list,
+                                       typeof(*info), send_list);
 
                kref_get(&info->refcount);
                spin_unlock_bh(&bat_priv->vis_hash_lock);
index 6b90a41..99cd8d9 100644 (file)
@@ -379,14 +379,10 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
        hci_conn_hold(acl);
 
        if (acl->state == BT_OPEN || acl->state == BT_CLOSED) {
-               acl->sec_level = sec_level;
+               acl->sec_level = BT_SECURITY_LOW;
+               acl->pending_sec_level = sec_level;
                acl->auth_type = auth_type;
                hci_acl_connect(acl);
-       } else {
-               if (acl->sec_level < sec_level)
-                       acl->sec_level = sec_level;
-               if (acl->auth_type < auth_type)
-                       acl->auth_type = auth_type;
        }
 
        if (type == ACL_LINK)
@@ -442,11 +438,17 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 {
        BT_DBG("conn %p", conn);
 
+       if (conn->pending_sec_level > sec_level)
+               sec_level = conn->pending_sec_level;
+
        if (sec_level > conn->sec_level)
-               conn->sec_level = sec_level;
+               conn->pending_sec_level = sec_level;
        else if (conn->link_mode & HCI_LM_AUTH)
                return 1;
 
+       /* Make sure we preserve an existing MITM requirement*/
+       auth_type |= (conn->auth_type & 0x01);
+
        conn->auth_type = auth_type;
 
        if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
index 8b602d8..9c4541b 100644 (file)
@@ -1011,6 +1011,10 @@ int hci_unregister_dev(struct hci_dev *hdev)
 
        destroy_workqueue(hdev->workqueue);
 
+       hci_dev_lock_bh(hdev);
+       hci_blacklist_clear(hdev);
+       hci_dev_unlock_bh(hdev);
+
        __hci_dev_put(hdev);
 
        return 0;
index 3810017..a290854 100644 (file)
@@ -692,13 +692,13 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev,
        if (conn->state != BT_CONFIG || !conn->out)
                return 0;
 
-       if (conn->sec_level == BT_SECURITY_SDP)
+       if (conn->pending_sec_level == BT_SECURITY_SDP)
                return 0;
 
        /* Only request authentication for SSP connections or non-SSP
         * devices with sec_level HIGH */
        if (!(hdev->ssp_mode > 0 && conn->ssp_mode > 0) &&
-                                       conn->sec_level != BT_SECURITY_HIGH)
+                               conn->pending_sec_level != BT_SECURITY_HIGH)
                return 0;
 
        return 1;
@@ -1095,9 +1095,10 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
 
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
        if (conn) {
-               if (!ev->status)
+               if (!ev->status) {
                        conn->link_mode |= HCI_LM_AUTH;
-               else
+                       conn->sec_level = conn->pending_sec_level;
+               } else
                        conn->sec_level = BT_SECURITY_LOW;
 
                clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
index c791fcd..675614e 100644 (file)
@@ -305,33 +305,44 @@ static void l2cap_chan_del(struct sock *sk, int err)
        }
 }
 
-/* Service level security */
-static inline int l2cap_check_security(struct sock *sk)
+static inline u8 l2cap_get_auth_type(struct sock *sk)
 {
-       struct l2cap_conn *conn = l2cap_pi(sk)->conn;
-       __u8 auth_type;
+       if (sk->sk_type == SOCK_RAW) {
+               switch (l2cap_pi(sk)->sec_level) {
+               case BT_SECURITY_HIGH:
+                       return HCI_AT_DEDICATED_BONDING_MITM;
+               case BT_SECURITY_MEDIUM:
+                       return HCI_AT_DEDICATED_BONDING;
+               default:
+                       return HCI_AT_NO_BONDING;
+               }
+       } else if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
+               if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
+                       l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
 
-       if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
                if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
-                       auth_type = HCI_AT_NO_BONDING_MITM;
+                       return HCI_AT_NO_BONDING_MITM;
                else
-                       auth_type = HCI_AT_NO_BONDING;
-
-               if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
-                       l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
+                       return HCI_AT_NO_BONDING;
        } else {
                switch (l2cap_pi(sk)->sec_level) {
                case BT_SECURITY_HIGH:
-                       auth_type = HCI_AT_GENERAL_BONDING_MITM;
-                       break;
+                       return HCI_AT_GENERAL_BONDING_MITM;
                case BT_SECURITY_MEDIUM:
-                       auth_type = HCI_AT_GENERAL_BONDING;
-                       break;
+                       return HCI_AT_GENERAL_BONDING;
                default:
-                       auth_type = HCI_AT_NO_BONDING;
-                       break;
+                       return HCI_AT_NO_BONDING;
                }
        }
+}
+
+/* Service level security */
+static inline int l2cap_check_security(struct sock *sk)
+{
+       struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+       __u8 auth_type;
+
+       auth_type = l2cap_get_auth_type(sk);
 
        return hci_conn_security(conn->hcon, l2cap_pi(sk)->sec_level,
                                                                auth_type);
@@ -848,6 +859,7 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
                                result = L2CAP_CR_SEC_BLOCK;
                        else
                                result = L2CAP_CR_BAD_PSM;
+                       sk->sk_state = BT_DISCONN;
 
                        rsp.scid   = cpu_to_le16(l2cap_pi(sk)->dcid);
                        rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
@@ -1068,39 +1080,7 @@ static int l2cap_do_connect(struct sock *sk)
 
        err = -ENOMEM;
 
-       if (sk->sk_type == SOCK_RAW) {
-               switch (l2cap_pi(sk)->sec_level) {
-               case BT_SECURITY_HIGH:
-                       auth_type = HCI_AT_DEDICATED_BONDING_MITM;
-                       break;
-               case BT_SECURITY_MEDIUM:
-                       auth_type = HCI_AT_DEDICATED_BONDING;
-                       break;
-               default:
-                       auth_type = HCI_AT_NO_BONDING;
-                       break;
-               }
-       } else if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
-               if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
-                       auth_type = HCI_AT_NO_BONDING_MITM;
-               else
-                       auth_type = HCI_AT_NO_BONDING;
-
-               if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
-                       l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
-       } else {
-               switch (l2cap_pi(sk)->sec_level) {
-               case BT_SECURITY_HIGH:
-                       auth_type = HCI_AT_GENERAL_BONDING_MITM;
-                       break;
-               case BT_SECURITY_MEDIUM:
-                       auth_type = HCI_AT_GENERAL_BONDING;
-                       break;
-               default:
-                       auth_type = HCI_AT_NO_BONDING;
-                       break;
-               }
-       }
+       auth_type = l2cap_get_auth_type(sk);
 
        hcon = hci_connect(hdev, ACL_LINK, dst,
                                        l2cap_pi(sk)->sec_level, auth_type);
@@ -1127,7 +1107,8 @@ static int l2cap_do_connect(struct sock *sk)
                if (sk->sk_type != SOCK_SEQPACKET &&
                                sk->sk_type != SOCK_STREAM) {
                        l2cap_sock_clear_timer(sk);
-                       sk->sk_state = BT_CONNECTED;
+                       if (l2cap_check_security(sk))
+                               sk->sk_state = BT_CONNECTED;
                } else
                        l2cap_do_start(sk);
        }
@@ -1893,8 +1874,8 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
                if (pi->mode == L2CAP_MODE_STREAMING) {
                        l2cap_streaming_send(sk);
                } else {
-                       if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY &&
-                                       pi->conn_state && L2CAP_CONN_WAIT_F) {
+                       if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
+                                       (pi->conn_state & L2CAP_CONN_WAIT_F)) {
                                err = len;
                                break;
                        }
index ff8aaa7..6b83776 100644 (file)
@@ -1164,7 +1164,8 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
                         * initiator rfcomm_process_rx already calls
                         * rfcomm_session_put() */
                        if (s->sock->sk->sk_state != BT_CLOSED)
-                               rfcomm_session_put(s);
+                               if (list_empty(&s->dlcs))
+                                       rfcomm_session_put(s);
                        break;
                }
        }
index 2575c2d..d7b9af4 100644 (file)
@@ -727,7 +727,9 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
                        break;
                }
 
+               tty_unlock();
                schedule();
+               tty_lock();
        }
        set_current_state(TASK_RUNNING);
        remove_wait_queue(&dev->wait, &wait);
index 9190ae4..6dee7bf 100644 (file)
@@ -6,6 +6,7 @@ config BRIDGE
        tristate "802.1d Ethernet Bridging"
        select LLC
        select STP
+       depends on IPV6 || IPV6=n
        ---help---
          If you say Y here, then your Linux box will be able to act as an
          Ethernet bridge, which means that the different Ethernet segments it
index 2872393..88485cc 100644 (file)
@@ -328,12 +328,12 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
        fdb = kmem_cache_alloc(br_fdb_cache, GFP_ATOMIC);
        if (fdb) {
                memcpy(fdb->addr.addr, addr, ETH_ALEN);
-               hlist_add_head_rcu(&fdb->hlist, head);
-
                fdb->dst = source;
                fdb->is_local = is_local;
                fdb->is_static = is_local;
                fdb->ageing_timer = jiffies;
+
+               hlist_add_head_rcu(&fdb->hlist, head);
        }
        return fdb;
 }
index 6f6d8e1..88e4aa9 100644 (file)
@@ -80,7 +80,7 @@ int br_handle_frame_finish(struct sk_buff *skb)
        if (is_multicast_ether_addr(dest)) {
                mdst = br_mdb_get(br, skb);
                if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) {
-                       if ((mdst && !hlist_unhashed(&mdst->mglist)) ||
+                       if ((mdst && mdst->mglist) ||
                            br_multicast_is_router(br))
                                skb2 = skb;
                        br_multicast_forward(mdst, skb, skb2);
index f701a21..030a002 100644 (file)
        rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock))
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-static inline int ipv6_is_local_multicast(const struct in6_addr *addr)
+static inline int ipv6_is_transient_multicast(const struct in6_addr *addr)
 {
-       if (ipv6_addr_is_multicast(addr) &&
-           IPV6_ADDR_MC_SCOPE(addr) <= IPV6_ADDR_SCOPE_LINKLOCAL)
+       if (ipv6_addr_is_multicast(addr) && IPV6_ADDR_MC_FLAG_TRANSIENT(addr))
                return 1;
        return 0;
 }
@@ -232,8 +231,7 @@ static void br_multicast_group_expired(unsigned long data)
        if (!netif_running(br->dev) || timer_pending(&mp->timer))
                goto out;
 
-       if (!hlist_unhashed(&mp->mglist))
-               hlist_del_init(&mp->mglist);
+       mp->mglist = false;
 
        if (mp->ports)
                goto out;
@@ -276,7 +274,7 @@ static void br_multicast_del_pg(struct net_bridge *br,
                del_timer(&p->query_timer);
                call_rcu_bh(&p->rcu, br_multicast_free_pg);
 
-               if (!mp->ports && hlist_unhashed(&mp->mglist) &&
+               if (!mp->ports && !mp->mglist &&
                    netif_running(br->dev))
                        mod_timer(&mp->timer, jiffies);
 
@@ -436,7 +434,6 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
        eth = eth_hdr(skb);
 
        memcpy(eth->h_source, br->dev->dev_addr, 6);
-       ipv6_eth_mc_map(group, eth->h_dest);
        eth->h_proto = htons(ETH_P_IPV6);
        skb_put(skb, sizeof(*eth));
 
@@ -448,8 +445,10 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
        ip6h->payload_len = htons(8 + sizeof(*mldq));
        ip6h->nexthdr = IPPROTO_HOPOPTS;
        ip6h->hop_limit = 1;
-       ipv6_addr_set(&ip6h->saddr, 0, 0, 0, 0);
+       ipv6_dev_get_saddr(dev_net(br->dev), br->dev, &ip6h->daddr, 0,
+                          &ip6h->saddr);
        ipv6_addr_set(&ip6h->daddr, htonl(0xff020000), 0, 0, htonl(1));
+       ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest);
 
        hopopt = (u8 *)(ip6h + 1);
        hopopt[0] = IPPROTO_ICMPV6;             /* next hdr */
@@ -528,7 +527,7 @@ static void br_multicast_group_query_expired(unsigned long data)
        struct net_bridge *br = mp->br;
 
        spin_lock(&br->multicast_lock);
-       if (!netif_running(br->dev) || hlist_unhashed(&mp->mglist) ||
+       if (!netif_running(br->dev) || !mp->mglist ||
            mp->queries_sent >= br->multicast_last_member_count)
                goto out;
 
@@ -719,7 +718,7 @@ static int br_multicast_add_group(struct net_bridge *br,
                goto err;
 
        if (!port) {
-               hlist_add_head(&mp->mglist, &br->mglist);
+               mp->mglist = true;
                mod_timer(&mp->timer, now + br->multicast_membership_interval);
                goto out;
        }
@@ -781,11 +780,11 @@ static int br_ip6_multicast_add_group(struct net_bridge *br,
 {
        struct br_ip br_group;
 
-       if (ipv6_is_local_multicast(group))
+       if (!ipv6_is_transient_multicast(group))
                return 0;
 
        ipv6_addr_copy(&br_group.u.ip6, group);
-       br_group.proto = htons(ETH_P_IP);
+       br_group.proto = htons(ETH_P_IPV6);
 
        return br_multicast_add_group(br, port, &br_group);
 }
@@ -1014,18 +1013,19 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
 
                nsrcs = skb_header_pointer(skb,
                                           len + offsetof(struct mld2_grec,
-                                                         grec_mca),
+                                                         grec_nsrcs),
                                           sizeof(_nsrcs), &_nsrcs);
                if (!nsrcs)
                        return -EINVAL;
 
                if (!pskb_may_pull(skb,
                                   len + sizeof(*grec) +
-                                  sizeof(struct in6_addr) * (*nsrcs)))
+                                  sizeof(struct in6_addr) * ntohs(*nsrcs)))
                        return -EINVAL;
 
                grec = (struct mld2_grec *)(skb->data + len);
-               len += sizeof(*grec) + sizeof(struct in6_addr) * (*nsrcs);
+               len += sizeof(*grec) +
+                      sizeof(struct in6_addr) * ntohs(*nsrcs);
 
                /* We treat these as MLDv1 reports for now. */
                switch (grec->grec_type) {
@@ -1165,7 +1165,7 @@ static int br_ip4_multicast_query(struct net_bridge *br,
 
        max_delay *= br->multicast_last_member_count;
 
-       if (!hlist_unhashed(&mp->mglist) &&
+       if (mp->mglist &&
            (timer_pending(&mp->timer) ?
             time_after(mp->timer.expires, now + max_delay) :
             try_to_del_timer_sync(&mp->timer) >= 0))
@@ -1177,7 +1177,7 @@ static int br_ip4_multicast_query(struct net_bridge *br,
                if (timer_pending(&p->timer) ?
                    time_after(p->timer.expires, now + max_delay) :
                    try_to_del_timer_sync(&p->timer) >= 0)
-                       mod_timer(&mp->timer, now + max_delay);
+                       mod_timer(&p->timer, now + max_delay);
        }
 
 out:
@@ -1236,7 +1236,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
                goto out;
 
        max_delay *= br->multicast_last_member_count;
-       if (!hlist_unhashed(&mp->mglist) &&
+       if (mp->mglist &&
            (timer_pending(&mp->timer) ?
             time_after(mp->timer.expires, now + max_delay) :
             try_to_del_timer_sync(&mp->timer) >= 0))
@@ -1248,7 +1248,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
                if (timer_pending(&p->timer) ?
                    time_after(p->timer.expires, now + max_delay) :
                    try_to_del_timer_sync(&p->timer) >= 0)
-                       mod_timer(&mp->timer, now + max_delay);
+                       mod_timer(&p->timer, now + max_delay);
        }
 
 out:
@@ -1283,7 +1283,7 @@ static void br_multicast_leave_group(struct net_bridge *br,
                     br->multicast_last_member_interval;
 
        if (!port) {
-               if (!hlist_unhashed(&mp->mglist) &&
+               if (mp->mglist &&
                    (timer_pending(&mp->timer) ?
                     time_after(mp->timer.expires, time) :
                     try_to_del_timer_sync(&mp->timer) >= 0)) {
@@ -1341,7 +1341,7 @@ static void br_ip6_multicast_leave_group(struct net_bridge *br,
 {
        struct br_ip br_group;
 
-       if (ipv6_is_local_multicast(group))
+       if (!ipv6_is_transient_multicast(group))
                return;
 
        ipv6_addr_copy(&br_group.u.ip6, group);
index 84aac77..4e1b620 100644 (file)
@@ -84,13 +84,13 @@ struct net_bridge_port_group {
 struct net_bridge_mdb_entry
 {
        struct hlist_node               hlist[2];
-       struct hlist_node               mglist;
        struct net_bridge               *br;
        struct net_bridge_port_group __rcu *ports;
        struct rcu_head                 rcu;
        struct timer_list               timer;
        struct timer_list               query_timer;
        struct br_ip                    addr;
+       bool                            mglist;
        u32                             queries_sent;
 };
 
@@ -238,7 +238,6 @@ struct net_bridge
        spinlock_t                      multicast_lock;
        struct net_bridge_mdb_htable __rcu *mdb;
        struct hlist_head               router_list;
-       struct hlist_head               mglist;
 
        struct timer_list               multicast_router_timer;
        struct timer_list               multicast_querier_timer;
index fa9dab3..6008d6d 100644 (file)
@@ -394,9 +394,7 @@ static void ipcaif_net_setup(struct net_device *dev)
        priv->conn_req.sockaddr.u.dgm.connection_id = -1;
        priv->flowenabled = false;
 
-       ASSERT_RTNL();
        init_waitqueue_head(&priv->netmgmt_wq);
-       list_add(&priv->list_field, &chnl_net_list);
 }
 
 
@@ -453,6 +451,8 @@ static int ipcaif_newlink(struct net *src_net, struct net_device *dev,
        ret = register_netdevice(dev);
        if (ret)
                pr_warn("device rtml registration failed\n");
+       else
+               list_add(&caifdev->list_field, &chnl_net_list);
        return ret;
 }
 
index dff633d..05f3578 100644 (file)
@@ -252,8 +252,12 @@ static int ceph_tcp_recvmsg(struct socket *sock, void *buf, size_t len)
 {
        struct kvec iov = {buf, len};
        struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL };
+       int r;
 
-       return kernel_recvmsg(sock, &msg, &iov, 1, len, msg.msg_flags);
+       r = kernel_recvmsg(sock, &msg, &iov, 1, len, msg.msg_flags);
+       if (r == -EAGAIN)
+               r = 0;
+       return r;
 }
 
 /*
@@ -264,13 +268,17 @@ static int ceph_tcp_sendmsg(struct socket *sock, struct kvec *iov,
                     size_t kvlen, size_t len, int more)
 {
        struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL };
+       int r;
 
        if (more)
                msg.msg_flags |= MSG_MORE;
        else
                msg.msg_flags |= MSG_EOR;  /* superfluous, but what the hell */
 
-       return kernel_sendmsg(sock, &msg, iov, kvlen, len);
+       r = kernel_sendmsg(sock, &msg, iov, kvlen, len);
+       if (r == -EAGAIN)
+               r = 0;
+       return r;
 }
 
 
@@ -328,7 +336,6 @@ static void reset_connection(struct ceph_connection *con)
                ceph_msg_put(con->out_msg);
                con->out_msg = NULL;
        }
-       con->out_keepalive_pending = false;
        con->in_seq = 0;
        con->in_seq_acked = 0;
 }
@@ -847,6 +854,8 @@ static int write_partial_msg_pages(struct ceph_connection *con)
                    (msg->pages || msg->pagelist || msg->bio || in_trail))
                        kunmap(page);
 
+               if (ret == -EAGAIN)
+                       ret = 0;
                if (ret <= 0)
                        goto out;
 
@@ -1238,8 +1247,6 @@ static int process_connect(struct ceph_connection *con)
                     con->auth_retry);
                if (con->auth_retry == 2) {
                        con->error_msg = "connect authorization failure";
-                       reset_connection(con);
-                       set_bit(CLOSED, &con->state);
                        return -1;
                }
                con->auth_retry = 1;
@@ -1705,14 +1712,6 @@ more:
 
        /* open the socket first? */
        if (con->sock == NULL) {
-               /*
-                * if we were STANDBY and are reconnecting _this_
-                * connection, bump connect_seq now.  Always bump
-                * global_seq.
-                */
-               if (test_and_clear_bit(STANDBY, &con->state))
-                       con->connect_seq++;
-
                prepare_write_banner(msgr, con);
                prepare_write_connect(msgr, con, 1);
                prepare_read_banner(con);
@@ -1737,16 +1736,12 @@ more_kvec:
        if (con->out_skip) {
                ret = write_partial_skip(con);
                if (ret <= 0)
-                       goto done;
-               if (ret < 0) {
-                       dout("try_write write_partial_skip err %d\n", ret);
-                       goto done;
-               }
+                       goto out;
        }
        if (con->out_kvec_left) {
                ret = write_partial_kvec(con);
                if (ret <= 0)
-                       goto done;
+                       goto out;
        }
 
        /* msg pages? */
@@ -1761,11 +1756,11 @@ more_kvec:
                if (ret == 1)
                        goto more_kvec;  /* we need to send the footer, too! */
                if (ret == 0)
-                       goto done;
+                       goto out;
                if (ret < 0) {
                        dout("try_write write_partial_msg_pages err %d\n",
                             ret);
-                       goto done;
+                       goto out;
                }
        }
 
@@ -1789,10 +1784,9 @@ do_next:
        /* Nothing to do! */
        clear_bit(WRITE_PENDING, &con->state);
        dout("try_write nothing else to write.\n");
-done:
        ret = 0;
 out:
-       dout("try_write done on %p\n", con);
+       dout("try_write done on %p ret %d\n", con, ret);
        return ret;
 }
 
@@ -1821,19 +1815,17 @@ more:
                        dout("try_read connecting\n");
                        ret = read_partial_banner(con);
                        if (ret <= 0)
-                               goto done;
-                       if (process_banner(con) < 0) {
-                               ret = -1;
                                goto out;
-                       }
+                       ret = process_banner(con);
+                       if (ret < 0)
+                               goto out;
                }
                ret = read_partial_connect(con);
                if (ret <= 0)
-                       goto done;
-               if (process_connect(con) < 0) {
-                       ret = -1;
                        goto out;
-               }
+               ret = process_connect(con);
+               if (ret < 0)
+                       goto out;
                goto more;
        }
 
@@ -1848,7 +1840,7 @@ more:
                dout("skipping %d / %d bytes\n", skip, -con->in_base_pos);
                ret = ceph_tcp_recvmsg(con->sock, buf, skip);
                if (ret <= 0)
-                       goto done;
+                       goto out;
                con->in_base_pos += ret;
                if (con->in_base_pos)
                        goto more;
@@ -1859,7 +1851,7 @@ more:
                 */
                ret = ceph_tcp_recvmsg(con->sock, &con->in_tag, 1);
                if (ret <= 0)
-                       goto done;
+                       goto out;
                dout("try_read got tag %d\n", (int)con->in_tag);
                switch (con->in_tag) {
                case CEPH_MSGR_TAG_MSG:
@@ -1870,7 +1862,7 @@ more:
                        break;
                case CEPH_MSGR_TAG_CLOSE:
                        set_bit(CLOSED, &con->state);   /* fixme */
-                       goto done;
+                       goto out;
                default:
                        goto bad_tag;
                }
@@ -1882,13 +1874,12 @@ more:
                        case -EBADMSG:
                                con->error_msg = "bad crc";
                                ret = -EIO;
-                               goto out;
+                               break;
                        case -EIO:
                                con->error_msg = "io error";
-                               goto out;
-                       default:
-                               goto done;
+                               break;
                        }
+                       goto out;
                }
                if (con->in_tag == CEPH_MSGR_TAG_READY)
                        goto more;
@@ -1898,15 +1889,13 @@ more:
        if (con->in_tag == CEPH_MSGR_TAG_ACK) {
                ret = read_partial_ack(con);
                if (ret <= 0)
-                       goto done;
+                       goto out;
                process_ack(con);
                goto more;
        }
 
-done:
-       ret = 0;
 out:
-       dout("try_read done on %p\n", con);
+       dout("try_read done on %p ret %d\n", con, ret);
        return ret;
 
 bad_tag:
@@ -1951,7 +1940,24 @@ static void con_work(struct work_struct *work)
                                                   work.work);
 
        mutex_lock(&con->mutex);
+       if (test_and_clear_bit(BACKOFF, &con->state)) {
+               dout("con_work %p backing off\n", con);
+               if (queue_delayed_work(ceph_msgr_wq, &con->work,
+                                      round_jiffies_relative(con->delay))) {
+                       dout("con_work %p backoff %lu\n", con, con->delay);
+                       mutex_unlock(&con->mutex);
+                       return;
+               } else {
+                       con->ops->put(con);
+                       dout("con_work %p FAILED to back off %lu\n", con,
+                            con->delay);
+               }
+       }
 
+       if (test_bit(STANDBY, &con->state)) {
+               dout("con_work %p STANDBY\n", con);
+               goto done;
+       }
        if (test_bit(CLOSED, &con->state)) { /* e.g. if we are replaced */
                dout("con_work CLOSED\n");
                con_close_socket(con);
@@ -2008,10 +2014,12 @@ static void ceph_fault(struct ceph_connection *con)
        /* Requeue anything that hasn't been acked */
        list_splice_init(&con->out_sent, &con->out_queue);
 
-       /* If there are no messages in the queue, place the connection
-        * in a STANDBY state (i.e., don't try to reconnect just yet). */
-       if (list_empty(&con->out_queue) && !con->out_keepalive_pending) {
-               dout("fault setting STANDBY\n");
+       /* If there are no messages queued or keepalive pending, place
+        * the connection in a STANDBY state */
+       if (list_empty(&con->out_queue) &&
+           !test_bit(KEEPALIVE_PENDING, &con->state)) {
+               dout("fault %p setting STANDBY clearing WRITE_PENDING\n", con);
+               clear_bit(WRITE_PENDING, &con->state);
                set_bit(STANDBY, &con->state);
        } else {
                /* retry after a delay. */
@@ -2019,11 +2027,24 @@ static void ceph_fault(struct ceph_connection *con)
                        con->delay = BASE_DELAY_INTERVAL;
                else if (con->delay < MAX_DELAY_INTERVAL)
                        con->delay *= 2;
-               dout("fault queueing %p delay %lu\n", con, con->delay);
                con->ops->get(con);
                if (queue_delayed_work(ceph_msgr_wq, &con->work,
-                                      round_jiffies_relative(con->delay)) == 0)
+                                      round_jiffies_relative(con->delay))) {
+                       dout("fault queued %p delay %lu\n", con, con->delay);
+               } else {
                        con->ops->put(con);
+                       dout("fault failed to queue %p delay %lu, backoff\n",
+                            con, con->delay);
+                       /*
+                        * In many cases we see a socket state change
+                        * while con_work is running and end up
+                        * queuing (non-delayed) work, such that we
+                        * can't backoff with a delay.  Set a flag so
+                        * that when con_work restarts we schedule the
+                        * delay then.
+                        */
+                       set_bit(BACKOFF, &con->state);
+               }
        }
 
 out_unlock:
@@ -2094,6 +2115,19 @@ void ceph_messenger_destroy(struct ceph_messenger *msgr)
 }
 EXPORT_SYMBOL(ceph_messenger_destroy);
 
+static void clear_standby(struct ceph_connection *con)
+{
+       /* come back from STANDBY? */
+       if (test_and_clear_bit(STANDBY, &con->state)) {
+               mutex_lock(&con->mutex);
+               dout("clear_standby %p and ++connect_seq\n", con);
+               con->connect_seq++;
+               WARN_ON(test_bit(WRITE_PENDING, &con->state));
+               WARN_ON(test_bit(KEEPALIVE_PENDING, &con->state));
+               mutex_unlock(&con->mutex);
+       }
+}
+
 /*
  * Queue up an outgoing message on the given connection.
  */
@@ -2126,6 +2160,7 @@ void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg)
 
        /* if there wasn't anything waiting to send before, queue
         * new work */
+       clear_standby(con);
        if (test_and_set_bit(WRITE_PENDING, &con->state) == 0)
                queue_con(con);
 }
@@ -2191,6 +2226,8 @@ void ceph_con_revoke_message(struct ceph_connection *con, struct ceph_msg *msg)
  */
 void ceph_con_keepalive(struct ceph_connection *con)
 {
+       dout("con_keepalive %p\n", con);
+       clear_standby(con);
        if (test_and_set_bit(KEEPALIVE_PENDING, &con->state) == 0 &&
            test_and_set_bit(WRITE_PENDING, &con->state) == 0)
                queue_con(con);
index 1a040e6..cd9c21d 100644 (file)
@@ -16,22 +16,30 @@ struct page **ceph_get_direct_page_vector(const char __user *data,
                                          int num_pages, bool write_page)
 {
        struct page **pages;
-       int rc;
+       int got = 0;
+       int rc = 0;
 
        pages = kmalloc(sizeof(*pages) * num_pages, GFP_NOFS);
        if (!pages)
                return ERR_PTR(-ENOMEM);
 
        down_read(&current->mm->mmap_sem);
-       rc = get_user_pages(current, current->mm, (unsigned long)data,
-                           num_pages, write_page, 0, pages, NULL);
+       while (got < num_pages) {
+               rc = get_user_pages(current, current->mm,
+                   (unsigned long)data + ((unsigned long)got * PAGE_SIZE),
+                   num_pages - got, write_page, 0, pages + got, NULL);
+               if (rc < 0)
+                       break;
+               BUG_ON(rc == 0);
+               got += rc;
+       }
        up_read(&current->mm->mmap_sem);
-       if (rc < num_pages)
+       if (rc < 0)
                goto fail;
        return pages;
 
 fail:
-       ceph_put_page_vector(pages, rc > 0 ? rc : 0, false);
+       ceph_put_page_vector(pages, got, false);
        return ERR_PTR(rc);
 }
 EXPORT_SYMBOL(ceph_get_direct_page_vector);
index 7c6a46f..6561021 100644 (file)
@@ -749,7 +749,8 @@ EXPORT_SYMBOL(dev_get_by_index);
  *     @ha: hardware address
  *
  *     Search for an interface by MAC address. Returns NULL if the device
- *     is not found or a pointer to the device. The caller must hold RCU
+ *     is not found or a pointer to the device.
+ *     The caller must hold RCU or RTNL.
  *     The returned device has not had its ref count increased
  *     and the caller must therefore be careful about locking
  *
@@ -1113,13 +1114,21 @@ EXPORT_SYMBOL(netdev_bonding_change);
 void dev_load(struct net *net, const char *name)
 {
        struct net_device *dev;
+       int no_module;
 
        rcu_read_lock();
        dev = dev_get_by_name_rcu(net, name);
        rcu_read_unlock();
 
-       if (!dev && capable(CAP_NET_ADMIN))
-               request_module("%s", name);
+       no_module = !dev;
+       if (no_module && capable(CAP_NET_ADMIN))
+               no_module = request_module("netdev-%s", name);
+       if (no_module && capable(CAP_SYS_MODULE)) {
+               if (!request_module("%s", name))
+                       pr_err("Loading kernel module for a network device "
+"with CAP_SYS_MODULE (deprecated).  Use CAP_NET_ADMIN and alias netdev-%s "
+"instead\n", name);
+       }
 }
 EXPORT_SYMBOL(dev_load);
 
@@ -1279,10 +1288,13 @@ static int __dev_close_many(struct list_head *head)
 
 static int __dev_close(struct net_device *dev)
 {
+       int retval;
        LIST_HEAD(single);
 
        list_add(&dev->unreg_list, &single);
-       return __dev_close_many(&single);
+       retval = __dev_close_many(&single);
+       list_del(&single);
+       return retval;
 }
 
 int dev_close_many(struct list_head *head)
@@ -1324,7 +1336,7 @@ int dev_close(struct net_device *dev)
 
        list_add(&dev->unreg_list, &single);
        dev_close_many(&single);
-
+       list_del(&single);
        return 0;
 }
 EXPORT_SYMBOL(dev_close);
@@ -2562,7 +2574,8 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
 
        map = rcu_dereference(rxqueue->rps_map);
        if (map) {
-               if (map->len == 1) {
+               if (map->len == 1 &&
+                   !rcu_dereference_raw(rxqueue->rps_flow_table)) {
                        tcpu = map->cpus[0];
                        if (cpu_online(tcpu))
                                cpu = tcpu;
@@ -3423,6 +3436,8 @@ static void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb)
        __skb_pull(skb, skb_headlen(skb));
        skb_reserve(skb, NET_IP_ALIGN - skb_headroom(skb));
        skb->vlan_tci = 0;
+       skb->dev = napi->dev;
+       skb->skb_iif = 0;
 
        napi->skb = skb;
 }
@@ -5059,6 +5074,7 @@ static void rollback_registered(struct net_device *dev)
 
        list_add(&dev->unreg_list, &single);
        rollback_registered_many(&single);
+       list_del(&single);
 }
 
 unsigned long netdev_fix_features(unsigned long features, const char *name)
@@ -5656,30 +5672,35 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
 
        dev_net_set(dev, &init_net);
 
+       dev->gso_max_size = GSO_MAX_SIZE;
+
+       INIT_LIST_HEAD(&dev->ethtool_ntuple_list.list);
+       dev->ethtool_ntuple_list.count = 0;
+       INIT_LIST_HEAD(&dev->napi_list);
+       INIT_LIST_HEAD(&dev->unreg_list);
+       INIT_LIST_HEAD(&dev->link_watch_list);
+       dev->priv_flags = IFF_XMIT_DST_RELEASE;
+       setup(dev);
+
        dev->num_tx_queues = txqs;
        dev->real_num_tx_queues = txqs;
        if (netif_alloc_netdev_queues(dev))
-               goto free_pcpu;
+               goto free_all;
 
 #ifdef CONFIG_RPS
        dev->num_rx_queues = rxqs;
        dev->real_num_rx_queues = rxqs;
        if (netif_alloc_rx_queues(dev))
-               goto free_pcpu;
+               goto free_all;
 #endif
 
-       dev->gso_max_size = GSO_MAX_SIZE;
-
-       INIT_LIST_HEAD(&dev->ethtool_ntuple_list.list);
-       dev->ethtool_ntuple_list.count = 0;
-       INIT_LIST_HEAD(&dev->napi_list);
-       INIT_LIST_HEAD(&dev->unreg_list);
-       INIT_LIST_HEAD(&dev->link_watch_list);
-       dev->priv_flags = IFF_XMIT_DST_RELEASE;
-       setup(dev);
        strcpy(dev->name, name);
        return dev;
 
+free_all:
+       free_netdev(dev);
+       return NULL;
+
 free_pcpu:
        free_percpu(dev->pcpu_refcnt);
        kfree(dev->_tx);
@@ -6207,6 +6228,7 @@ static void __net_exit default_device_exit_batch(struct list_head *net_list)
                }
        }
        unregister_netdevice_many(&dev_kill_list);
+       list_del(&dev_kill_list);
        rtnl_unlock();
 }
 
index 508f9c1..133fd22 100644 (file)
@@ -144,7 +144,7 @@ void __hw_addr_del_multiple(struct netdev_hw_addr_list *to_list,
 
        list_for_each_entry(ha, &from_list->list, list) {
                type = addr_type ? addr_type : ha->type;
-               __hw_addr_del(to_list, ha->addr, addr_len, addr_type);
+               __hw_addr_del(to_list, ha->addr, addr_len, type);
        }
 }
 EXPORT_SYMBOL(__hw_addr_del_multiple);
index 1774178..ff23029 100644 (file)
@@ -817,7 +817,7 @@ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
        if (regs.len > reglen)
                regs.len = reglen;
 
-       regbuf = vmalloc(reglen);
+       regbuf = vzalloc(reglen);
        if (!regbuf)
                return -ENOMEM;
 
index a9e7fc4..b5bada9 100644 (file)
@@ -3321,7 +3321,7 @@ static void show_results(struct pktgen_dev *pkt_dev, int nr_frags)
                                    pkt_dev->started_at);
        ktime_t idle = ns_to_ktime(pkt_dev->idle_acc);
 
-       p += sprintf(p, "OK: %llu(c%llu+d%llu) nsec, %llu (%dbyte,%dfrags)\n",
+       p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags)\n",
                     (unsigned long long)ktime_to_us(elapsed),
                     (unsigned long long)ktime_to_us(ktime_sub(elapsed, idle)),
                     (unsigned long long)ktime_to_us(idle),
index 750db57..2d65c6b 100644 (file)
@@ -1121,8 +1121,7 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])
                                return -EOPNOTSUPP;
 
                        if (af_ops->validate_link_af) {
-                               err = af_ops->validate_link_af(dev,
-                                                       tb[IFLA_AF_SPEC]);
+                               err = af_ops->validate_link_af(dev, af);
                                if (err < 0)
                                        return err;
                        }
@@ -1672,6 +1671,9 @@ replay:
                        snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind);
 
                dest_net = rtnl_link_get_net(net, tb);
+               if (IS_ERR(dest_net))
+                       return PTR_ERR(dest_net);
+
                dev = rtnl_create_link(net, dest_net, ifname, ops, tb);
 
                if (IS_ERR(dev))
index bbe4544..4c1ef02 100644 (file)
@@ -95,7 +95,7 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
                int fd = fdp[i];
                struct file *file;
 
-               if (fd < 0 || !(file = fget(fd)))
+               if (fd < 0 || !(file = fget_raw(fd)))
                        return -EBADF;
                *fpp++ = file;
                fpl->count++;
index d31bb36..d883dcc 100644 (file)
@@ -210,6 +210,7 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
        shinfo = skb_shinfo(skb);
        memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
        atomic_set(&shinfo->dataref, 1);
+       kmemcheck_annotate_variable(shinfo->destructor_arg);
 
        if (fclone) {
                struct sk_buff *child = skb + 1;
@@ -2744,8 +2745,12 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
 
 merge:
        if (offset > headlen) {
-               skbinfo->frags[0].page_offset += offset - headlen;
-               skbinfo->frags[0].size -= offset - headlen;
+               unsigned int eat = offset - headlen;
+
+               skbinfo->frags[0].page_offset += eat;
+               skbinfo->frags[0].size -= eat;
+               skb->data_len -= eat;
+               skb->len -= eat;
                offset = headlen;
        }
 
index d900ab9..c44348a 100644 (file)
@@ -583,7 +583,7 @@ static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb,
        u8 up, idtype;
        int ret = -EINVAL;
 
-       if (!tb[DCB_ATTR_APP] || !netdev->dcbnl_ops->getapp)
+       if (!tb[DCB_ATTR_APP])
                goto out;
 
        ret = nla_parse_nested(app_tb, DCB_APP_ATTR_MAX, tb[DCB_ATTR_APP],
@@ -604,7 +604,16 @@ static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb,
                goto out;
 
        id = nla_get_u16(app_tb[DCB_APP_ATTR_ID]);
-       up = netdev->dcbnl_ops->getapp(netdev, idtype, id);
+
+       if (netdev->dcbnl_ops->getapp) {
+               up = netdev->dcbnl_ops->getapp(netdev, idtype, id);
+       } else {
+               struct dcb_app app = {
+                                       .selector = idtype,
+                                       .protocol = id,
+                                    };
+               up = dcb_getapp(netdev, &app);
+       }
 
        /* send this back */
        dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
@@ -617,6 +626,9 @@ static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb,
        dcb->cmd = DCB_CMD_GAPP;
 
        app_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_APP);
+       if (!app_nest)
+               goto out_cancel;
+
        ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_IDTYPE, idtype);
        if (ret)
                goto out_cancel;
@@ -1181,7 +1193,7 @@ static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb,
                        goto err;
        }
 
-       if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setets) {
+       if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) {
                struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]);
                err = ops->ieee_setpfc(netdev, pfc);
                if (err)
@@ -1604,6 +1616,10 @@ EXPORT_SYMBOL(dcb_getapp);
 u8 dcb_setapp(struct net_device *dev, struct dcb_app *new)
 {
        struct dcb_app_type *itr;
+       struct dcb_app_type event;
+
+       memcpy(&event.name, dev->name, sizeof(event.name));
+       memcpy(&event.app, new, sizeof(event.app));
 
        spin_lock(&dcb_lock);
        /* Search for existing match and replace */
@@ -1635,7 +1651,7 @@ u8 dcb_setapp(struct net_device *dev, struct dcb_app *new)
        }
 out:
        spin_unlock(&dcb_lock);
-       call_dcbevent_notifiers(DCB_APP_EVENT, new);
+       call_dcbevent_notifiers(DCB_APP_EVENT, &event);
        return 0;
 }
 EXPORT_SYMBOL(dcb_setapp);
index 8cde009..4222e7a 100644 (file)
@@ -614,6 +614,9 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                /* Caller (dccp_v4_do_rcv) will send Reset */
                dcb->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION;
                return 1;
+       } else if (sk->sk_state == DCCP_CLOSED) {
+               dcb->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION;
+               return 1;
        }
 
        if (sk->sk_state != DCCP_REQUESTING && sk->sk_state != DCCP_RESPOND) {
@@ -668,10 +671,6 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
        }
 
        switch (sk->sk_state) {
-       case DCCP_CLOSED:
-               dcb->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION;
-               return 1;
-
        case DCCP_REQUESTING:
                queued = dccp_rcv_request_sent_state_process(sk, skb, dh, len);
                if (queued >= 0)
index 739435a..cfa7a5e 100644 (file)
@@ -67,8 +67,9 @@ dns_resolver_instantiate(struct key *key, const void *_data, size_t datalen)
        size_t result_len = 0;
        const char *data = _data, *end, *opt;
 
-       kenter("%%%d,%s,'%s',%zu",
-              key->serial, key->description, data, datalen);
+       kenter("%%%d,%s,'%*.*s',%zu",
+              key->serial, key->description,
+              (int)datalen, (int)datalen, data, datalen);
 
        if (datalen <= 1 || !data || data[datalen - 1] != '\0')
                return -EINVAL;
@@ -217,6 +218,19 @@ static void dns_resolver_describe(const struct key *key, struct seq_file *m)
                seq_printf(m, ": %u", key->datalen);
 }
 
+/*
+ * read the DNS data
+ * - the key's semaphore is read-locked
+ */
+static long dns_resolver_read(const struct key *key,
+                             char __user *buffer, size_t buflen)
+{
+       if (key->type_data.x[0])
+               return key->type_data.x[0];
+
+       return user_read(key, buffer, buflen);
+}
+
 struct key_type key_type_dns_resolver = {
        .name           = "dns_resolver",
        .instantiate    = dns_resolver_instantiate,
@@ -224,7 +238,7 @@ struct key_type key_type_dns_resolver = {
        .revoke         = user_revoke,
        .destroy        = user_destroy,
        .describe       = dns_resolver_describe,
-       .read           = user_read,
+       .read           = dns_resolver_read,
 };
 
 static int __init init_dns_resolver(void)
index 15dcc1a..0c28263 100644 (file)
@@ -265,13 +265,13 @@ static void ec_tx_done(struct sk_buff *skb, int result)
 static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
                          struct msghdr *msg, size_t len)
 {
-       struct sock *sk = sock->sk;
        struct sockaddr_ec *saddr=(struct sockaddr_ec *)msg->msg_name;
        struct net_device *dev;
        struct ec_addr addr;
        int err;
        unsigned char port, cb;
 #if defined(CONFIG_ECONET_AUNUDP) || defined(CONFIG_ECONET_NATIVE)
+       struct sock *sk = sock->sk;
        struct sk_buff *skb;
        struct ec_cb *eb;
 #endif
@@ -488,10 +488,10 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
 
 error_free_buf:
        vfree(userbuf);
+error:
 #else
        err = -EPROTOTYPE;
 #endif
-       error:
        mutex_unlock(&econet_mutex);
 
        return err;
index f2b6110..45b89d7 100644 (file)
@@ -880,6 +880,19 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 }
 EXPORT_SYMBOL(inet_ioctl);
 
+#ifdef CONFIG_COMPAT
+int inet_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+       struct sock *sk = sock->sk;
+       int err = -ENOIOCTLCMD;
+
+       if (sk->sk_prot->compat_ioctl)
+               err = sk->sk_prot->compat_ioctl(sk, cmd, arg);
+
+       return err;
+}
+#endif
+
 const struct proto_ops inet_stream_ops = {
        .family            = PF_INET,
        .owner             = THIS_MODULE,
@@ -903,6 +916,7 @@ const struct proto_ops inet_stream_ops = {
 #ifdef CONFIG_COMPAT
        .compat_setsockopt = compat_sock_common_setsockopt,
        .compat_getsockopt = compat_sock_common_getsockopt,
+       .compat_ioctl      = inet_compat_ioctl,
 #endif
 };
 EXPORT_SYMBOL(inet_stream_ops);
@@ -929,6 +943,7 @@ const struct proto_ops inet_dgram_ops = {
 #ifdef CONFIG_COMPAT
        .compat_setsockopt = compat_sock_common_setsockopt,
        .compat_getsockopt = compat_sock_common_getsockopt,
+       .compat_ioctl      = inet_compat_ioctl,
 #endif
 };
 EXPORT_SYMBOL(inet_dgram_ops);
@@ -959,6 +974,7 @@ static const struct proto_ops inet_sockraw_ops = {
 #ifdef CONFIG_COMPAT
        .compat_setsockopt = compat_sock_common_setsockopt,
        .compat_getsockopt = compat_sock_common_getsockopt,
+       .compat_ioctl      = inet_compat_ioctl,
 #endif
 };
 
index 04c8b69..7927589 100644 (file)
@@ -1017,14 +1017,13 @@ static int arp_req_set_proxy(struct net *net, struct net_device *dev, int on)
                IPV4_DEVCONF_ALL(net, PROXY_ARP) = on;
                return 0;
        }
-       if (__in_dev_get_rcu(dev)) {
-               IN_DEV_CONF_SET(__in_dev_get_rcu(dev), PROXY_ARP, on);
+       if (__in_dev_get_rtnl(dev)) {
+               IN_DEV_CONF_SET(__in_dev_get_rtnl(dev), PROXY_ARP, on);
                return 0;
        }
        return -ENXIO;
 }
 
-/* must be called with rcu_read_lock() */
 static int arp_req_set_public(struct net *net, struct arpreq *r,
                struct net_device *dev)
 {
@@ -1233,10 +1232,10 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
        if (!(r.arp_flags & ATF_NETMASK))
                ((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr =
                                                           htonl(0xFFFFFFFFUL);
-       rcu_read_lock();
+       rtnl_lock();
        if (r.arp_dev[0]) {
                err = -ENODEV;
-               dev = dev_get_by_name_rcu(net, r.arp_dev);
+               dev = __dev_get_by_name(net, r.arp_dev);
                if (dev == NULL)
                        goto out;
 
@@ -1263,7 +1262,7 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
                break;
        }
 out:
-       rcu_read_unlock();
+       rtnl_unlock();
        if (cmd == SIOCGARP && !err && copy_to_user(arg, &r, sizeof(r)))
                err = -EFAULT;
        return err;
index 748cb5b..036652c 100644 (file)
@@ -670,7 +670,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
                             ifap = &ifa->ifa_next) {
                                if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
                                    sin_orig.sin_addr.s_addr ==
-                                                       ifa->ifa_address) {
+                                                       ifa->ifa_local) {
                                        break; /* found */
                                }
                        }
@@ -1030,6 +1030,21 @@ static inline bool inetdev_valid_mtu(unsigned mtu)
        return mtu >= 68;
 }
 
+static void inetdev_send_gratuitous_arp(struct net_device *dev,
+                                       struct in_device *in_dev)
+
+{
+       struct in_ifaddr *ifa = in_dev->ifa_list;
+
+       if (!ifa)
+               return;
+
+       arp_send(ARPOP_REQUEST, ETH_P_ARP,
+                ifa->ifa_local, dev,
+                ifa->ifa_local, NULL,
+                dev->dev_addr, NULL);
+}
+
 /* Called only under RTNL semaphore */
 
 static int inetdev_event(struct notifier_block *this, unsigned long event,
@@ -1082,18 +1097,13 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
                }
                ip_mc_up(in_dev);
                /* fall through */
-       case NETDEV_NOTIFY_PEERS:
        case NETDEV_CHANGEADDR:
+               if (!IN_DEV_ARP_NOTIFY(in_dev))
+                       break;
+               /* fall through */
+       case NETDEV_NOTIFY_PEERS:
                /* Send gratuitous ARP to notify of link change */
-               if (IN_DEV_ARP_NOTIFY(in_dev)) {
-                       struct in_ifaddr *ifa = in_dev->ifa_list;
-
-                       if (ifa)
-                               arp_send(ARPOP_REQUEST, ETH_P_ARP,
-                                        ifa->ifa_address, dev,
-                                        ifa->ifa_address, NULL,
-                                        dev->dev_addr, NULL);
-               }
+               inetdev_send_gratuitous_arp(dev, in_dev);
                break;
        case NETDEV_DOWN:
                ip_mc_down(in_dev);
index c5af909..3c8dfa1 100644 (file)
@@ -505,7 +505,9 @@ restart:
                        }
 
                        rcu_read_unlock();
+                       local_bh_disable();
                        inet_twsk_deschedule(tw, twdr);
+                       local_bh_enable();
                        inet_twsk_put(tw);
                        goto restart_rcu;
                }
index d9bc857..a96e656 100644 (file)
@@ -475,7 +475,7 @@ static int cleanup_once(unsigned long ttl)
 struct inet_peer *inet_getpeer(struct inetpeer_addr *daddr, int create)
 {
        struct inet_peer __rcu **stack[PEER_MAXDEPTH], ***stackptr;
-       struct inet_peer_base *base = family_to_base(AF_INET);
+       struct inet_peer_base *base = family_to_base(daddr->family);
        struct inet_peer *p;
 
        /* Look up for the address quickly, lockless.
index eb68a0e..d1d0e2c 100644 (file)
@@ -775,6 +775,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
                        .fl4_dst = dst,
                        .fl4_src = tiph->saddr,
                        .fl4_tos = RT_TOS(tos),
+                       .proto = IPPROTO_GRE,
                        .fl_gre_key = tunnel->parms.o_key
                };
                if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
@@ -1764,4 +1765,4 @@ module_exit(ipgre_fini);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_RTNL_LINK("gre");
 MODULE_ALIAS_RTNL_LINK("gretap");
-MODULE_ALIAS("gre0");
+MODULE_ALIAS_NETDEV("gre0");
index 988f52f..a5f58e7 100644 (file)
@@ -913,4 +913,4 @@ static void __exit ipip_fini(void)
 module_init(ipip_init);
 module_exit(ipip_fini);
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("tunl0");
+MODULE_ALIAS_NETDEV("tunl0");
index 3f3a9af..8b65a12 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/notifier.h>
 #include <linux/if_arp.h>
 #include <linux/netfilter_ipv4.h>
+#include <linux/compat.h>
 #include <net/ipip.h>
 #include <net/checksum.h>
 #include <net/netlink.h>
@@ -1434,6 +1435,81 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
        }
 }
 
+#ifdef CONFIG_COMPAT
+struct compat_sioc_sg_req {
+       struct in_addr src;
+       struct in_addr grp;
+       compat_ulong_t pktcnt;
+       compat_ulong_t bytecnt;
+       compat_ulong_t wrong_if;
+};
+
+struct compat_sioc_vif_req {
+       vifi_t  vifi;           /* Which iface */
+       compat_ulong_t icount;
+       compat_ulong_t ocount;
+       compat_ulong_t ibytes;
+       compat_ulong_t obytes;
+};
+
+int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
+{
+       struct compat_sioc_sg_req sr;
+       struct compat_sioc_vif_req vr;
+       struct vif_device *vif;
+       struct mfc_cache *c;
+       struct net *net = sock_net(sk);
+       struct mr_table *mrt;
+
+       mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
+       if (mrt == NULL)
+               return -ENOENT;
+
+       switch (cmd) {
+       case SIOCGETVIFCNT:
+               if (copy_from_user(&vr, arg, sizeof(vr)))
+                       return -EFAULT;
+               if (vr.vifi >= mrt->maxvif)
+                       return -EINVAL;
+               read_lock(&mrt_lock);
+               vif = &mrt->vif_table[vr.vifi];
+               if (VIF_EXISTS(mrt, vr.vifi)) {
+                       vr.icount = vif->pkt_in;
+                       vr.ocount = vif->pkt_out;
+                       vr.ibytes = vif->bytes_in;
+                       vr.obytes = vif->bytes_out;
+                       read_unlock(&mrt_lock);
+
+                       if (copy_to_user(arg, &vr, sizeof(vr)))
+                               return -EFAULT;
+                       return 0;
+               }
+               read_unlock(&mrt_lock);
+               return -EADDRNOTAVAIL;
+       case SIOCGETSGCNT:
+               if (copy_from_user(&sr, arg, sizeof(sr)))
+                       return -EFAULT;
+
+               rcu_read_lock();
+               c = ipmr_cache_find(mrt, sr.src.s_addr, sr.grp.s_addr);
+               if (c) {
+                       sr.pktcnt = c->mfc_un.res.pkt;
+                       sr.bytecnt = c->mfc_un.res.bytes;
+                       sr.wrong_if = c->mfc_un.res.wrong_if;
+                       rcu_read_unlock();
+
+                       if (copy_to_user(arg, &sr, sizeof(sr)))
+                               return -EFAULT;
+                       return 0;
+               }
+               rcu_read_unlock();
+               return -EADDRNOTAVAIL;
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+#endif
+
 
 static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
index b8ddcc4..a5e52a9 100644 (file)
@@ -60,12 +60,12 @@ static int checkentry(const struct xt_tgchk_param *par)
 
        if (mangle->flags & ~ARPT_MANGLE_MASK ||
            !(mangle->flags & ARPT_MANGLE_MASK))
-               return false;
+               return -EINVAL;
 
        if (mangle->target != NF_DROP && mangle->target != NF_ACCEPT &&
           mangle->target != XT_CONTINUE)
-               return false;
-       return true;
+               return -EINVAL;
+       return 0;
 }
 
 static struct xt_target arpt_mangle_reg __read_mostly = {
index a3d5ab7..6390ba2 100644 (file)
@@ -76,6 +76,7 @@
 #include <linux/seq_file.h>
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv4.h>
+#include <linux/compat.h>
 
 static struct raw_hashinfo raw_v4_hashinfo = {
        .lock = __RW_LOCK_UNLOCKED(raw_v4_hashinfo.lock),
@@ -838,6 +839,23 @@ static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg)
        }
 }
 
+#ifdef CONFIG_COMPAT
+static int compat_raw_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case SIOCOUTQ:
+       case SIOCINQ:
+               return -ENOIOCTLCMD;
+       default:
+#ifdef CONFIG_IP_MROUTE
+               return ipmr_compat_ioctl(sk, cmd, compat_ptr(arg));
+#else
+               return -ENOIOCTLCMD;
+#endif
+       }
+}
+#endif
+
 struct proto raw_prot = {
        .name              = "RAW",
        .owner             = THIS_MODULE,
@@ -860,6 +878,7 @@ struct proto raw_prot = {
 #ifdef CONFIG_COMPAT
        .compat_setsockopt = compat_raw_setsockopt,
        .compat_getsockopt = compat_raw_getsockopt,
+       .compat_ioctl      = compat_raw_ioctl,
 #endif
 };
 
index 351dc4e..6ed6603 100644 (file)
@@ -2707,6 +2707,11 @@ static struct dst_entry *ipv4_blackhole_dst_check(struct dst_entry *dst, u32 coo
        return NULL;
 }
 
+static unsigned int ipv4_blackhole_default_mtu(const struct dst_entry *dst)
+{
+       return 0;
+}
+
 static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
 {
 }
@@ -2716,6 +2721,8 @@ static struct dst_ops ipv4_dst_blackhole_ops = {
        .protocol               =       cpu_to_be16(ETH_P_IP),
        .destroy                =       ipv4_dst_destroy,
        .check                  =       ipv4_blackhole_dst_check,
+       .default_mtu            =       ipv4_blackhole_default_mtu,
+       .default_advmss         =       ipv4_default_advmss,
        .update_pmtu            =       ipv4_rt_blackhole_update_pmtu,
 };
 
index 2549b29..65f6c04 100644 (file)
@@ -1222,7 +1222,7 @@ static int tcp_check_dsack(struct sock *sk, struct sk_buff *ack_skb,
        }
 
        /* D-SACK for already forgotten data... Do dumb counting. */
-       if (dup_sack &&
+       if (dup_sack && tp->undo_marker && tp->undo_retrans &&
            !after(end_seq_0, prior_snd_una) &&
            after(end_seq_0, tp->undo_marker))
                tp->undo_retrans--;
@@ -1299,7 +1299,8 @@ static u8 tcp_sacktag_one(struct sk_buff *skb, struct sock *sk,
 
        /* Account D-SACK for retransmitted packet. */
        if (dup_sack && (sacked & TCPCB_RETRANS)) {
-               if (after(TCP_SKB_CB(skb)->end_seq, tp->undo_marker))
+               if (tp->undo_marker && tp->undo_retrans &&
+                   after(TCP_SKB_CB(skb)->end_seq, tp->undo_marker))
                        tp->undo_retrans--;
                if (sacked & TCPCB_SACKED_ACKED)
                        state->reord = min(fack_count, state->reord);
@@ -4399,7 +4400,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
                        if (!skb_copy_datagram_iovec(skb, 0, tp->ucopy.iov, chunk)) {
                                tp->ucopy.len -= chunk;
                                tp->copied_seq += chunk;
-                               eaten = (chunk == skb->len && !th->fin);
+                               eaten = (chunk == skb->len);
                                tcp_rcv_space_adjust(sk);
                        }
                        local_bh_disable();
index 856f684..02f583b 100644 (file)
@@ -1994,7 +1994,6 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
                                }
                                req = req->dl_next;
                        }
-                       st->offset = 0;
                        if (++st->sbucket >= icsk->icsk_accept_queue.listen_opt->nr_table_entries)
                                break;
 get_req:
index 406f320..dfa5beb 100644 (file)
@@ -2162,7 +2162,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
                if (!tp->retrans_stamp)
                        tp->retrans_stamp = TCP_SKB_CB(skb)->when;
 
-               tp->undo_retrans++;
+               tp->undo_retrans += tcp_skb_pcount(skb);
 
                /* snd_nxt is stored to detect loss of retransmitted segment,
                 * see tcp_input.c tcp_sacktag_write_queue().
index 24a1cf1..fd6782e 100644 (file)
@@ -2661,14 +2661,12 @@ static int addrconf_ifdown(struct net_device *dev, int how)
        struct net *net = dev_net(dev);
        struct inet6_dev *idev;
        struct inet6_ifaddr *ifa;
-       LIST_HEAD(keep_list);
-       int state;
+       int state, i;
 
        ASSERT_RTNL();
 
-       /* Flush routes if device is being removed or it is not loopback */
-       if (how || !(dev->flags & IFF_LOOPBACK))
-               rt6_ifdown(net, dev);
+       rt6_ifdown(net, dev);
+       neigh_ifdown(&nd_tbl, dev);
 
        idev = __in6_dev_get(dev);
        if (idev == NULL)
@@ -2689,6 +2687,23 @@ static int addrconf_ifdown(struct net_device *dev, int how)
 
        }
 
+       /* Step 2: clear hash table */
+       for (i = 0; i < IN6_ADDR_HSIZE; i++) {
+               struct hlist_head *h = &inet6_addr_lst[i];
+               struct hlist_node *n;
+
+               spin_lock_bh(&addrconf_hash_lock);
+       restart:
+               hlist_for_each_entry_rcu(ifa, n, h, addr_lst) {
+                       if (ifa->idev == idev) {
+                               hlist_del_init_rcu(&ifa->addr_lst);
+                               addrconf_del_timer(ifa);
+                               goto restart;
+                       }
+               }
+               spin_unlock_bh(&addrconf_hash_lock);
+       }
+
        write_lock_bh(&idev->lock);
 
        /* Step 2: clear flags for stateless addrconf */
@@ -2722,52 +2737,23 @@ static int addrconf_ifdown(struct net_device *dev, int how)
                                       struct inet6_ifaddr, if_list);
                addrconf_del_timer(ifa);
 
-               /* If just doing link down, and address is permanent
-                  and not link-local, then retain it. */
-               if (!how &&
-                   (ifa->flags&IFA_F_PERMANENT) &&
-                   !(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
-                       list_move_tail(&ifa->if_list, &keep_list);
-
-                       /* If not doing DAD on this address, just keep it. */
-                       if ((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) ||
-                           idev->cnf.accept_dad <= 0 ||
-                           (ifa->flags & IFA_F_NODAD))
-                               continue;
+               list_del(&ifa->if_list);
 
-                       /* If it was tentative already, no need to notify */
-                       if (ifa->flags & IFA_F_TENTATIVE)
-                               continue;
+               write_unlock_bh(&idev->lock);
 
-                       /* Flag it for later restoration when link comes up */
-                       ifa->flags |= IFA_F_TENTATIVE;
-                       ifa->state = INET6_IFADDR_STATE_DAD;
-               } else {
-                       list_del(&ifa->if_list);
-
-                       /* clear hash table */
-                       spin_lock_bh(&addrconf_hash_lock);
-                       hlist_del_init_rcu(&ifa->addr_lst);
-                       spin_unlock_bh(&addrconf_hash_lock);
-
-                       write_unlock_bh(&idev->lock);
-                       spin_lock_bh(&ifa->state_lock);
-                       state = ifa->state;
-                       ifa->state = INET6_IFADDR_STATE_DEAD;
-                       spin_unlock_bh(&ifa->state_lock);
-
-                       if (state != INET6_IFADDR_STATE_DEAD) {
-                               __ipv6_ifa_notify(RTM_DELADDR, ifa);
-                               atomic_notifier_call_chain(&inet6addr_chain,
-                                                          NETDEV_DOWN, ifa);
-                       }
+               spin_lock_bh(&ifa->state_lock);
+               state = ifa->state;
+               ifa->state = INET6_IFADDR_STATE_DEAD;
+               spin_unlock_bh(&ifa->state_lock);
 
-                       in6_ifa_put(ifa);
-                       write_lock_bh(&idev->lock);
+               if (state != INET6_IFADDR_STATE_DEAD) {
+                       __ipv6_ifa_notify(RTM_DELADDR, ifa);
+                       atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
                }
-       }
+               in6_ifa_put(ifa);
 
-       list_splice(&keep_list, &idev->addr_list);
+               write_lock_bh(&idev->lock);
+       }
 
        write_unlock_bh(&idev->lock);
 
@@ -4156,8 +4142,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
                addrconf_leave_solict(ifp->idev, &ifp->addr);
                dst_hold(&ifp->rt->dst);
 
-               if (ifp->state == INET6_IFADDR_STATE_DEAD &&
-                   ip6_del_rt(ifp->rt))
+               if (ip6_del_rt(ifp->rt))
                        dst_free(&ifp->rt->dst);
                break;
        }
index 4f4483e..e528a42 100644 (file)
@@ -57,6 +57,7 @@
 MODULE_AUTHOR("Ville Nuorvala");
 MODULE_DESCRIPTION("IPv6 tunneling device");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_NETDEV("ip6tnl0");
 
 #ifdef IP6_TNL_DEBUG
 #define IP6_TNL_TRACE(x...) printk(KERN_DEBUG "%s:" x "\n", __func__)
index 9fab274..0e1d53b 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/seq_file.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/compat.h>
 #include <net/protocol.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
@@ -1804,6 +1805,80 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
        }
 }
 
+#ifdef CONFIG_COMPAT
+struct compat_sioc_sg_req6 {
+       struct sockaddr_in6 src;
+       struct sockaddr_in6 grp;
+       compat_ulong_t pktcnt;
+       compat_ulong_t bytecnt;
+       compat_ulong_t wrong_if;
+};
+
+struct compat_sioc_mif_req6 {
+       mifi_t  mifi;
+       compat_ulong_t icount;
+       compat_ulong_t ocount;
+       compat_ulong_t ibytes;
+       compat_ulong_t obytes;
+};
+
+int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
+{
+       struct compat_sioc_sg_req6 sr;
+       struct compat_sioc_mif_req6 vr;
+       struct mif_device *vif;
+       struct mfc6_cache *c;
+       struct net *net = sock_net(sk);
+       struct mr6_table *mrt;
+
+       mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
+       if (mrt == NULL)
+               return -ENOENT;
+
+       switch (cmd) {
+       case SIOCGETMIFCNT_IN6:
+               if (copy_from_user(&vr, arg, sizeof(vr)))
+                       return -EFAULT;
+               if (vr.mifi >= mrt->maxvif)
+                       return -EINVAL;
+               read_lock(&mrt_lock);
+               vif = &mrt->vif6_table[vr.mifi];
+               if (MIF_EXISTS(mrt, vr.mifi)) {
+                       vr.icount = vif->pkt_in;
+                       vr.ocount = vif->pkt_out;
+                       vr.ibytes = vif->bytes_in;
+                       vr.obytes = vif->bytes_out;
+                       read_unlock(&mrt_lock);
+
+                       if (copy_to_user(arg, &vr, sizeof(vr)))
+                               return -EFAULT;
+                       return 0;
+               }
+               read_unlock(&mrt_lock);
+               return -EADDRNOTAVAIL;
+       case SIOCGETSGCNT_IN6:
+               if (copy_from_user(&sr, arg, sizeof(sr)))
+                       return -EFAULT;
+
+               read_lock(&mrt_lock);
+               c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
+               if (c) {
+                       sr.pktcnt = c->mfc_un.res.pkt;
+                       sr.bytecnt = c->mfc_un.res.bytes;
+                       sr.wrong_if = c->mfc_un.res.wrong_if;
+                       read_unlock(&mrt_lock);
+
+                       if (copy_to_user(arg, &sr, sizeof(sr)))
+                               return -EFAULT;
+                       return 0;
+               }
+               read_unlock(&mrt_lock);
+               return -EADDRNOTAVAIL;
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+#endif
 
 static inline int ip6mr_forward2_finish(struct sk_buff *skb)
 {
index 09c8889..de33803 100644 (file)
@@ -410,7 +410,7 @@ fallback:
                if (p != NULL) {
                        sb_add(m, "%02x", *p++);
                        for (i = 1; i < len; i++)
-                               sb_add(m, ":%02x", p[i]);
+                               sb_add(m, ":%02x", *p++);
                }
                sb_add(m, " ");
 
index 86c3952..c5b0915 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv6.h>
 #include <linux/skbuff.h>
+#include <linux/compat.h>
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
 
@@ -1157,6 +1158,23 @@ static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg)
        }
 }
 
+#ifdef CONFIG_COMPAT
+static int compat_rawv6_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case SIOCOUTQ:
+       case SIOCINQ:
+               return -ENOIOCTLCMD;
+       default:
+#ifdef CONFIG_IPV6_MROUTE
+               return ip6mr_compat_ioctl(sk, cmd, compat_ptr(arg));
+#else
+               return -ENOIOCTLCMD;
+#endif
+       }
+}
+#endif
+
 static void rawv6_close(struct sock *sk, long timeout)
 {
        if (inet_sk(sk)->inet_num == IPPROTO_RAW)
@@ -1215,6 +1233,7 @@ struct proto rawv6_prot = {
 #ifdef CONFIG_COMPAT
        .compat_setsockopt = compat_rawv6_setsockopt,
        .compat_getsockopt = compat_rawv6_getsockopt,
+       .compat_ioctl      = compat_rawv6_ioctl,
 #endif
 };
 
index 373bd04..e7db701 100644 (file)
@@ -72,8 +72,6 @@
 #define RT6_TRACE(x...) do { ; } while (0)
 #endif
 
-#define CLONE_OFFLINK_ROUTE 0
-
 static struct rt6_info * ip6_rt_copy(struct rt6_info *ort);
 static struct dst_entry        *ip6_dst_check(struct dst_entry *dst, u32 cookie);
 static unsigned int     ip6_default_advmss(const struct dst_entry *dst);
@@ -115,6 +113,11 @@ static struct dst_ops ip6_dst_ops_template = {
        .local_out              =       __ip6_local_out,
 };
 
+static unsigned int ip6_blackhole_default_mtu(const struct dst_entry *dst)
+{
+       return 0;
+}
+
 static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
 {
 }
@@ -124,6 +127,8 @@ static struct dst_ops ip6_dst_blackhole_ops = {
        .protocol               =       cpu_to_be16(ETH_P_IPV6),
        .destroy                =       ip6_dst_destroy,
        .check                  =       ip6_dst_check,
+       .default_mtu            =       ip6_blackhole_default_mtu,
+       .default_advmss         =       ip6_default_advmss,
        .update_pmtu            =       ip6_rt_blackhole_update_pmtu,
 };
 
@@ -196,7 +201,6 @@ static void ip6_dst_destroy(struct dst_entry *dst)
                in6_dev_put(idev);
        }
        if (peer) {
-               BUG_ON(!(rt->rt6i_flags & RTF_CACHE));
                rt->rt6i_peer = NULL;
                inet_putpeer(peer);
        }
@@ -206,9 +210,6 @@ void rt6_bind_peer(struct rt6_info *rt, int create)
 {
        struct inet_peer *peer;
 
-       if (WARN_ON(!(rt->rt6i_flags & RTF_CACHE)))
-               return;
-
        peer = inet_getpeer_v6(&rt->rt6i_dst.addr, create);
        if (peer && cmpxchg(&rt->rt6i_peer, NULL, peer) != NULL)
                inet_putpeer(peer);
@@ -738,13 +739,10 @@ restart:
 
        if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
                nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src);
-       else {
-#if CLONE_OFFLINK_ROUTE
+       else if (!(rt->dst.flags & DST_HOST))
                nrt = rt6_alloc_clone(rt, &fl->fl6_dst);
-#else
+       else
                goto out2;
-#endif
-       }
 
        dst_release(&rt->dst);
        rt = nrt ? : net->ipv6.ip6_null_entry;
@@ -2561,14 +2559,16 @@ static
 int ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write,
                              void __user *buffer, size_t *lenp, loff_t *ppos)
 {
-       struct net *net = current->nsproxy->net_ns;
-       int delay = net->ipv6.sysctl.flush_delay;
-       if (write) {
-               proc_dointvec(ctl, write, buffer, lenp, ppos);
-               fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net);
-               return 0;
-       } else
+       struct net *net;
+       int delay;
+       if (!write)
                return -EINVAL;
+
+       net = (struct net *)ctl->extra1;
+       delay = net->ipv6.sysctl.flush_delay;
+       proc_dointvec(ctl, write, buffer, lenp, ppos);
+       fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net);
+       return 0;
 }
 
 ctl_table ipv6_route_table_template[] = {
@@ -2655,6 +2655,7 @@ struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
 
        if (table) {
                table[0].data = &net->ipv6.sysctl.flush_delay;
+               table[0].extra1 = net;
                table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
                table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
                table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
index 8ce38f1..d2c16e1 100644 (file)
@@ -1290,4 +1290,4 @@ static int __init sit_init(void)
 module_init(sit_init);
 module_exit(sit_cleanup);
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("sit0");
+MODULE_ALIAS_NETDEV("sit0");
index fa1d8f4..7cb65ef 100644 (file)
@@ -15,6 +15,8 @@
 #include <net/addrconf.h>
 #include <net/inet_frag.h>
 
+static struct ctl_table empty[1];
+
 static ctl_table ipv6_table_template[] = {
        {
                .procname       = "route",
@@ -35,6 +37,12 @@ static ctl_table ipv6_table_template[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
+       {
+               .procname       = "neigh",
+               .maxlen         = 0,
+               .mode           = 0555,
+               .child          = empty,
+       },
        { }
 };
 
@@ -152,7 +160,6 @@ static struct ctl_table_header *ip6_base;
 
 int ipv6_static_sysctl_register(void)
 {
-       static struct ctl_table empty[1];
        ip6_base = register_sysctl_paths(net_ipv6_ctl_path, empty);
        if (ip6_base == NULL)
                return -ENOMEM;
index 7e74023..da87428 100644 (file)
@@ -98,6 +98,10 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
        if (!xdst->u.rt6.rt6i_idev)
                return -ENODEV;
 
+       xdst->u.rt6.rt6i_peer = rt->rt6i_peer;
+       if (rt->rt6i_peer)
+               atomic_inc(&rt->rt6i_peer->refcnt);
+
        /* Sheit... I remember I did this right. Apparently,
         * it was magically lost, so this code needs audit */
        xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST |
@@ -216,6 +220,8 @@ static void xfrm6_dst_destroy(struct dst_entry *dst)
 
        if (likely(xdst->u.rt6.rt6i_idev))
                in6_dev_put(xdst->u.rt6.rt6i_idev);
+       if (likely(xdst->u.rt6.rt6i_peer))
+               inet_putpeer(xdst->u.rt6.rt6i_peer);
        xfrm_dst_destroy(xdst);
 }
 
index 4bc8a92..9cd73b1 100644 (file)
@@ -1822,6 +1822,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
                *cookie ^= 2;
                IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
                local->hw_roc_skb = skb;
+               local->hw_roc_skb_for_status = skb;
                mutex_unlock(&local->mtx);
 
                return 0;
@@ -1875,6 +1876,7 @@ static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
                if (ret == 0) {
                        kfree_skb(local->hw_roc_skb);
                        local->hw_roc_skb = NULL;
+                       local->hw_roc_skb_for_status = NULL;
                }
 
                mutex_unlock(&local->mtx);
index c47d7c0..533fd32 100644 (file)
@@ -953,7 +953,7 @@ struct ieee80211_local {
 
        struct ieee80211_channel *hw_roc_channel;
        struct net_device *hw_roc_dev;
-       struct sk_buff *hw_roc_skb;
+       struct sk_buff *hw_roc_skb, *hw_roc_skb_for_status;
        struct work_struct hw_roc_start, hw_roc_done;
        enum nl80211_channel_type hw_roc_channel_type;
        unsigned int hw_roc_duration;
index 8acba45..7a10a8d 100644 (file)
@@ -1229,6 +1229,7 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
        }
        mutex_unlock(&local->iflist_mtx);
        unregister_netdevice_many(&unreg_list);
+       list_del(&unreg_list);
 }
 
 static u32 ieee80211_idle_off(struct ieee80211_local *local,
index 45fbb9e..c9ceb4d 100644 (file)
@@ -1033,6 +1033,12 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
        if (is_multicast_ether_addr(hdr->addr1))
                return;
 
+       /*
+        * In case we receive frames after disassociation.
+        */
+       if (!sdata->u.mgd.associated)
+               return;
+
        ieee80211_sta_reset_conn_monitor(sdata);
 }
 
index 38a7972..071ac95 100644 (file)
@@ -323,6 +323,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
                struct ieee80211_work *wk;
+               u64 cookie = (unsigned long)skb;
 
                rcu_read_lock();
                list_for_each_entry_rcu(wk, &local->work_list, list) {
@@ -334,8 +335,12 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                        break;
                }
                rcu_read_unlock();
+               if (local->hw_roc_skb_for_status == skb) {
+                       cookie = local->hw_roc_cookie ^ 2;
+                       local->hw_roc_skb_for_status = NULL;
+               }
                cfg80211_mgmt_tx_status(
-                       skb->dev, (unsigned long) skb, skb->data, skb->len,
+                       skb->dev, cookie, skb->data, skb->len,
                        !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC);
        }
 
index 5950e3a..b0beaa5 100644 (file)
@@ -1547,7 +1547,7 @@ static int ieee80211_skb_resize(struct ieee80211_local *local,
                skb_orphan(skb);
        }
 
-       if (skb_header_cloned(skb))
+       if (skb_cloned(skb))
                I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
        else if (head_need || tail_need)
                I802_DEBUG_INC(local->tx_expand_skb_head);
@@ -2230,6 +2230,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
 
        sdata = vif_to_sdata(vif);
 
+       if (!ieee80211_sdata_running(sdata))
+               goto out;
+
        if (tim_offset)
                *tim_offset = 0;
        if (tim_length)
index cf68700..d036597 100644 (file)
@@ -1210,7 +1210,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                switch (sdata->vif.type) {
                case NL80211_IFTYPE_STATION:
                        changed |= BSS_CHANGED_ASSOC;
+                       mutex_lock(&sdata->u.mgd.mtx);
                        ieee80211_bss_info_change_notify(sdata, changed);
+                       mutex_unlock(&sdata->u.mgd.mtx);
                        break;
                case NL80211_IFTYPE_ADHOC:
                        changed |= BSS_CHANGED_IBSS;
index 32fcbe2..4aa614b 100644 (file)
@@ -133,6 +133,7 @@ unsigned int nf_iterate(struct list_head *head,
 
                /* Optimization: we don't need to hold module
                   reference here, since function can't sleep. --RR */
+repeat:
                verdict = elem->hook(hook, skb, indev, outdev, okfn);
                if (verdict != NF_ACCEPT) {
 #ifdef CONFIG_NETFILTER_DEBUG
@@ -145,7 +146,7 @@ unsigned int nf_iterate(struct list_head *head,
 #endif
                        if (verdict != NF_REPEAT)
                                return verdict;
-                       *i = (*i)->prev;
+                       goto repeat;
                }
        }
        return NF_ACCEPT;
index 22f7ad5..ba98e13 100644 (file)
@@ -808,9 +808,9 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
        dest->u_threshold = udest->u_threshold;
        dest->l_threshold = udest->l_threshold;
 
-       spin_lock(&dest->dst_lock);
+       spin_lock_bh(&dest->dst_lock);
        ip_vs_dst_reset(dest);
-       spin_unlock(&dest->dst_lock);
+       spin_unlock_bh(&dest->dst_lock);
 
        if (add)
                ip_vs_new_estimator(&dest->stats);
index e615119..84f4fcc 100644 (file)
@@ -942,8 +942,15 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
        if (set_reply && !test_and_set_bit(IPS_SEEN_REPLY_BIT, &ct->status))
                nf_conntrack_event_cache(IPCT_REPLY, ct);
 out:
-       if (tmpl)
-               nf_ct_put(tmpl);
+       if (tmpl) {
+               /* Special case: we have to repeat this hook, assign the
+                * template again to this packet. We assume that this packet
+                * has no conntrack assigned. This is used by nf_ct_tcp. */
+               if (ret == NF_REPEAT)
+                       skb->nfct = (struct nf_conntrack *)tmpl;
+               else
+                       nf_ct_put(tmpl);
+       }
 
        return ret;
 }
index 5702de3..63a1b91 100644 (file)
@@ -63,6 +63,9 @@ void nf_ct_deliver_cached_events(struct nf_conn *ct)
                 * this does not harm and it happens very rarely. */
                unsigned long missed = e->missed;
 
+               if (!((events | missed) & e->ctmask))
+                       goto out_unlock;
+
                ret = notify->fcn(events | missed, &item);
                if (unlikely(ret < 0 || missed)) {
                        spin_lock_bh(&ct->lock);
index 93297aa..eead9db 100644 (file)
@@ -667,6 +667,7 @@ restart:
                        if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
                                                cb->nlh->nlmsg_seq,
                                                IPCTNL_MSG_CT_NEW, ct) < 0) {
+                               nf_conntrack_get(&ct->ct_general);
                                cb->args[1] = (unsigned long)ct;
                                goto out;
                        }
index b07393e..9181699 100644 (file)
@@ -85,6 +85,8 @@ EXPORT_SYMBOL(nf_log_unregister);
 
 int nf_log_bind_pf(u_int8_t pf, const struct nf_logger *logger)
 {
+       if (pf >= ARRAY_SIZE(nf_loggers))
+               return -EINVAL;
        mutex_lock(&nf_log_mutex);
        if (__find_logger(pf, logger->name) == NULL) {
                mutex_unlock(&nf_log_mutex);
@@ -98,6 +100,8 @@ EXPORT_SYMBOL(nf_log_bind_pf);
 
 void nf_log_unbind_pf(u_int8_t pf)
 {
+       if (pf >= ARRAY_SIZE(nf_loggers))
+               return;
        mutex_lock(&nf_log_mutex);
        rcu_assign_pointer(nf_loggers[pf], NULL);
        mutex_unlock(&nf_log_mutex);
index 4d87bef..474d621 100644 (file)
@@ -28,26 +28,23 @@ nf_tproxy_destructor(struct sk_buff *skb)
        skb->destructor = NULL;
 
        if (sk)
-               nf_tproxy_put_sock(sk);
+               sock_put(sk);
 }
 
 /* consumes sk */
-int
+void
 nf_tproxy_assign_sock(struct sk_buff *skb, struct sock *sk)
 {
-       bool transparent = (sk->sk_state == TCP_TIME_WAIT) ?
-                               inet_twsk(sk)->tw_transparent :
-                               inet_sk(sk)->transparent;
-
-       if (transparent) {
-               skb_orphan(skb);
-               skb->sk = sk;
-               skb->destructor = nf_tproxy_destructor;
-               return 1;
-       } else
-               nf_tproxy_put_sock(sk);
-
-       return 0;
+       /* assigning tw sockets complicates things; most
+        * skb->sk->X checks would have to test sk->sk_state first */
+       if (sk->sk_state == TCP_TIME_WAIT) {
+               inet_twsk_put(inet_twsk(sk));
+               return;
+       }
+
+       skb_orphan(skb);
+       skb->sk = sk;
+       skb->destructor = nf_tproxy_destructor;
 }
 EXPORT_SYMBOL_GPL(nf_tproxy_assign_sock);
 
index 640678f..dcfd57e 100644 (file)
 #include <net/netfilter/nf_tproxy_core.h>
 #include <linux/netfilter/xt_TPROXY.h>
 
+static bool tproxy_sk_is_transparent(struct sock *sk)
+{
+       if (sk->sk_state != TCP_TIME_WAIT) {
+               if (inet_sk(sk)->transparent)
+                       return true;
+               sock_put(sk);
+       } else {
+               if (inet_twsk(sk)->tw_transparent)
+                       return true;
+               inet_twsk_put(inet_twsk(sk));
+       }
+       return false;
+}
+
 static inline __be32
 tproxy_laddr4(struct sk_buff *skb, __be32 user_laddr, __be32 daddr)
 {
@@ -141,7 +155,7 @@ tproxy_tg4(struct sk_buff *skb, __be32 laddr, __be16 lport,
                                           skb->dev, NFT_LOOKUP_LISTENER);
 
        /* NOTE: assign_sock consumes our sk reference */
-       if (sk && nf_tproxy_assign_sock(skb, sk)) {
+       if (sk && tproxy_sk_is_transparent(sk)) {
                /* This should be in a separate target, but we don't do multiple
                   targets on the same rule yet */
                skb->mark = (skb->mark & ~mark_mask) ^ mark_value;
@@ -149,6 +163,8 @@ tproxy_tg4(struct sk_buff *skb, __be32 laddr, __be16 lport,
                pr_debug("redirecting: proto %hhu %pI4:%hu -> %pI4:%hu, mark: %x\n",
                         iph->protocol, &iph->daddr, ntohs(hp->dest),
                         &laddr, ntohs(lport), skb->mark);
+
+               nf_tproxy_assign_sock(skb, sk);
                return NF_ACCEPT;
        }
 
@@ -306,7 +322,7 @@ tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par)
                                           par->in, NFT_LOOKUP_LISTENER);
 
        /* NOTE: assign_sock consumes our sk reference */
-       if (sk && nf_tproxy_assign_sock(skb, sk)) {
+       if (sk && tproxy_sk_is_transparent(sk)) {
                /* This should be in a separate target, but we don't do multiple
                   targets on the same rule yet */
                skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value;
@@ -314,6 +330,8 @@ tproxy_tg6_v1(struct sk_buff *skb, const struct xt_action_param *par)
                pr_debug("redirecting: proto %hhu %pI6:%hu -> %pI6:%hu, mark: %x\n",
                         tproto, &iph->saddr, ntohs(hp->source),
                         laddr, ntohs(lport), skb->mark);
+
+               nf_tproxy_assign_sock(skb, sk);
                return NF_ACCEPT;
        }
 
index 88f7c35..73c33a4 100644 (file)
@@ -53,15 +53,13 @@ iprange_mt4(const struct sk_buff *skb, struct xt_action_param *par)
 }
 
 static inline int
-iprange_ipv6_sub(const struct in6_addr *a, const struct in6_addr *b)
+iprange_ipv6_lt(const struct in6_addr *a, const struct in6_addr *b)
 {
        unsigned int i;
-       int r;
 
        for (i = 0; i < 4; ++i) {
-               r = ntohl(a->s6_addr32[i]) - ntohl(b->s6_addr32[i]);
-               if (r != 0)
-                       return r;
+               if (a->s6_addr32[i] != b->s6_addr32[i])
+                       return ntohl(a->s6_addr32[i]) < ntohl(b->s6_addr32[i]);
        }
 
        return 0;
@@ -75,15 +73,15 @@ iprange_mt6(const struct sk_buff *skb, struct xt_action_param *par)
        bool m;
 
        if (info->flags & IPRANGE_SRC) {
-               m  = iprange_ipv6_sub(&iph->saddr, &info->src_min.in6) < 0;
-               m |= iprange_ipv6_sub(&iph->saddr, &info->src_max.in6) > 0;
+               m  = iprange_ipv6_lt(&iph->saddr, &info->src_min.in6);
+               m |= iprange_ipv6_lt(&info->src_max.in6, &iph->saddr);
                m ^= !!(info->flags & IPRANGE_SRC_INV);
                if (m)
                        return false;
        }
        if (info->flags & IPRANGE_DST) {
-               m  = iprange_ipv6_sub(&iph->daddr, &info->dst_min.in6) < 0;
-               m |= iprange_ipv6_sub(&iph->daddr, &info->dst_max.in6) > 0;
+               m  = iprange_ipv6_lt(&iph->daddr, &info->dst_min.in6);
+               m |= iprange_ipv6_lt(&info->dst_max.in6, &iph->daddr);
                m ^= !!(info->flags & IPRANGE_DST_INV);
                if (m)
                        return false;
index 00d6ae8..9cc4635 100644 (file)
 #include <net/netfilter/nf_conntrack.h>
 #endif
 
+static void
+xt_socket_put_sk(struct sock *sk)
+{
+       if (sk->sk_state == TCP_TIME_WAIT)
+               inet_twsk_put(inet_twsk(sk));
+       else
+               sock_put(sk);
+}
+
 static int
 extract_icmp4_fields(const struct sk_buff *skb,
                    u8 *protocol,
@@ -164,7 +173,7 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
                                       (sk->sk_state == TCP_TIME_WAIT &&
                                        inet_twsk(sk)->tw_transparent));
 
-               nf_tproxy_put_sock(sk);
+               xt_socket_put_sk(sk);
 
                if (wildcard || !transparent)
                        sk = NULL;
@@ -298,7 +307,7 @@ socket_mt6_v1(const struct sk_buff *skb, struct xt_action_param *par)
                                       (sk->sk_state == TCP_TIME_WAIT &&
                                        inet_twsk(sk)->tw_transparent));
 
-               nf_tproxy_put_sock(sk);
+               xt_socket_put_sk(sk);
 
                if (wildcard || !transparent)
                        sk = NULL;
index 478181d..1f92459 100644 (file)
@@ -1407,7 +1407,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
        int noblock = flags&MSG_DONTWAIT;
        size_t copied;
        struct sk_buff *skb, *data_skb;
-       int err;
+       int err, ret;
 
        if (flags&MSG_OOB)
                return -EOPNOTSUPP;
@@ -1470,8 +1470,13 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
 
        skb_free_datagram(sk, skb);
 
-       if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2)
-               netlink_dump(sk);
+       if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) {
+               ret = netlink_dump(sk);
+               if (ret) {
+                       sk->sk_err = ret;
+                       sk->sk_error_report(sk);
+               }
+       }
 
        scm_recv(sock, msg, siocb->scm, flags);
 out:
@@ -1736,6 +1741,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
        struct netlink_callback *cb;
        struct sock *sk;
        struct netlink_sock *nlk;
+       int ret;
 
        cb = kzalloc(sizeof(*cb), GFP_KERNEL);
        if (cb == NULL)
@@ -1764,9 +1770,13 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
        nlk->cb = cb;
        mutex_unlock(nlk->cb_mutex);
 
-       netlink_dump(sk);
+       ret = netlink_dump(sk);
+
        sock_put(sk);
 
+       if (ret)
+               return ret;
+
        /* We successfully started a dump, by returning -EINTR we
         * signal not to send ACK even if it was requested.
         */
index 4123967..cce19f9 100644 (file)
@@ -364,7 +364,6 @@ void rds_ib_exit(void)
        rds_ib_sysctl_exit();
        rds_ib_recv_exit();
        rds_trans_unregister(&rds_ib_transport);
-       rds_ib_fmr_exit();
 }
 
 struct rds_transport rds_ib_transport = {
@@ -400,13 +399,9 @@ int rds_ib_init(void)
 
        INIT_LIST_HEAD(&rds_ib_devices);
 
-       ret = rds_ib_fmr_init();
-       if (ret)
-               goto out;
-
        ret = ib_register_client(&rds_ib_client);
        if (ret)
-               goto out_fmr_exit;
+               goto out;
 
        ret = rds_ib_sysctl_init();
        if (ret)
@@ -430,8 +425,6 @@ out_sysctl:
        rds_ib_sysctl_exit();
 out_ibreg:
        rds_ib_unregister_client();
-out_fmr_exit:
-       rds_ib_fmr_exit();
 out:
        return ret;
 }
index e34ad03..4297d92 100644 (file)
@@ -307,8 +307,6 @@ void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
 void rds_ib_sync_mr(void *trans_private, int dir);
 void rds_ib_free_mr(void *trans_private, int invalidate);
 void rds_ib_flush_mrs(void);
-int rds_ib_fmr_init(void);
-void rds_ib_fmr_exit(void);
 
 /* ib_recv.c */
 int rds_ib_recv_init(void);
index 18a833c..819c35a 100644 (file)
@@ -38,8 +38,6 @@
 #include "ib.h"
 #include "xlist.h"
 
-static struct workqueue_struct *rds_ib_fmr_wq;
-
 static DEFINE_PER_CPU(unsigned long, clean_list_grace);
 #define CLEAN_LIST_BUSY_BIT 0
 
@@ -307,7 +305,7 @@ static struct rds_ib_mr *rds_ib_alloc_fmr(struct rds_ib_device *rds_ibdev)
        int err = 0, iter = 0;
 
        if (atomic_read(&pool->dirty_count) >= pool->max_items / 10)
-               queue_delayed_work(rds_ib_fmr_wq, &pool->flush_worker, 10);
+               schedule_delayed_work(&pool->flush_worker, 10);
 
        while (1) {
                ibmr = rds_ib_reuse_fmr(pool);
@@ -696,24 +694,6 @@ out_nolock:
        return ret;
 }
 
-int rds_ib_fmr_init(void)
-{
-       rds_ib_fmr_wq = create_workqueue("rds_fmr_flushd");
-       if (!rds_ib_fmr_wq)
-               return -ENOMEM;
-       return 0;
-}
-
-/*
- * By the time this is called all the IB devices should have been torn down and
- * had their pools freed.  As each pool is freed its work struct is waited on,
- * so the pool flushing work queue should be idle by the time we get here.
- */
-void rds_ib_fmr_exit(void)
-{
-       destroy_workqueue(rds_ib_fmr_wq);
-}
-
 static void rds_ib_mr_pool_flush_worker(struct work_struct *work)
 {
        struct rds_ib_mr_pool *pool = container_of(work, struct rds_ib_mr_pool, flush_worker.work);
@@ -741,7 +721,7 @@ void rds_ib_free_mr(void *trans_private, int invalidate)
        /* If we've pinned too many pages, request a flush */
        if (atomic_read(&pool->free_pinned) >= pool->max_free_pinned ||
            atomic_read(&pool->dirty_count) >= pool->max_items / 10)
-               queue_delayed_work(rds_ib_fmr_wq, &pool->flush_worker, 10);
+               schedule_delayed_work(&pool->flush_worker, 10);
 
        if (invalidate) {
                if (likely(!in_interrupt())) {
@@ -749,8 +729,7 @@ void rds_ib_free_mr(void *trans_private, int invalidate)
                } else {
                        /* We get here if the user created a MR marked
                         * as use_once and invalidate at the same time. */
-                       queue_delayed_work(rds_ib_fmr_wq,
-                                          &pool->flush_worker, 10);
+                       schedule_delayed_work(&pool->flush_worker, 10);
                }
        }
 
index 71f373c..c47a511 100644 (file)
@@ -551,7 +551,10 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm,
        if (conn->c_loopback
            && rm->m_inc.i_hdr.h_flags & RDS_FLAG_CONG_BITMAP) {
                rds_cong_map_updated(conn->c_fcong, ~(u64) 0);
-               return sizeof(struct rds_header) + RDS_CONG_MAP_BYTES;
+               scat = &rm->data.op_sg[sg];
+               ret = sizeof(struct rds_header) + RDS_CONG_MAP_BYTES;
+               ret = min_t(int, ret, scat->length - conn->c_xmit_data_off);
+               return ret;
        }
 
        /* FIXME we may overallocate here */
index aeec1d4..bca6761 100644 (file)
@@ -61,10 +61,15 @@ static int rds_loop_xmit(struct rds_connection *conn, struct rds_message *rm,
                         unsigned int hdr_off, unsigned int sg,
                         unsigned int off)
 {
+       struct scatterlist *sgp = &rm->data.op_sg[sg];
+       int ret = sizeof(struct rds_header) +
+                       be32_to_cpu(rm->m_inc.i_hdr.h_len);
+
        /* Do not send cong updates to loopback */
        if (rm->m_inc.i_hdr.h_flags & RDS_FLAG_CONG_BITMAP) {
                rds_cong_map_updated(conn->c_fcong, ~(u64) 0);
-               return sizeof(struct rds_header) + RDS_CONG_MAP_BYTES;
+               ret = min_t(int, ret, sgp->length - conn->c_xmit_data_off);
+               goto out;
        }
 
        BUG_ON(hdr_off || sg || off);
@@ -80,8 +85,8 @@ static int rds_loop_xmit(struct rds_connection *conn, struct rds_message *rm,
                            NULL);
 
        rds_inc_put(&rm->m_inc);
-
-       return sizeof(struct rds_header) + be32_to_cpu(rm->m_inc.i_hdr.h_len);
+out:
+       return ret;
 }
 
 /*
index 8931500..1a2b063 100644 (file)
@@ -423,6 +423,7 @@ void rxrpc_fast_process_packet(struct rxrpc_call *call, struct sk_buff *skb)
                        goto protocol_error;
                }
 
+       case RXRPC_PACKET_TYPE_ACKALL:
        case RXRPC_PACKET_TYPE_ACK:
                /* ACK processing is done in process context */
                read_lock_bh(&call->state_lock);
index 5ee16f0..d763793 100644 (file)
@@ -89,11 +89,11 @@ static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr,
                return ret;
 
        plen -= sizeof(*token);
-       token = kmalloc(sizeof(*token), GFP_KERNEL);
+       token = kzalloc(sizeof(*token), GFP_KERNEL);
        if (!token)
                return -ENOMEM;
 
-       token->kad = kmalloc(plen, GFP_KERNEL);
+       token->kad = kzalloc(plen, GFP_KERNEL);
        if (!token->kad) {
                kfree(token);
                return -ENOMEM;
@@ -731,10 +731,10 @@ static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen)
                goto error;
 
        ret = -ENOMEM;
-       token = kmalloc(sizeof(*token), GFP_KERNEL);
+       token = kzalloc(sizeof(*token), GFP_KERNEL);
        if (!token)
                goto error;
-       token->kad = kmalloc(plen, GFP_KERNEL);
+       token->kad = kzalloc(plen, GFP_KERNEL);
        if (!token->kad)
                goto error_free;
 
index c80d1c2..5f63ec5 100644 (file)
@@ -390,7 +390,6 @@ cbq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        ret = qdisc_enqueue(skb, cl->q);
        if (ret == NET_XMIT_SUCCESS) {
                sch->q.qlen++;
-               qdisc_bstats_update(sch, skb);
                cbq_mark_toplevel(q, cl);
                if (!cl->next_alive)
                        cbq_activate_class(cl);
@@ -649,7 +648,6 @@ static int cbq_reshape_fail(struct sk_buff *skb, struct Qdisc *child)
                ret = qdisc_enqueue(skb, cl->q);
                if (ret == NET_XMIT_SUCCESS) {
                        sch->q.qlen++;
-                       qdisc_bstats_update(sch, skb);
                        if (!cl->next_alive)
                                cbq_activate_class(cl);
                        return 0;
@@ -971,6 +969,7 @@ cbq_dequeue(struct Qdisc *sch)
 
                skb = cbq_dequeue_1(sch);
                if (skb) {
+                       qdisc_bstats_update(sch, skb);
                        sch->q.qlen--;
                        sch->flags &= ~TCQ_F_THROTTLED;
                        return skb;
index de55e64..6b7fe4a 100644 (file)
@@ -376,7 +376,6 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        }
 
        bstats_update(&cl->bstats, skb);
-       qdisc_bstats_update(sch, skb);
 
        sch->q.qlen++;
        return err;
@@ -403,6 +402,7 @@ static struct sk_buff *drr_dequeue(struct Qdisc *sch)
                        skb = qdisc_dequeue_peeked(cl->qdisc);
                        if (cl->qdisc->q.qlen == 0)
                                list_del(&cl->alist);
+                       qdisc_bstats_update(sch, skb);
                        sch->q.qlen--;
                        return skb;
                }
index 60f4bdd..0f7bf3f 100644 (file)
@@ -260,7 +260,6 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                return err;
        }
 
-       qdisc_bstats_update(sch, skb);
        sch->q.qlen++;
 
        return NET_XMIT_SUCCESS;
@@ -283,6 +282,7 @@ static struct sk_buff *dsmark_dequeue(struct Qdisc *sch)
        if (skb == NULL)
                return NULL;
 
+       qdisc_bstats_update(sch, skb);
        sch->q.qlen--;
 
        index = skb->tc_index & (p->indices - 1);
index aa4d633..d468b47 100644 (file)
@@ -46,17 +46,14 @@ static int pfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 
 static int pfifo_tail_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 {
-       struct sk_buff *skb_head;
        struct fifo_sched_data *q = qdisc_priv(sch);
 
        if (likely(skb_queue_len(&sch->q) < q->limit))
                return qdisc_enqueue_tail(skb, sch);
 
        /* queue full, remove one skb to fulfill the limit */
-       skb_head = qdisc_dequeue_head(sch);
+       __qdisc_queue_drop_head(sch, &sch->q);
        sch->qstats.drops++;
-       kfree_skb(skb_head);
-
        qdisc_enqueue_tail(skb, sch);
 
        return NET_XMIT_CN;
index 34dc598..1bc6980 100644 (file)
@@ -839,6 +839,7 @@ void dev_deactivate(struct net_device *dev)
 
        list_add(&dev->unreg_list, &single);
        dev_deactivate_many(&single);
+       list_del(&single);
 }
 
 static void dev_init_scheduler_queue(struct net_device *dev,
index 2e45791..14a799d 100644 (file)
@@ -1600,7 +1600,6 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                set_active(cl, qdisc_pkt_len(skb));
 
        bstats_update(&cl->bstats, skb);
-       qdisc_bstats_update(sch, skb);
        sch->q.qlen++;
 
        return NET_XMIT_SUCCESS;
@@ -1666,6 +1665,7 @@ hfsc_dequeue(struct Qdisc *sch)
        }
 
        sch->flags &= ~TCQ_F_THROTTLED;
+       qdisc_bstats_update(sch, skb);
        sch->q.qlen--;
 
        return skb;
index 984c1b0..fc12fe6 100644 (file)
@@ -574,7 +574,6 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        }
 
        sch->q.qlen++;
-       qdisc_bstats_update(sch, skb);
        return NET_XMIT_SUCCESS;
 }
 
@@ -842,7 +841,7 @@ next:
 
 static struct sk_buff *htb_dequeue(struct Qdisc *sch)
 {
-       struct sk_buff *skb = NULL;
+       struct sk_buff *skb;
        struct htb_sched *q = qdisc_priv(sch);
        int level;
        psched_time_t next_event;
@@ -851,6 +850,8 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch)
        /* try to dequeue direct packets as high prio (!) to minimize cpu work */
        skb = __skb_dequeue(&q->direct_queue);
        if (skb != NULL) {
+ok:
+               qdisc_bstats_update(sch, skb);
                sch->flags &= ~TCQ_F_THROTTLED;
                sch->q.qlen--;
                return skb;
@@ -884,11 +885,8 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch)
                        int prio = ffz(m);
                        m |= 1 << prio;
                        skb = htb_dequeue_tree(q, prio, level);
-                       if (likely(skb != NULL)) {
-                               sch->q.qlen--;
-                               sch->flags &= ~TCQ_F_THROTTLED;
-                               goto fin;
-                       }
+                       if (likely(skb != NULL))
+                               goto ok;
                }
        }
        sch->qstats.overlimits++;
index 21f13da..436a2e7 100644 (file)
@@ -83,7 +83,6 @@ multiq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 
        ret = qdisc_enqueue(skb, qdisc);
        if (ret == NET_XMIT_SUCCESS) {
-               qdisc_bstats_update(sch, skb);
                sch->q.qlen++;
                return NET_XMIT_SUCCESS;
        }
@@ -112,6 +111,7 @@ static struct sk_buff *multiq_dequeue(struct Qdisc *sch)
                        qdisc = q->queues[q->curband];
                        skb = qdisc->dequeue(qdisc);
                        if (skb) {
+                               qdisc_bstats_update(sch, skb);
                                sch->q.qlen--;
                                return skb;
                        }
index 1c4bce8..6a3006b 100644 (file)
@@ -240,7 +240,6 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 
        if (likely(ret == NET_XMIT_SUCCESS)) {
                sch->q.qlen++;
-               qdisc_bstats_update(sch, skb);
        } else if (net_xmit_drop_count(ret)) {
                sch->qstats.drops++;
        }
@@ -289,6 +288,7 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
                                skb->tstamp.tv64 = 0;
 #endif
                        pr_debug("netem_dequeue: return skb=%p\n", skb);
+                       qdisc_bstats_update(sch, skb);
                        sch->q.qlen--;
                        return skb;
                }
@@ -476,7 +476,6 @@ static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
                __skb_queue_after(list, skb, nskb);
 
                sch->qstats.backlog += qdisc_pkt_len(nskb);
-               qdisc_bstats_update(sch, nskb);
 
                return NET_XMIT_SUCCESS;
        }
index 966158d..fbd710d 100644 (file)
@@ -84,7 +84,6 @@ prio_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 
        ret = qdisc_enqueue(skb, qdisc);
        if (ret == NET_XMIT_SUCCESS) {
-               qdisc_bstats_update(sch, skb);
                sch->q.qlen++;
                return NET_XMIT_SUCCESS;
        }
@@ -116,6 +115,7 @@ static struct sk_buff *prio_dequeue(struct Qdisc* sch)
                struct Qdisc *qdisc = q->queues[prio];
                struct sk_buff *skb = qdisc->dequeue(qdisc);
                if (skb) {
+                       qdisc_bstats_update(sch, skb);
                        sch->q.qlen--;
                        return skb;
                }
index a6009c5..9f98dbd 100644 (file)
@@ -94,7 +94,6 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 
        ret = qdisc_enqueue(skb, child);
        if (likely(ret == NET_XMIT_SUCCESS)) {
-               qdisc_bstats_update(sch, skb);
                sch->q.qlen++;
        } else if (net_xmit_drop_count(ret)) {
                q->stats.pdrop++;
@@ -114,11 +113,13 @@ static struct sk_buff * red_dequeue(struct Qdisc* sch)
        struct Qdisc *child = q->qdisc;
 
        skb = child->dequeue(child);
-       if (skb)
+       if (skb) {
+               qdisc_bstats_update(sch, skb);
                sch->q.qlen--;
-       else if (!red_is_idling(&q->parms))
-               red_start_of_idle_period(&q->parms);
-
+       } else {
+               if (!red_is_idling(&q->parms))
+                       red_start_of_idle_period(&q->parms);
+       }
        return skb;
 }
 
index 239ec53..edea8ce 100644 (file)
@@ -402,10 +402,8 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                q->tail = slot;
                slot->allot = q->scaled_quantum;
        }
-       if (++sch->q.qlen <= q->limit) {
-               qdisc_bstats_update(sch, skb);
+       if (++sch->q.qlen <= q->limit)
                return NET_XMIT_SUCCESS;
-       }
 
        sfq_drop(sch);
        return NET_XMIT_CN;
@@ -445,6 +443,7 @@ next_slot:
        }
        skb = slot_dequeue_head(slot);
        sfq_dec(q, a);
+       qdisc_bstats_update(sch, skb);
        sch->q.qlen--;
        sch->qstats.backlog -= qdisc_pkt_len(skb);
 
index 77565e7..e931658 100644 (file)
@@ -134,7 +134,6 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch)
        }
 
        sch->q.qlen++;
-       qdisc_bstats_update(sch, skb);
        return NET_XMIT_SUCCESS;
 }
 
@@ -187,6 +186,7 @@ static struct sk_buff *tbf_dequeue(struct Qdisc* sch)
                        q->ptokens = ptoks;
                        sch->q.qlen--;
                        sch->flags &= ~TCQ_F_THROTTLED;
+                       qdisc_bstats_update(sch, skb);
                        return skb;
                }
 
index 84ce48e..d84e732 100644 (file)
@@ -87,7 +87,6 @@ teql_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 
        if (q->q.qlen < dev->tx_queue_len) {
                __skb_queue_tail(&q->q, skb);
-               qdisc_bstats_update(sch, skb);
                return NET_XMIT_SUCCESS;
        }
 
@@ -111,6 +110,8 @@ teql_dequeue(struct Qdisc* sch)
                        dat->m->slaves = sch;
                        netif_wake_queue(m);
                }
+       } else {
+               qdisc_bstats_update(sch, skb);
        }
        sch->q.qlen = dat->q.qlen + dat_queue->qdisc->q.qlen;
        return skb;
index 2cc46f0..b23428f 100644 (file)
@@ -2029,11 +2029,11 @@ static sctp_ierror_t sctp_process_unk_param(const struct sctp_association *asoc,
                        *errp = sctp_make_op_error_fixed(asoc, chunk);
 
                if (*errp) {
-                       sctp_init_cause_fixed(*errp, SCTP_ERROR_UNKNOWN_PARAM,
-                                       WORD_ROUND(ntohs(param.p->length)));
-                       sctp_addto_chunk_fixed(*errp,
-                                       WORD_ROUND(ntohs(param.p->length)),
-                                       param.v);
+                       if (!sctp_init_cause_fixed(*errp, SCTP_ERROR_UNKNOWN_PARAM,
+                                       WORD_ROUND(ntohs(param.p->length))))
+                               sctp_addto_chunk_fixed(*errp,
+                                               WORD_ROUND(ntohs(param.p->length)),
+                                               param.v);
                } else {
                        /* If there is no memory for generating the ERROR
                         * report as specified, an ABORT will be triggered
index 243fc09..3fc8624 100644 (file)
@@ -252,23 +252,37 @@ static void rpc_set_active(struct rpc_task *task)
 
 /*
  * Mark an RPC call as having completed by clearing the 'active' bit
+ * and then waking up all tasks that were sleeping.
  */
-static void rpc_mark_complete_task(struct rpc_task *task)
+static int rpc_complete_task(struct rpc_task *task)
 {
-       smp_mb__before_clear_bit();
+       void *m = &task->tk_runstate;
+       wait_queue_head_t *wq = bit_waitqueue(m, RPC_TASK_ACTIVE);
+       struct wait_bit_key k = __WAIT_BIT_KEY_INITIALIZER(m, RPC_TASK_ACTIVE);
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&wq->lock, flags);
        clear_bit(RPC_TASK_ACTIVE, &task->tk_runstate);
-       smp_mb__after_clear_bit();
-       wake_up_bit(&task->tk_runstate, RPC_TASK_ACTIVE);
+       ret = atomic_dec_and_test(&task->tk_count);
+       if (waitqueue_active(wq))
+               __wake_up_locked_key(wq, TASK_NORMAL, &k);
+       spin_unlock_irqrestore(&wq->lock, flags);
+       return ret;
 }
 
 /*
  * Allow callers to wait for completion of an RPC call
+ *
+ * Note the use of out_of_line_wait_on_bit() rather than wait_on_bit()
+ * to enforce taking of the wq->lock and hence avoid races with
+ * rpc_complete_task().
  */
 int __rpc_wait_for_completion_task(struct rpc_task *task, int (*action)(void *))
 {
        if (action == NULL)
                action = rpc_wait_bit_killable;
-       return wait_on_bit(&task->tk_runstate, RPC_TASK_ACTIVE,
+       return out_of_line_wait_on_bit(&task->tk_runstate, RPC_TASK_ACTIVE,
                        action, TASK_KILLABLE);
 }
 EXPORT_SYMBOL_GPL(__rpc_wait_for_completion_task);
@@ -857,34 +871,67 @@ static void rpc_async_release(struct work_struct *work)
        rpc_free_task(container_of(work, struct rpc_task, u.tk_work));
 }
 
-void rpc_put_task(struct rpc_task *task)
+static void rpc_release_resources_task(struct rpc_task *task)
 {
-       if (!atomic_dec_and_test(&task->tk_count))
-               return;
-       /* Release resources */
        if (task->tk_rqstp)
                xprt_release(task);
        if (task->tk_msg.rpc_cred)
                put_rpccred(task->tk_msg.rpc_cred);
        rpc_task_release_client(task);
-       if (task->tk_workqueue != NULL) {
+}
+
+static void rpc_final_put_task(struct rpc_task *task,
+               struct workqueue_struct *q)
+{
+       if (q != NULL) {
                INIT_WORK(&task->u.tk_work, rpc_async_release);
-               queue_work(task->tk_workqueue, &task->u.tk_work);
+               queue_work(q, &task->u.tk_work);
        } else
                rpc_free_task(task);
 }
+
+static void rpc_do_put_task(struct rpc_task *task, struct workqueue_struct *q)
+{
+       if (atomic_dec_and_test(&task->tk_count)) {
+               rpc_release_resources_task(task);
+               rpc_final_put_task(task, q);
+       }
+}
+
+void rpc_put_task(struct rpc_task *task)
+{
+       rpc_do_put_task(task, NULL);
+}
 EXPORT_SYMBOL_GPL(rpc_put_task);
 
+void rpc_put_task_async(struct rpc_task *task)
+{
+       rpc_do_put_task(task, task->tk_workqueue);
+}
+EXPORT_SYMBOL_GPL(rpc_put_task_async);
+
 static void rpc_release_task(struct rpc_task *task)
 {
        dprintk("RPC: %5u release task\n", task->tk_pid);
 
        BUG_ON (RPC_IS_QUEUED(task));
 
-       /* Wake up anyone who is waiting for task completion */
-       rpc_mark_complete_task(task);
+       rpc_release_resources_task(task);
 
-       rpc_put_task(task);
+       /*
+        * Note: at this point we have been removed from rpc_clnt->cl_tasks,
+        * so it should be safe to use task->tk_count as a test for whether
+        * or not any other processes still hold references to our rpc_task.
+        */
+       if (atomic_read(&task->tk_count) != 1 + !RPC_IS_ASYNC(task)) {
+               /* Wake up anyone who may be waiting for task completion */
+               if (!rpc_complete_task(task))
+                       return;
+       } else {
+               if (!atomic_dec_and_test(&task->tk_count))
+                       return;
+       }
+       rpc_final_put_task(task, task->tk_workqueue);
 }
 
 int rpciod_up(void)
@@ -908,7 +955,7 @@ static int rpciod_start(void)
         * Create the rpciod thread and wait for it to start.
         */
        dprintk("RPC:       creating workqueue rpciod\n");
-       wq = alloc_workqueue("rpciod", WQ_RESCUER, 0);
+       wq = alloc_workqueue("rpciod", WQ_MEM_RECLAIM, 0);
        rpciod_workqueue = wq;
        return rpciod_workqueue != NULL;
 }
index 7bd3bbb..d802e94 100644 (file)
@@ -1609,9 +1609,7 @@ static struct svc_xprt *svc_bc_create_socket(struct svc_serv *serv,
  */
 static void svc_bc_sock_free(struct svc_xprt *xprt)
 {
-       if (xprt) {
-               kfree(xprt->xpt_bc_sid);
+       if (xprt)
                kfree(container_of(xprt, struct svc_sock, sk_xprt));
-       }
 }
 #endif /* CONFIG_NFS_V4_1 */
index 9df1ead..1a10dcd 100644 (file)
@@ -1335,6 +1335,7 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
                                            p, 0, length, DMA_FROM_DEVICE);
        if (ib_dma_mapping_error(xprt->sc_cm_id->device, ctxt->sge[0].addr)) {
                put_page(p);
+               svc_rdma_put_context(ctxt, 1);
                return;
        }
        atomic_inc(&xprt->sc_dma_used);
index c431f5a..be96d42 100644 (file)
@@ -1631,7 +1631,8 @@ static struct socket *xs_create_sock(struct rpc_xprt *xprt,
        }
        xs_reclassify_socket(family, sock);
 
-       if (xs_bind(transport, sock)) {
+       err = xs_bind(transport, sock);
+       if (err) {
                sock_release(sock);
                goto out;
        }
index dd419d2..ba5b8c2 100644 (file)
@@ -850,7 +850,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                 * Get the parent directory, calculate the hash for last
                 * component.
                 */
-               err = path_lookup(sunaddr->sun_path, LOOKUP_PARENT, &nd);
+               err = kern_path_parent(sunaddr->sun_path, &nd);
                if (err)
                        goto out_mknod_parent;
 
@@ -1724,7 +1724,11 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
 
        msg->msg_namelen = 0;
 
-       mutex_lock(&u->readlock);
+       err = mutex_lock_interruptible(&u->readlock);
+       if (err) {
+               err = sock_intr_errno(sock_rcvtimeo(sk, noblock));
+               goto out;
+       }
 
        skb = skb_recv_datagram(sk, flags, noblock, &err);
        if (!skb) {
@@ -1864,7 +1868,11 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
                memset(&tmp_scm, 0, sizeof(tmp_scm));
        }
 
-       mutex_lock(&u->readlock);
+       err = mutex_lock_interruptible(&u->readlock);
+       if (err) {
+               err = sock_intr_errno(timeo);
+               goto out;
+       }
 
        do {
                int chunk;
@@ -1895,11 +1903,12 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
 
                        timeo = unix_stream_data_wait(sk, timeo);
 
-                       if (signal_pending(current)) {
+                       if (signal_pending(current)
+                           ||  mutex_lock_interruptible(&u->readlock)) {
                                err = sock_intr_errno(timeo);
                                goto out;
                        }
-                       mutex_lock(&u->readlock);
+
                        continue;
  unlock:
                        unix_state_unlock(sk);
index f89f83b..b6f4b99 100644 (file)
@@ -104,7 +104,7 @@ struct sock *unix_get_socket(struct file *filp)
        /*
         *      Socket ?
         */
-       if (S_ISSOCK(inode->i_mode)) {
+       if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) {
                struct socket *sock = SOCKET_I(inode);
                struct sock *s = sock->sk;
 
index 3e5dbd4..d112f03 100644 (file)
@@ -802,11 +802,11 @@ int cfg80211_wext_siwfreq(struct net_device *dev,
                        return freq;
                if (freq == 0)
                        return -EINVAL;
-               wdev_lock(wdev);
                mutex_lock(&rdev->devlist_mtx);
+               wdev_lock(wdev);
                err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
-               mutex_unlock(&rdev->devlist_mtx);
                wdev_unlock(wdev);
+               mutex_unlock(&rdev->devlist_mtx);
                return err;
        default:
                return -EOPNOTSUPP;
index 55187c8..4062075 100644 (file)
 #include <net/sock.h>
 #include <net/x25.h>
 
-/*
- * Parse a set of facilities into the facilities structures. Unrecognised
- *     facilities are written to the debug log file.
+/**
+ * x25_parse_facilities - Parse facilities from skb into the facilities structs
+ *
+ * @skb: sk_buff to parse
+ * @facilities: Regular facilites, updated as facilities are found
+ * @dte_facs: ITU DTE facilities, updated as DTE facilities are found
+ * @vc_fac_mask: mask is updated with all facilities found
+ *
+ * Return codes:
+ *  -1 - Parsing error, caller should drop call and clean up
+ *   0 - Parse OK, this skb has no facilities
+ *  >0 - Parse OK, returns the length of the facilities header
+ *
  */
 int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
                struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask)
@@ -62,7 +72,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
                switch (*p & X25_FAC_CLASS_MASK) {
                case X25_FAC_CLASS_A:
                        if (len < 2)
-                               return 0;
+                               return -1;
                        switch (*p) {
                        case X25_FAC_REVERSE:
                                if((p[1] & 0x81) == 0x81) {
@@ -107,7 +117,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
                        break;
                case X25_FAC_CLASS_B:
                        if (len < 3)
-                               return 0;
+                               return -1;
                        switch (*p) {
                        case X25_FAC_PACKET_SIZE:
                                facilities->pacsize_in  = p[1];
@@ -130,7 +140,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
                        break;
                case X25_FAC_CLASS_C:
                        if (len < 4)
-                               return 0;
+                               return -1;
                        printk(KERN_DEBUG "X.25: unknown facility %02X, "
                               "values %02X, %02X, %02X\n",
                               p[0], p[1], p[2], p[3]);
@@ -139,18 +149,18 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
                        break;
                case X25_FAC_CLASS_D:
                        if (len < p[1] + 2)
-                               return 0;
+                               return -1;
                        switch (*p) {
                        case X25_FAC_CALLING_AE:
                                if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1)
-                                       return 0;
+                                       return -1;
                                dte_facs->calling_len = p[2];
                                memcpy(dte_facs->calling_ae, &p[3], p[1] - 1);
                                *vc_fac_mask |= X25_MASK_CALLING_AE;
                                break;
                        case X25_FAC_CALLED_AE:
                                if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1)
-                                       return 0;
+                                       return -1;
                                dte_facs->called_len = p[2];
                                memcpy(dte_facs->called_ae, &p[3], p[1] - 1);
                                *vc_fac_mask |= X25_MASK_CALLED_AE;
index f729f02..15de65f 100644 (file)
@@ -91,10 +91,10 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
 {
        struct x25_address source_addr, dest_addr;
        int len;
+       struct x25_sock *x25 = x25_sk(sk);
 
        switch (frametype) {
                case X25_CALL_ACCEPTED: {
-                       struct x25_sock *x25 = x25_sk(sk);
 
                        x25_stop_timer(sk);
                        x25->condition = 0x00;
@@ -113,14 +113,16 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
                                                &dest_addr);
                        if (len > 0)
                                skb_pull(skb, len);
+                       else if (len < 0)
+                               goto out_clear;
 
                        len = x25_parse_facilities(skb, &x25->facilities,
                                                &x25->dte_facilities,
                                                &x25->vc_facil_mask);
                        if (len > 0)
                                skb_pull(skb, len);
-                       else
-                               return -1;
+                       else if (len < 0)
+                               goto out_clear;
                        /*
                         *      Copy any Call User Data.
                         */
@@ -144,6 +146,12 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
        }
 
        return 0;
+
+out_clear:
+       x25_write_internal(sk, X25_CLEAR_REQUEST);
+       x25->state = X25_STATE_2;
+       x25_start_t23timer(sk);
+       return 0;
 }
 
 /*
index 4cbc942..2130692 100644 (file)
@@ -396,9 +396,12 @@ void __exit x25_link_free(void)
        write_lock_bh(&x25_neigh_list_lock);
 
        list_for_each_safe(entry, tmp, &x25_neigh_list) {
+               struct net_device *dev;
+
                nb = list_entry(entry, struct x25_neigh, node);
+               dev = nb->dev;
                __x25_remove_neigh(nb);
-               dev_put(nb->dev);
+               dev_put(dev);
        }
        write_unlock_bh(&x25_neigh_list_lock);
 }
index 8b3ef40..6459588 100644 (file)
@@ -1340,10 +1340,13 @@ static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family)
        default:
                BUG();
        }
-       xdst = dst_alloc(dst_ops) ?: ERR_PTR(-ENOBUFS);
+       xdst = dst_alloc(dst_ops);
        xfrm_policy_put_afinfo(afinfo);
 
-       xdst->flo.ops = &xfrm_bundle_fc_ops;
+       if (likely(xdst))
+               xdst->flo.ops = &xfrm_bundle_fc_ops;
+       else
+               xdst = ERR_PTR(-ENOBUFS);
 
        return xdst;
 }
index c9a16ab..291228e 100644 (file)
@@ -309,12 +309,18 @@ static void do_config_file(const char *filename)
        close(fd);
 }
 
+/*
+ * Important: The below generated source_foo.o and deps_foo.o variable
+ * assignments are parsed not only by make, but also by the rather simple
+ * parser in scripts/mod/sumversion.c.
+ */
 static void parse_dep_file(void *map, size_t len)
 {
        char *m = map;
        char *end = m + len;
        char *p;
        char s[PATH_MAX];
+       int first;
 
        p = strchr(m, ':');
        if (!p) {
@@ -322,11 +328,11 @@ static void parse_dep_file(void *map, size_t len)
                exit(1);
        }
        memcpy(s, m, p-m); s[p-m] = 0;
-       printf("deps_%s := \\\n", target);
        m = p+1;
 
        clear_config();
 
+       first = 1;
        while (m < end) {
                while (m < end && (*m == ' ' || *m == '\\' || *m == '\n'))
                        m++;
@@ -340,9 +346,20 @@ static void parse_dep_file(void *map, size_t len)
                if (strrcmp(s, "include/generated/autoconf.h") &&
                    strrcmp(s, "arch/um/include/uml-config.h") &&
                    strrcmp(s, ".ver")) {
-                       printf("  %s \\\n", s);
+                       /*
+                        * Do not list the source file as dependency, so that
+                        * kbuild is not confused if a .c file is rewritten
+                        * into .S or vice versa. Storing it in source_* is
+                        * needed for modpost to compute srcversions.
+                        */
+                       if (first) {
+                               printf("source_%s := %s\n\n", target, s);
+                               printf("deps_%s := \\\n", target);
+                       } else
+                               printf("  %s \\\n", s);
                        do_config_file(s);
                }
+               first = 0;
                m = p + 1;
        }
        printf("\n%s: $(deps_%s)\n\n", target, target);
index 4c0383d..58848e3 100755 (executable)
@@ -2654,11 +2654,6 @@ sub process {
                        WARN("Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n" . $herecurr);
                }
 
-# SPIN_LOCK_UNLOCKED & RW_LOCK_UNLOCKED are deprecated
-               if ($line =~ /\b(SPIN_LOCK_UNLOCKED|RW_LOCK_UNLOCKED)/) {
-                       ERROR("Use of $1 is deprecated: see Documentation/spinlocks.txt\n" . $herecurr);
-               }
-
 # warn about #if 0
                if ($line =~ /^.\s*\#\s*if\s+0\b/) {
                        CHK("if this code is redundant consider removing it\n" .
index fd81fc3..a4fe923 100644 (file)
@@ -1,6 +1,6 @@
 #!/usr/bin/perl -w
 #
-# Copywrite 2005-2009 - Steven Rostedt
+# Copyright 2005-2009 - Steven Rostedt
 # Licensed under the terms of the GNU GPL License version 2
 #
 #  It's simple enough to figure out how this works.
index ecf9c7d..9dfcd6d 100644 (file)
@@ -300,8 +300,8 @@ static int is_static_library(const char *objfile)
                return 0;
 }
 
-/* We have dir/file.o.  Open dir/.file.o.cmd, look for deps_ line to
- * figure out source file. */
+/* We have dir/file.o.  Open dir/.file.o.cmd, look for source_ and deps_ line
+ * to figure out source files. */
 static int parse_source_files(const char *objfile, struct md4_ctx *md)
 {
        char *cmd, *file, *line, *dir;
@@ -340,6 +340,21 @@ static int parse_source_files(const char *objfile, struct md4_ctx *md)
        */
        while ((line = get_next_line(&pos, file, flen)) != NULL) {
                char* p = line;
+
+               if (strncmp(line, "source_", sizeof("source_")-1) == 0) {
+                       p = strrchr(line, ' ');
+                       if (!p) {
+                               warn("malformed line: %s\n", line);
+                               goto out_file;
+                       }
+                       p++;
+                       if (!parse_file(p, md)) {
+                               warn("could not open %s: %s\n",
+                                    p, strerror(errno));
+                               goto out_file;
+                       }
+                       continue;
+               }
                if (strncmp(line, "deps_", sizeof("deps_")-1) == 0) {
                        check_files = 1;
                        continue;
index b0b2357..f6cbc3d 100644 (file)
@@ -238,12 +238,12 @@ EOF
 fi
 
 # Build header package
-find . -name Makefile -o -name Kconfig\* -o -name \*.pl > /tmp/files$$
-find arch/x86/include include scripts -type f >> /tmp/files$$
+(cd $srctree; find . -name Makefile -o -name Kconfig\* -o -name \*.pl > /tmp/files$$)
+(cd $srctree; find arch/$SRCARCH/include include scripts -type f >> /tmp/files$$)
 (cd $objtree; find .config Module.symvers include scripts -type f >> /tmp/objfiles$$)
 destdir=$kernel_headers_dir/usr/src/linux-headers-$version
 mkdir -p "$destdir"
-tar -c -f - -T /tmp/files$$ | (cd $destdir; tar -xf -)
+(cd $srctree; tar -c -f - -T /tmp/files$$) | (cd $destdir; tar -xf -)
 (cd $objtree; tar -c -f - -T /tmp/objfiles$$) | (cd $destdir; tar -xf -)
 rm -f /tmp/files$$ /tmp/objfiles$$
 arch=$(dpkg --print-architecture)
index 038b3d1..f9f6f52 100644 (file)
@@ -206,7 +206,8 @@ static uint32_t (*w2)(uint16_t);
 static int
 is_mcounted_section_name(char const *const txtname)
 {
-       return 0 == strcmp(".text",          txtname) ||
+       return 0 == strcmp(".text",           txtname) ||
+               0 == strcmp(".ref.text",      txtname) ||
                0 == strcmp(".sched.text",    txtname) ||
                0 == strcmp(".spinlock.text", txtname) ||
                0 == strcmp(".irqentry.text", txtname) ||
index 1d7963f..4be0dee 100755 (executable)
@@ -130,6 +130,7 @@ if ($inputfile =~ m,kernel/trace/ftrace\.o$,) {
 # Acceptable sections to record.
 my %text_sections = (
      ".text" => 1,
+     ".ref.text" => 1,
      ".sched.text" => 1,
      ".spinlock.text" => 1,
      ".irqentry.text" => 1,
index 44423b4..8c81d76 100644 (file)
@@ -33,8 +33,6 @@ cmd_opcodes = {
     "lockintnowait" : "6",
     "lockcont"      : "7",
     "unlock"        : "8",
-    "lockbkl"       : "9",
-    "unlockbkl"     : "10",
     "signal"        : "11",
     "resetevent"    : "98",
     "reset"         : "99",
index 8821f27..3710c8b 100644 (file)
@@ -19,8 +19,6 @@
 # lockintnowait        lock nr (0-7)
 # lockcont     lock nr (0-7)
 # unlock       lock nr (0-7)
-# lockbkl      lock nr (0-7)
-# unlockbkl    lock nr (0-7)
 # signal       0
 # reset                0
 # resetevent   0
@@ -39,9 +37,6 @@
 # blocked      lock nr (0-7)
 # blockedwake  lock nr (0-7)
 # unlocked     lock nr (0-7)
-# lockedbkl    dont care
-# blockedbkl   dont care
-# unlockedbkl  dont care
 # opcodeeq     command opcode or number
 # opcodelt     number
 # opcodegt     number
index cde1f18..b4cc959 100644 (file)
@@ -19,8 +19,6 @@
 # lockintnowait        lock nr (0-7)
 # lockcont     lock nr (0-7)
 # unlock       lock nr (0-7)
-# lockbkl      lock nr (0-7)
-# unlockbkl    lock nr (0-7)
 # signal       0
 # reset                0
 # resetevent   0
@@ -39,9 +37,6 @@
 # blocked      lock nr (0-7)
 # blockedwake  lock nr (0-7)
 # unlocked     lock nr (0-7)
-# lockedbkl    dont care
-# blockedbkl   dont care
-# unlockedbkl  dont care
 # opcodeeq     command opcode or number
 # opcodelt     number
 # opcodegt     number
index 3ab0bfc..1b57376 100644 (file)
@@ -19,8 +19,6 @@
 # lockintnowait        lock nr (0-7)
 # lockcont     lock nr (0-7)
 # unlock       lock nr (0-7)
-# lockbkl      lock nr (0-7)
-# unlockbkl    lock nr (0-7)
 # signal       0
 # reset                0
 # resetevent   0
@@ -39,9 +37,6 @@
 # blocked      lock nr (0-7)
 # blockedwake  lock nr (0-7)
 # unlocked     lock nr (0-7)
-# lockedbkl    dont care
-# blockedbkl   dont care
-# unlockedbkl  dont care
 # opcodeeq     command opcode or number
 # opcodelt     number
 # opcodegt     number
index f4b5d5d..68b1062 100644 (file)
@@ -19,8 +19,6 @@
 # lockintnowait        lock nr (0-7)
 # lockcont     lock nr (0-7)
 # unlock       lock nr (0-7)
-# lockbkl      lock nr (0-7)
-# unlockbkl    lock nr (0-7)
 # signal       0
 # reset                0
 # resetevent   0
@@ -39,9 +37,6 @@
 # blocked      lock nr (0-7)
 # blockedwake  lock nr (0-7)
 # unlocked     lock nr (0-7)
-# lockedbkl    dont care
-# blockedbkl   dont care
-# unlockedbkl  dont care
 # opcodeeq     command opcode or number
 # opcodelt     number
 # opcodegt     number
index 63440ca..8e6c8b1 100644 (file)
@@ -19,8 +19,6 @@
 # lockintnowait        lock nr (0-7)
 # lockcont     lock nr (0-7)
 # unlock       lock nr (0-7)
-# lockbkl      lock nr (0-7)
-# unlockbkl    lock nr (0-7)
 # signal       thread to signal (0-7)
 # reset                0
 # resetevent   0
@@ -39,9 +37,6 @@
 # blocked      lock nr (0-7)
 # blockedwake  lock nr (0-7)
 # unlocked     lock nr (0-7)
-# lockedbkl    dont care
-# blockedbkl   dont care
-# unlockedbkl  dont care
 # opcodeeq     command opcode or number
 # opcodelt     number
 # opcodegt     number
index e5816fe..69c2212 100644 (file)
@@ -19,8 +19,6 @@
 # lockintnowait        lock nr (0-7)
 # lockcont     lock nr (0-7)
 # unlock       lock nr (0-7)
-# lockbkl      lock nr (0-7)
-# unlockbkl    lock nr (0-7)
 # signal       thread to signal (0-7)
 # reset                0
 # resetevent   0
@@ -39,9 +37,6 @@
 # blocked      lock nr (0-7)
 # blockedwake  lock nr (0-7)
 # unlocked     lock nr (0-7)
-# lockedbkl    dont care
-# blockedbkl   dont care
-# unlockedbkl  dont care
 # opcodeeq     command opcode or number
 # opcodelt     number
 # opcodegt     number
index 718b82b..9b0f1eb 100644 (file)
@@ -19,8 +19,6 @@
 # lockintnowait        lock nr (0-7)
 # lockcont     lock nr (0-7)
 # unlock       lock nr (0-7)
-# lockbkl      lock nr (0-7)
-# unlockbkl    lock nr (0-7)
 # signal       thread to signal (0-7)
 # reset                0
 # resetevent   0
@@ -39,9 +37,6 @@
 # blocked      lock nr (0-7)
 # blockedwake  lock nr (0-7)
 # unlocked     lock nr (0-7)
-# lockedbkl    dont care
-# blockedbkl   dont care
-# unlockedbkl  dont care
 # opcodeeq     command opcode or number
 # opcodelt     number
 # opcodegt     number
index c6e2135..39ec74a 100644 (file)
@@ -19,8 +19,6 @@
 # lockintnowait        lock nr (0-7)
 # lockcont     lock nr (0-7)
 # unlock       lock nr (0-7)
-# lockbkl      lock nr (0-7)
-# unlockbkl    lock nr (0-7)
 # signal       thread to signal (0-7)
 # reset                0
 # resetevent   0
@@ -39,9 +37,6 @@
 # blocked      lock nr (0-7)
 # blockedwake  lock nr (0-7)
 # unlocked     lock nr (0-7)
-# lockedbkl    dont care
-# blockedbkl   dont care
-# unlockedbkl  dont care
 # opcodeeq     command opcode or number
 # opcodelt     number
 # opcodegt     number
index f53749d..e03db7e 100644 (file)
@@ -19,8 +19,6 @@
 # lockintnowait        lock nr (0-7)
 # lockcont     lock nr (0-7)
 # unlock       lock nr (0-7)
-# lockbkl      lock nr (0-7)
-# unlockbkl    lock nr (0-7)
 # signal       thread to signal (0-7)
 # reset                0
 # resetevent   0
@@ -39,9 +37,6 @@
 # blocked      lock nr (0-7)
 # blockedwake  lock nr (0-7)
 # unlocked     lock nr (0-7)
-# lockedbkl    dont care
-# blockedbkl   dont care
-# unlockedbkl  dont care
 # opcodeeq     command opcode or number
 # opcodelt     number
 # opcodegt     number
index cdc3e4f..7b59100 100644 (file)
@@ -19,8 +19,6 @@
 # lockintnowait        lock nr (0-7)
 # lockcont     lock nr (0-7)
 # unlock       lock nr (0-7)
-# lockbkl      lock nr (0-7)
-# unlockbkl    lock nr (0-7)
 # signal       thread to signal (0-7)
 # reset                0
 # resetevent   0
@@ -39,9 +37,6 @@
 # blocked      lock nr (0-7)
 # blockedwake  lock nr (0-7)
 # unlocked     lock nr (0-7)
-# lockedbkl    dont care
-# blockedbkl   dont care
-# unlockedbkl  dont care
 # opcodeeq     command opcode or number
 # opcodelt     number
 # opcodegt     number
index baa1413..2f0e049 100644 (file)
@@ -19,8 +19,6 @@
 # lockintnowait        lock nr (0-7)
 # lockcont     lock nr (0-7)
 # unlock       lock nr (0-7)
-# lockbkl      lock nr (0-7)
-# unlockbkl    lock nr (0-7)
 # signal       thread to signal (0-7)
 # reset                0
 # resetevent   0
@@ -39,9 +37,6 @@
 # blocked      lock nr (0-7)
 # blockedwake  lock nr (0-7)
 # unlocked     lock nr (0-7)
-# lockedbkl    dont care
-# blockedbkl   dont care
-# unlockedbkl  dont care
 # opcodeeq     command opcode or number
 # opcodelt     number
 # opcodegt     number
index e6ec0c8..04f4034 100644 (file)
@@ -19,8 +19,6 @@
 # lockintnowait        lock nr (0-7)
 # lockcont     lock nr (0-7)
 # unlock       lock nr (0-7)
-# lockbkl      lock nr (0-7)
-# unlockbkl    lock nr (0-7)
 # signal       thread to signal (0-7)
 # reset                0
 # resetevent   0
@@ -39,9 +37,6 @@
 # blocked      lock nr (0-7)
 # blockedwake  lock nr (0-7)
 # unlocked     lock nr (0-7)
-# lockedbkl    dont care
-# blockedbkl   dont care
-# unlockedbkl  dont care
 # opcodeeq     command opcode or number
 # opcodelt     number
 # opcodegt     number
index ca64f8b..a48a6ee 100644 (file)
@@ -19,8 +19,6 @@
 # lockintnowait        lock nr (0-7)
 # lockcont     lock nr (0-7)
 # unlock       lock nr (0-7)
-# lockbkl      lock nr (0-7)
-# unlockbkl    lock nr (0-7)
 # signal       thread to signal (0-7)
 # reset                0
 # resetevent   0
@@ -39,9 +37,6 @@
 # blocked      lock nr (0-7)
 # blockedwake  lock nr (0-7)
 # unlocked     lock nr (0-7)
-# lockedbkl    dont care
-# blockedbkl   dont care
-# unlockedbkl  dont care
 # opcodeeq     command opcode or number
 # opcodelt     number
 # opcodegt     number
index 64c2ed9..dbfdaed 100644 (file)
@@ -93,7 +93,7 @@ int cap_capable(struct task_struct *tsk, const struct cred *cred, int cap,
  * Determine whether the current process may set the system clock and timezone
  * information, returning 0 if permission granted, -ve if denied.
  */
-int cap_settime(struct timespec *ts, struct timezone *tz)
+int cap_settime(const struct timespec *ts, const struct timezone *tz)
 {
        if (!capable(CAP_SYS_TIME))
                return -EPERM;
index edfa50d..a52aa7c 100644 (file)
@@ -87,13 +87,13 @@ extern void key_type_put(struct key_type *ktype);
 extern int __key_link_begin(struct key *keyring,
                            const struct key_type *type,
                            const char *description,
-                           struct keyring_list **_prealloc);
+                           unsigned long *_prealloc);
 extern int __key_link_check_live_key(struct key *keyring, struct key *key);
 extern void __key_link(struct key *keyring, struct key *key,
-                      struct keyring_list **_prealloc);
+                      unsigned long *_prealloc);
 extern void __key_link_end(struct key *keyring,
                           struct key_type *type,
-                          struct keyring_list *prealloc);
+                          unsigned long prealloc);
 
 extern key_ref_t __keyring_search_one(key_ref_t keyring_ref,
                                      const struct key_type *type,
index 84d4eb5..1c2d43d 100644 (file)
@@ -415,7 +415,7 @@ static int __key_instantiate_and_link(struct key *key,
                                      size_t datalen,
                                      struct key *keyring,
                                      struct key *authkey,
-                                     struct keyring_list **_prealloc)
+                                     unsigned long *_prealloc)
 {
        int ret, awaken;
 
@@ -481,7 +481,7 @@ int key_instantiate_and_link(struct key *key,
                             struct key *keyring,
                             struct key *authkey)
 {
-       struct keyring_list *prealloc;
+       unsigned long prealloc;
        int ret;
 
        if (keyring) {
@@ -526,7 +526,7 @@ int key_negate_and_link(struct key *key,
                        struct key *keyring,
                        struct key *authkey)
 {
-       struct keyring_list *prealloc;
+       unsigned long prealloc;
        struct timespec now;
        int ret, awaken, link_ret = 0;
 
@@ -814,7 +814,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
                               key_perm_t perm,
                               unsigned long flags)
 {
-       struct keyring_list *prealloc;
+       unsigned long prealloc;
        const struct cred *cred = current_cred();
        struct key_type *ktype;
        struct key *keyring, *key = NULL;
index 92024ed..5620f08 100644 (file)
@@ -25,6 +25,8 @@
                (keyring)->payload.subscriptions,                       \
                rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem)))
 
+#define KEY_LINK_FIXQUOTA 1UL
+
 /*
  * When plumbing the depths of the key tree, this sets a hard limit
  * set on how deep we're willing to go.
@@ -699,11 +701,11 @@ static void keyring_unlink_rcu_disposal(struct rcu_head *rcu)
  * Preallocate memory so that a key can be linked into to a keyring.
  */
 int __key_link_begin(struct key *keyring, const struct key_type *type,
-                    const char *description,
-                    struct keyring_list **_prealloc)
+                    const char *description, unsigned long *_prealloc)
        __acquires(&keyring->sem)
 {
        struct keyring_list *klist, *nklist;
+       unsigned long prealloc;
        unsigned max;
        size_t size;
        int loop, ret;
@@ -746,6 +748,7 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
 
                                /* note replacement slot */
                                klist->delkey = nklist->delkey = loop;
+                               prealloc = (unsigned long)nklist;
                                goto done;
                        }
                }
@@ -760,6 +763,7 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
        if (klist && klist->nkeys < klist->maxkeys) {
                /* there's sufficient slack space to append directly */
                nklist = NULL;
+               prealloc = KEY_LINK_FIXQUOTA;
        } else {
                /* grow the key list */
                max = 4;
@@ -794,8 +798,9 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
                nklist->keys[nklist->delkey] = NULL;
        }
 
+       prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA;
 done:
-       *_prealloc = nklist;
+       *_prealloc = prealloc;
        kleave(" = 0");
        return 0;
 
@@ -836,12 +841,12 @@ int __key_link_check_live_key(struct key *keyring, struct key *key)
  * combination.
  */
 void __key_link(struct key *keyring, struct key *key,
-               struct keyring_list **_prealloc)
+               unsigned long *_prealloc)
 {
        struct keyring_list *klist, *nklist;
 
-       nklist = *_prealloc;
-       *_prealloc = NULL;
+       nklist = (struct keyring_list *)(*_prealloc & ~KEY_LINK_FIXQUOTA);
+       *_prealloc = 0;
 
        kenter("%d,%d,%p", keyring->serial, key->serial, nklist);
 
@@ -881,20 +886,22 @@ void __key_link(struct key *keyring, struct key *key,
  * Must be called with __key_link_begin() having being called.
  */
 void __key_link_end(struct key *keyring, struct key_type *type,
-                   struct keyring_list *prealloc)
+                   unsigned long prealloc)
        __releases(&keyring->sem)
 {
        BUG_ON(type == NULL);
        BUG_ON(type->name == NULL);
-       kenter("%d,%s,%p", keyring->serial, type->name, prealloc);
+       kenter("%d,%s,%lx", keyring->serial, type->name, prealloc);
 
        if (type == &key_type_keyring)
                up_write(&keyring_serialise_link_sem);
 
        if (prealloc) {
-               kfree(prealloc);
-               key_payload_reserve(keyring,
-                                   keyring->datalen - KEYQUOTA_LINK_BYTES);
+               if (prealloc & KEY_LINK_FIXQUOTA)
+                       key_payload_reserve(keyring,
+                                           keyring->datalen -
+                                           KEYQUOTA_LINK_BYTES);
+               kfree((struct keyring_list *)(prealloc & ~KEY_LINK_FIXQUOTA));
        }
        up_write(&keyring->sem);
 }
@@ -921,7 +928,7 @@ void __key_link_end(struct key *keyring, struct key_type *type,
  */
 int key_link(struct key *keyring, struct key *key)
 {
-       struct keyring_list *prealloc;
+       unsigned long prealloc;
        int ret;
 
        key_check(keyring);
index 9a7fb39..a3dc0d4 100644 (file)
@@ -352,8 +352,8 @@ static int construct_alloc_key(struct key_type *type,
                               struct key_user *user,
                               struct key **_key)
 {
-       struct keyring_list *prealloc;
        const struct cred *cred = current_cred();
+       unsigned long prealloc;
        struct key *key;
        key_ref_t key_ref;
        int ret;
index 739e403..bb33eca 100644 (file)
@@ -154,10 +154,9 @@ int security_capset(struct cred *new, const struct cred *old,
                                    effective, inheritable, permitted);
 }
 
-int security_capable(int cap)
+int security_capable(const struct cred *cred, int cap)
 {
-       return security_ops->capable(current, current_cred(), cap,
-                                    SECURITY_CAP_AUDIT);
+       return security_ops->capable(current, cred, cap, SECURITY_CAP_AUDIT);
 }
 
 int security_real_capable(struct task_struct *tsk, int cap)
@@ -202,7 +201,7 @@ int security_syslog(int type)
        return security_ops->syslog(type);
 }
 
-int security_settime(struct timespec *ts, struct timezone *tz)
+int security_settime(const struct timespec *ts, const struct timezone *tz)
 {
        return security_ops->settime(ts, tz);
 }
index e276eb4..c8d6992 100644 (file)
@@ -3198,7 +3198,11 @@ static void selinux_cred_free(struct cred *cred)
 {
        struct task_security_struct *tsec = cred->security;
 
-       BUG_ON((unsigned long) cred->security < PAGE_SIZE);
+       /*
+        * cred->security == NULL if security_cred_alloc_blank() or
+        * security_prepare_creds() returned an error.
+        */
+       BUG_ON(cred->security && (unsigned long) cred->security < PAGE_SIZE);
        cred->security = (void *) 0x7UL;
        kfree(tsec);
 }
index 91acc9a..7c1fc64 100644 (file)
@@ -30,6 +30,8 @@
 
 #define DRIVER_NAME    "aaci-pl041"
 
+#define FRAME_PERIOD_US        21
+
 /*
  * PM support is not complete.  Turn it off.
  */
@@ -48,7 +50,11 @@ static void aaci_ac97_select_codec(struct aaci *aaci, struct snd_ac97 *ac97)
        if (v & SLFR_1RXV)
                readl(aaci->base + AACI_SL1RX);
 
-       writel(maincr, aaci->base + AACI_MAINCR);
+       if (maincr != readl(aaci->base + AACI_MAINCR)) {
+               writel(maincr, aaci->base + AACI_MAINCR);
+               readl(aaci->base + AACI_MAINCR);
+               udelay(1);
+       }
 }
 
 /*
@@ -64,8 +70,8 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
                            unsigned short val)
 {
        struct aaci *aaci = ac97->private_data;
+       int timeout;
        u32 v;
-       int timeout = 5000;
 
        if (ac97->num >= 4)
                return;
@@ -81,14 +87,17 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
        writel(val << 4, aaci->base + AACI_SL2TX);
        writel(reg << 12, aaci->base + AACI_SL1TX);
 
-       /*
-        * Wait for the transmission of both slots to complete.
-        */
+       /* Initially, wait one frame period */
+       udelay(FRAME_PERIOD_US);
+
+       /* And then wait an additional eight frame periods for it to be sent */
+       timeout = FRAME_PERIOD_US * 8;
        do {
+               udelay(1);
                v = readl(aaci->base + AACI_SLFR);
        } while ((v & (SLFR_1TXB|SLFR_2TXB)) && --timeout);
 
-       if (!timeout)
+       if (v & (SLFR_1TXB|SLFR_2TXB))
                dev_err(&aaci->dev->dev,
                        "timeout waiting for write to complete\n");
 
@@ -101,9 +110,8 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
 {
        struct aaci *aaci = ac97->private_data;
+       int timeout, retries = 10;
        u32 v;
-       int timeout = 5000;
-       int retries = 10;
 
        if (ac97->num >= 4)
                return ~0;
@@ -117,35 +125,34 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
         */
        writel((reg << 12) | (1 << 19), aaci->base + AACI_SL1TX);
 
-       /*
-        * Wait for the transmission to complete.
-        */
+       /* Initially, wait one frame period */
+       udelay(FRAME_PERIOD_US);
+
+       /* And then wait an additional eight frame periods for it to be sent */
+       timeout = FRAME_PERIOD_US * 8;
        do {
+               udelay(1);
                v = readl(aaci->base + AACI_SLFR);
        } while ((v & SLFR_1TXB) && --timeout);
 
-       if (!timeout) {
+       if (v & SLFR_1TXB) {
                dev_err(&aaci->dev->dev, "timeout on slot 1 TX busy\n");
                v = ~0;
                goto out;
        }
 
-       /*
-        * Give the AC'97 codec more than enough time
-        * to respond. (42us = ~2 frames at 48kHz.)
-        */
-       udelay(42);
+       /* Now wait for the response frame */
+       udelay(FRAME_PERIOD_US);
 
-       /*
-        * Wait for slot 2 to indicate data.
-        */
-       timeout = 5000;
+       /* And then wait an additional eight frame periods for data */
+       timeout = FRAME_PERIOD_US * 8;
        do {
+               udelay(1);
                cond_resched();
                v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV);
        } while ((v != (SLFR_1RXV|SLFR_2RXV)) && --timeout);
 
-       if (!timeout) {
+       if (v != (SLFR_1RXV|SLFR_2RXV)) {
                dev_err(&aaci->dev->dev, "timeout on RX valid\n");
                v = ~0;
                goto out;
@@ -179,6 +186,7 @@ aaci_chan_wait_ready(struct aaci_runtime *aacirun, unsigned long mask)
        int timeout = 5000;
 
        do {
+               udelay(1);
                val = readl(aacirun->base + AACI_SR);
        } while (val & mask && timeout--);
 }
@@ -874,7 +882,7 @@ static int __devinit aaci_probe_ac97(struct aaci *aaci)
         * Give the AC'97 codec more than enough time
         * to wake up. (42us = ~2 frames at 48kHz.)
         */
-       udelay(42);
+       udelay(FRAME_PERIOD_US * 2);
 
        ret = snd_ac97_bus(aaci->card, 0, &aaci_bus_ops, aaci, &ac97_bus);
        if (ret)
@@ -989,6 +997,8 @@ static unsigned int __devinit aaci_size_fifo(struct aaci *aaci)
         * disabling the channel doesn't clear the FIFO.
         */
        writel(aaci->maincr & ~MAINCR_IE, aaci->base + AACI_MAINCR);
+       readl(aaci->base + AACI_MAINCR);
+       udelay(1);
        writel(aaci->maincr, aaci->base + AACI_MAINCR);
 
        /*
index 10c3a87..b310702 100644 (file)
 #include <linux/dw_dmac.h>
 
 #include <mach/cpu.h>
-#include <mach/hardware.h>
 #include <mach/gpio.h>
 
+#ifdef CONFIG_ARCH_AT91
+#include <mach/hardware.h>
+#endif
+
 #include "ac97c.h"
 
 enum {
index 7730575..b8b31c4 100644 (file)
@@ -45,12 +45,13 @@ static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
 {
        struct snd_hrtimer *stime = container_of(hrt, struct snd_hrtimer, hrt);
        struct snd_timer *t = stime->timer;
+       unsigned long oruns;
 
        if (!atomic_read(&stime->running))
                return HRTIMER_NORESTART;
 
-       hrtimer_forward_now(hrt, ns_to_ktime(t->sticks * resolution));
-       snd_timer_interrupt(stime->timer, t->sticks);
+       oruns = hrtimer_forward_now(hrt, ns_to_ktime(t->sticks * resolution));
+       snd_timer_interrupt(stime->timer, t->sticks * oruns);
 
        if (!atomic_read(&stime->running))
                return HRTIMER_NORESTART;
@@ -104,7 +105,7 @@ static int snd_hrtimer_stop(struct snd_timer *t)
 }
 
 static struct snd_timer_hardware hrtimer_hw = {
-       .flags =        SNDRV_TIMER_HW_AUTO,
+       .flags =        SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_TASKLET,
        .open =         snd_hrtimer_open,
        .close =        snd_hrtimer_close,
        .start =        snd_hrtimer_start,
index 4902ae5..53b53e9 100644 (file)
@@ -141,6 +141,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
 
 fail_input:
        input_free_device(jack->input_dev);
+       kfree(jack->id);
        kfree(jack);
        return err;
 }
index da03597..5c426df 100644 (file)
 #include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/ioport.h>
+#include <linux/io.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/rawmidi.h>
 #include <linux/delay.h>
 
-#include <asm/io.h>
-
 /*
  *      globals
  */
index 96f14dc..90ffb99 100644 (file)
@@ -87,7 +87,7 @@ ifeq ($(CONFIG_PSS_HAVE_BOOT),y)
        $(obj)/bin2hex pss_synth < $< > $@
 else
     $(obj)/pss_boot.h:
-       (                                                       \
+       $(Q)(                                                   \
            echo 'static unsigned char * pss_synth = NULL;';    \
            echo 'static int pss_synthLen = 0;';                \
        ) > $@
@@ -102,7 +102,7 @@ ifeq ($(CONFIG_TRIX_HAVE_BOOT),y)
        $(obj)/hex2hex -i trix_boot < $< > $@
 else
     $(obj)/trix_boot.h:
-       (                                                       \
+       $(Q)(                                                   \
            echo 'static unsigned char * trix_boot = NULL;';    \
            echo 'static int trix_boot_len = 0;';               \
        ) > $@
index 23f49f3..16c0bdf 100644 (file)
@@ -1252,11 +1252,19 @@ static void vortex_adbdma_resetup(vortex_t *vortex, int adbdma) {
 static int inline vortex_adbdma_getlinearpos(vortex_t * vortex, int adbdma)
 {
        stream_t *dma = &vortex->dma_adb[adbdma];
-       int temp;
+       int temp, page, delta;
 
        temp = hwread(vortex->mmio, VORTEX_ADBDMA_STAT + (adbdma << 2));
-       temp = (dma->period_virt * dma->period_bytes) + (temp & (dma->period_bytes - 1));
-       return temp;
+       page = (temp & ADB_SUBBUF_MASK) >> ADB_SUBBUF_SHIFT;
+       if (dma->nr_periods >= 4)
+               delta = (page - dma->period_real) & 3;
+       else {
+               delta = (page - dma->period_real);
+               if (delta < 0)
+                       delta += dma->nr_periods;
+       }
+       return (dma->period_virt + delta) * dma->period_bytes
+               + (temp & (dma->period_bytes - 1));
 }
 
 static void vortex_adbdma_startfifo(vortex_t * vortex, int adbdma)
index 6117595..573594b 100644 (file)
@@ -979,31 +979,25 @@ snd_azf3328_codec_setfmt(struct snd_azf3328_codec_data *codec,
 
        snd_azf3328_dbgcallenter();
        switch (bitrate) {
-#define AZF_FMT_XLATE(in_freq, out_bits) \
-       do { \
-               case AZF_FREQ_ ## in_freq: \
-                       freq = SOUNDFORMAT_FREQ_ ## out_bits; \
-                       break; \
-       } while (0);
-       AZF_FMT_XLATE(4000, SUSPECTED_4000)
-       AZF_FMT_XLATE(4800, SUSPECTED_4800)
-       /* the AZF3328 names it "5510" for some strange reason: */
-       AZF_FMT_XLATE(5512, 5510)
-       AZF_FMT_XLATE(6620, 6620)
-       AZF_FMT_XLATE(8000, 8000)
-       AZF_FMT_XLATE(9600, 9600)
-       AZF_FMT_XLATE(11025, 11025)
-       AZF_FMT_XLATE(13240, SUSPECTED_13240)
-       AZF_FMT_XLATE(16000, 16000)
-       AZF_FMT_XLATE(22050, 22050)
-       AZF_FMT_XLATE(32000, 32000)
+       case AZF_FREQ_4000:  freq = SOUNDFORMAT_FREQ_SUSPECTED_4000; break;
+       case AZF_FREQ_4800:  freq = SOUNDFORMAT_FREQ_SUSPECTED_4800; break;
+       case AZF_FREQ_5512:
+               /* the AZF3328 names it "5510" for some strange reason */
+                            freq = SOUNDFORMAT_FREQ_5510; break;
+       case AZF_FREQ_6620:  freq = SOUNDFORMAT_FREQ_6620; break;
+       case AZF_FREQ_8000:  freq = SOUNDFORMAT_FREQ_8000; break;
+       case AZF_FREQ_9600:  freq = SOUNDFORMAT_FREQ_9600; break;
+       case AZF_FREQ_11025: freq = SOUNDFORMAT_FREQ_11025; break;
+       case AZF_FREQ_13240: freq = SOUNDFORMAT_FREQ_SUSPECTED_13240; break;
+       case AZF_FREQ_16000: freq = SOUNDFORMAT_FREQ_16000; break;
+       case AZF_FREQ_22050: freq = SOUNDFORMAT_FREQ_22050; break;
+       case AZF_FREQ_32000: freq = SOUNDFORMAT_FREQ_32000; break;
        default:
                snd_printk(KERN_WARNING "unknown bitrate %d, assuming 44.1kHz!\n", bitrate);
                /* fall-through */
-       AZF_FMT_XLATE(44100, 44100)
-       AZF_FMT_XLATE(48000, 48000)
-       AZF_FMT_XLATE(66200, SUSPECTED_66200)
-#undef AZF_FMT_XLATE
+       case AZF_FREQ_44100: freq = SOUNDFORMAT_FREQ_44100; break;
+       case AZF_FREQ_48000: freq = SOUNDFORMAT_FREQ_48000; break;
+       case AZF_FREQ_66200: freq = SOUNDFORMAT_FREQ_SUSPECTED_66200; break;
        }
        /* val = 0xff07; 3m27.993s (65301Hz; -> 64000Hz???) hmm, 66120, 65967, 66123 */
        /* val = 0xff09; 17m15.098s (13123,478Hz; -> 12000Hz???) hmm, 13237.2Hz? */
index 4a66347..74b0560 100644 (file)
@@ -381,7 +381,7 @@ static void hdmi_show_short_audio_desc(struct cea_sad *a)
        snd_print_pcm_rates(a->rates, buf, sizeof(buf));
 
        if (a->format == AUDIO_CODING_TYPE_LPCM)
-               snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2 - 8));
+               snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2) - 8);
        else if (a->max_bitrate)
                snprintf(buf2, sizeof(buf2),
                                ", max bitrate = %d", a->max_bitrate);
index 2e91a99..fcedad9 100644 (file)
@@ -2308,6 +2308,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = {
        SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB),
+       SND_PCI_QUIRK(0x1043, 0x8410, "ASUS", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba A100-259", POS_FIX_LPIB),
@@ -2703,7 +2704,7 @@ static int __devinit azx_probe(struct pci_dev *pci,
        if (err < 0)
                goto out_free;
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
-       if (patch[dev]) {
+       if (patch[dev] && *patch[dev]) {
                snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n",
                           patch[dev]);
                err = snd_hda_load_patch(chip->bus, patch[dev]);
index a07b031..067982f 100644 (file)
@@ -1039,9 +1039,11 @@ static struct hda_verb cs_errata_init_verbs[] = {
        {0x11, AC_VERB_SET_PROC_COEF, 0x0008},
        {0x11, AC_VERB_SET_PROC_STATE, 0x00},
 
+#if 0 /* Don't to set to D3 as we are in power-up sequence */
        {0x07, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Rx: D3 */
        {0x08, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Tx: D3 */
        /*{0x01, AC_VERB_SET_POWER_STATE, 0x03},*/ /* AFG: D3 This is already handled */
+#endif
 
        {} /* terminator */
 };
index 9bb030a..4d5004e 100644 (file)
@@ -85,6 +85,7 @@ struct conexant_spec {
        unsigned int auto_mic;
        int auto_mic_ext;               /* autocfg.inputs[] index for ext mic */
        unsigned int need_dac_fix;
+       hda_nid_t slave_dig_outs[2];
 
        /* capture */
        unsigned int num_adc_nids;
@@ -127,6 +128,7 @@ struct conexant_spec {
        unsigned int ideapad:1;
        unsigned int thinkpad:1;
        unsigned int hp_laptop:1;
+       unsigned int asus:1;
 
        unsigned int ext_mic_present;
        unsigned int recording;
@@ -352,6 +354,8 @@ static int conexant_build_pcms(struct hda_codec *codec)
                        info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
                                spec->dig_in_nid;
                }
+               if (spec->slave_dig_outs[0])
+                       codec->slave_dig_outs = spec->slave_dig_outs;
        }
 
        return 0;
@@ -403,10 +407,16 @@ static int conexant_add_jack(struct hda_codec *codec,
        struct conexant_spec *spec;
        struct conexant_jack *jack;
        const char *name;
-       int err;
+       int i, err;
 
        spec = codec->spec;
        snd_array_init(&spec->jacks, sizeof(*jack), 32);
+
+       jack = spec->jacks.list;
+       for (i = 0; i < spec->jacks.used; i++, jack++)
+               if (jack->nid == nid)
+                       return 0 ; /* already present */
+
        jack = snd_array_new(&spec->jacks);
        name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ;
 
@@ -2100,7 +2110,7 @@ static int patch_cxt5051(struct hda_codec *codec)
 static hda_nid_t cxt5066_dac_nids[1] = { 0x10 };
 static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 };
 static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 };
-#define CXT5066_SPDIF_OUT      0x21
+static hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 };
 
 /* OLPC's microphone port is DC coupled for use with external sensors,
  * therefore we use a 50% mic bias in order to center the input signal with
@@ -2312,6 +2322,19 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec)
        }
 }
 
+
+/* toggle input of built-in digital mic and mic jack appropriately */
+static void cxt5066_asus_automic(struct hda_codec *codec)
+{
+       unsigned int present;
+
+       present = snd_hda_jack_detect(codec, 0x1b);
+       snd_printdd("CXT5066: external microphone present=%d\n", present);
+       snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL,
+                           present ? 1 : 0);
+}
+
+
 /* toggle input of built-in digital mic and mic jack appropriately */
 static void cxt5066_hp_laptop_automic(struct hda_codec *codec)
 {
@@ -2387,79 +2410,55 @@ static void cxt5066_hp_automute(struct hda_codec *codec)
        cxt5066_update_speaker(codec);
 }
 
-/* unsolicited event for jack sensing */
-static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res)
+/* Dispatch the right mic autoswitch function */
+static void cxt5066_automic(struct hda_codec *codec)
 {
        struct conexant_spec *spec = codec->spec;
-       snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
-       switch (res >> 26) {
-       case CONEXANT_HP_EVENT:
-               cxt5066_hp_automute(codec);
-               break;
-       case CONEXANT_MIC_EVENT:
-               /* ignore mic events in DC mode; we're always using the jack */
-               if (!spec->dc_enable)
-                       cxt5066_olpc_automic(codec);
-               break;
-       }
-}
 
-/* unsolicited event for jack sensing */
-static void cxt5066_vostro_event(struct hda_codec *codec, unsigned int res)
-{
-       snd_printdd("CXT5066_vostro: unsol event %x (%x)\n", res, res >> 26);
-       switch (res >> 26) {
-       case CONEXANT_HP_EVENT:
-               cxt5066_hp_automute(codec);
-               break;
-       case CONEXANT_MIC_EVENT:
+       if (spec->dell_vostro)
                cxt5066_vostro_automic(codec);
-               break;
-       }
-}
-
-/* unsolicited event for jack sensing */
-static void cxt5066_ideapad_event(struct hda_codec *codec, unsigned int res)
-{
-       snd_printdd("CXT5066_ideapad: unsol event %x (%x)\n", res, res >> 26);
-       switch (res >> 26) {
-       case CONEXANT_HP_EVENT:
-               cxt5066_hp_automute(codec);
-               break;
-       case CONEXANT_MIC_EVENT:
+       else if (spec->ideapad)
                cxt5066_ideapad_automic(codec);
-               break;
-       }
+       else if (spec->thinkpad)
+               cxt5066_thinkpad_automic(codec);
+       else if (spec->hp_laptop)
+               cxt5066_hp_laptop_automic(codec);
+       else if (spec->asus)
+               cxt5066_asus_automic(codec);
 }
 
 /* unsolicited event for jack sensing */
-static void cxt5066_hp_laptop_event(struct hda_codec *codec, unsigned int res)
+static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res)
 {
-       snd_printdd("CXT5066_hp_laptop: unsol event %x (%x)\n", res, res >> 26);
+       struct conexant_spec *spec = codec->spec;
+       snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
        switch (res >> 26) {
        case CONEXANT_HP_EVENT:
                cxt5066_hp_automute(codec);
                break;
        case CONEXANT_MIC_EVENT:
-               cxt5066_hp_laptop_automic(codec);
+               /* ignore mic events in DC mode; we're always using the jack */
+               if (!spec->dc_enable)
+                       cxt5066_olpc_automic(codec);
                break;
        }
 }
 
 /* unsolicited event for jack sensing */
-static void cxt5066_thinkpad_event(struct hda_codec *codec, unsigned int res)
+static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res)
 {
-       snd_printdd("CXT5066_thinkpad: unsol event %x (%x)\n", res, res >> 26);
+       snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
        switch (res >> 26) {
        case CONEXANT_HP_EVENT:
                cxt5066_hp_automute(codec);
                break;
        case CONEXANT_MIC_EVENT:
-               cxt5066_thinkpad_automic(codec);
+               cxt5066_automic(codec);
                break;
        }
 }
 
+
 static const struct hda_input_mux cxt5066_analog_mic_boost = {
        .num_items = 5,
        .items = {
@@ -2633,6 +2632,27 @@ static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec)
        spec->recording = 0;
 }
 
+static void conexant_check_dig_outs(struct hda_codec *codec,
+                                   hda_nid_t *dig_pins,
+                                   int num_pins)
+{
+       struct conexant_spec *spec = codec->spec;
+       hda_nid_t *nid_loc = &spec->multiout.dig_out_nid;
+       int i;
+
+       for (i = 0; i < num_pins; i++, dig_pins++) {
+               unsigned int cfg = snd_hda_codec_get_pincfg(codec, *dig_pins);
+               if (get_defcfg_connect(cfg) == AC_JACK_PORT_NONE)
+                       continue;
+               if (snd_hda_get_connections(codec, *dig_pins, nid_loc, 1) != 1)
+                       continue;
+               if (spec->slave_dig_outs[0])
+                       nid_loc++;
+               else
+                       nid_loc = spec->slave_dig_outs;
+       }
+}
+
 static struct hda_input_mux cxt5066_capture_source = {
        .num_items = 4,
        .items = {
@@ -3039,20 +3059,11 @@ static struct hda_verb cxt5066_init_verbs_hp_laptop[] = {
 /* initialize jack-sensing, too */
 static int cxt5066_init(struct hda_codec *codec)
 {
-       struct conexant_spec *spec = codec->spec;
-
        snd_printdd("CXT5066: init\n");
        conexant_init(codec);
        if (codec->patch_ops.unsol_event) {
                cxt5066_hp_automute(codec);
-               if (spec->dell_vostro)
-                       cxt5066_vostro_automic(codec);
-               else if (spec->ideapad)
-                       cxt5066_ideapad_automic(codec);
-               else if (spec->thinkpad)
-                       cxt5066_thinkpad_automic(codec);
-               else if (spec->hp_laptop)
-                       cxt5066_hp_laptop_automic(codec);
+               cxt5066_automic(codec);
        }
        cxt5066_set_mic_boost(codec);
        return 0;
@@ -3080,6 +3091,7 @@ enum {
        CXT5066_DELL_VOSTRO,    /* Dell Vostro 1015i */
        CXT5066_IDEAPAD,        /* Lenovo IdeaPad U150 */
        CXT5066_THINKPAD,       /* Lenovo ThinkPad T410s, others? */
+       CXT5066_ASUS,           /* Asus K52JU, Lenovo G560 - Int mic at 0x1a and Ext mic at 0x1b */
        CXT5066_HP_LAPTOP,      /* HP Laptop */
        CXT5066_MODELS
 };
@@ -3091,6 +3103,7 @@ static const char * const cxt5066_models[CXT5066_MODELS] = {
        [CXT5066_DELL_VOSTRO]   = "dell-vostro",
        [CXT5066_IDEAPAD]       = "ideapad",
        [CXT5066_THINKPAD]      = "thinkpad",
+       [CXT5066_ASUS]          = "asus",
        [CXT5066_HP_LAPTOP]     = "hp-laptop",
 };
 
@@ -3101,8 +3114,12 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0401, "Dell Vostro 1014", CXT5066_DELL_VOSTRO),
        SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO),
        SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD),
+       SND_PCI_QUIRK(0x1028, 0x050f, "Dell Inspiron", CXT5066_IDEAPAD),
+       SND_PCI_QUIRK(0x1028, 0x0510, "Dell Vostro", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP),
-       SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_HP_LAPTOP),
+       SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_ASUS),
+       SND_PCI_QUIRK(0x1043, 0x1643, "Asus K52JU", CXT5066_ASUS),
+       SND_PCI_QUIRK(0x1043, 0x1993, "Asus U50F", CXT5066_ASUS),
        SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5),
        SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5),
@@ -3111,7 +3128,9 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
        SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD),
        SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD),
+       SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS),
        SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD),
+       SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS),
        SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT5066_IDEAPAD), /* Fallback for Lenovos without dock mic */
        {}
 };
@@ -3133,7 +3152,8 @@ static int patch_cxt5066(struct hda_codec *codec)
        spec->multiout.max_channels = 2;
        spec->multiout.num_dacs = ARRAY_SIZE(cxt5066_dac_nids);
        spec->multiout.dac_nids = cxt5066_dac_nids;
-       spec->multiout.dig_out_nid = CXT5066_SPDIF_OUT;
+       conexant_check_dig_outs(codec, cxt5066_digout_pin_nids,
+           ARRAY_SIZE(cxt5066_digout_pin_nids));
        spec->num_adc_nids = 1;
        spec->adc_nids = cxt5066_adc_nids;
        spec->capsrc_nids = cxt5066_capsrc_nids;
@@ -3167,17 +3187,20 @@ static int patch_cxt5066(struct hda_codec *codec)
                spec->num_init_verbs++;
                spec->dell_automute = 1;
                break;
+       case CXT5066_ASUS:
        case CXT5066_HP_LAPTOP:
                codec->patch_ops.init = cxt5066_init;
-               codec->patch_ops.unsol_event = cxt5066_hp_laptop_event;
+               codec->patch_ops.unsol_event = cxt5066_unsol_event;
                spec->init_verbs[spec->num_init_verbs] =
                        cxt5066_init_verbs_hp_laptop;
                spec->num_init_verbs++;
-               spec->hp_laptop = 1;
+               spec->hp_laptop = board_config == CXT5066_HP_LAPTOP;
+               spec->asus = board_config == CXT5066_ASUS;
                spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
                spec->mixers[spec->num_mixers++] = cxt5066_mixers;
                /* no S/PDIF out */
-               spec->multiout.dig_out_nid = 0;
+               if (board_config == CXT5066_HP_LAPTOP)
+                       spec->multiout.dig_out_nid = 0;
                /* input source automatically selected */
                spec->input_mux = NULL;
                spec->port_d_mode = 0;
@@ -3207,7 +3230,7 @@ static int patch_cxt5066(struct hda_codec *codec)
                break;
        case CXT5066_DELL_VOSTRO:
                codec->patch_ops.init = cxt5066_init;
-               codec->patch_ops.unsol_event = cxt5066_vostro_event;
+               codec->patch_ops.unsol_event = cxt5066_unsol_event;
                spec->init_verbs[0] = cxt5066_init_verbs_vostro;
                spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
                spec->mixers[spec->num_mixers++] = cxt5066_mixers;
@@ -3224,7 +3247,7 @@ static int patch_cxt5066(struct hda_codec *codec)
                break;
        case CXT5066_IDEAPAD:
                codec->patch_ops.init = cxt5066_init;
-               codec->patch_ops.unsol_event = cxt5066_ideapad_event;
+               codec->patch_ops.unsol_event = cxt5066_unsol_event;
                spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
                spec->mixers[spec->num_mixers++] = cxt5066_mixers;
                spec->init_verbs[0] = cxt5066_init_verbs_ideapad;
@@ -3240,7 +3263,7 @@ static int patch_cxt5066(struct hda_codec *codec)
                break;
        case CXT5066_THINKPAD:
                codec->patch_ops.init = cxt5066_init;
-               codec->patch_ops.unsol_event = cxt5066_thinkpad_event;
+               codec->patch_ops.unsol_event = cxt5066_unsol_event;
                spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
                spec->mixers[spec->num_mixers++] = cxt5066_mixers;
                spec->init_verbs[0] = cxt5066_init_verbs_thinkpad;
@@ -3389,7 +3412,7 @@ static void cx_auto_parse_output(struct hda_codec *codec)
                }
        }
        spec->multiout.dac_nids = spec->private_dac_nids;
-       spec->multiout.max_channels = nums * 2;
+       spec->multiout.max_channels = spec->multiout.num_dacs * 2;
 
        if (cfg->hp_outs > 0)
                spec->auto_mute = 1;
@@ -3708,9 +3731,9 @@ static int cx_auto_init(struct hda_codec *codec)
        return 0;
 }
 
-static int cx_auto_add_volume(struct hda_codec *codec, const char *basename,
+static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
                              const char *dir, int cidx,
-                             hda_nid_t nid, int hda_dir)
+                             hda_nid_t nid, int hda_dir, int amp_idx)
 {
        static char name[32];
        static struct snd_kcontrol_new knew[] = {
@@ -3722,7 +3745,8 @@ static int cx_auto_add_volume(struct hda_codec *codec, const char *basename,
 
        for (i = 0; i < 2; i++) {
                struct snd_kcontrol *kctl;
-               knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, 0, hda_dir);
+               knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, amp_idx,
+                                                           hda_dir);
                knew[i].subdevice = HDA_SUBDEV_AMP_FLAG;
                knew[i].index = cidx;
                snprintf(name, sizeof(name), "%s%s %s", basename, dir, sfx[i]);
@@ -3738,6 +3762,9 @@ static int cx_auto_add_volume(struct hda_codec *codec, const char *basename,
        return 0;
 }
 
+#define cx_auto_add_volume(codec, str, dir, cidx, nid, hda_dir)                \
+       cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0)
+
 #define cx_auto_add_pb_volume(codec, nid, str, idx)                    \
        cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT)
 
@@ -3787,29 +3814,60 @@ static int cx_auto_build_input_controls(struct hda_codec *codec)
        struct conexant_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
        static const char *prev_label;
-       int i, err, cidx;
+       int i, err, cidx, conn_len;
+       hda_nid_t conn[HDA_MAX_CONNECTIONS];
+
+       int multi_adc_volume = 0; /* If the ADC nid has several input volumes */
+       int adc_nid = spec->adc_nids[0];
+
+       conn_len = snd_hda_get_connections(codec, adc_nid, conn,
+                                          HDA_MAX_CONNECTIONS);
+       if (conn_len < 0)
+               return conn_len;
+
+       multi_adc_volume = cfg->num_inputs > 1 && conn_len > 1;
+       if (!multi_adc_volume) {
+               err = cx_auto_add_volume(codec, "Capture", "", 0, adc_nid,
+                                        HDA_INPUT);
+               if (err < 0)
+                       return err;
+       }
 
-       err = cx_auto_add_volume(codec, "Capture", "", 0, spec->adc_nids[0],
-                                HDA_INPUT);
-       if (err < 0)
-               return err;
        prev_label = NULL;
        cidx = 0;
        for (i = 0; i < cfg->num_inputs; i++) {
                hda_nid_t nid = cfg->inputs[i].pin;
                const char *label;
-               if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP))
+               int j;
+               int pin_amp = get_wcaps(codec, nid) & AC_WCAP_IN_AMP;
+               if (!pin_amp && !multi_adc_volume)
                        continue;
+
                label = hda_get_autocfg_input_label(codec, cfg, i);
                if (label == prev_label)
                        cidx++;
                else
                        cidx = 0;
                prev_label = label;
-               err = cx_auto_add_volume(codec, label, " Capture", cidx,
-                                        nid, HDA_INPUT);
-               if (err < 0)
-                       return err;
+
+               if (pin_amp) {
+                       err = cx_auto_add_volume(codec, label, " Boost", cidx,
+                                                nid, HDA_INPUT);
+                       if (err < 0)
+                               return err;
+               }
+
+               if (!multi_adc_volume)
+                       continue;
+               for (j = 0; j < conn_len; j++) {
+                       if (conn[j] == nid) {
+                               err = cx_auto_add_volume_idx(codec, label,
+                                   " Capture", cidx, adc_nid, HDA_INPUT, j);
+                               if (err < 0)
+                                       return err;
+                               break;
+                       }
+               }
        }
        return 0;
 }
@@ -3881,6 +3939,8 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = {
          .patch = patch_cxt5066 },
        { .id = 0x14f15069, .name = "CX20585",
          .patch = patch_cxt5066 },
+       { .id = 0x14f1506e, .name = "CX20590",
+         .patch = patch_cxt5066 },
        { .id = 0x14f15097, .name = "CX20631",
          .patch = patch_conexant_auto },
        { .id = 0x14f15098, .name = "CX20632",
@@ -3907,6 +3967,7 @@ MODULE_ALIAS("snd-hda-codec-id:14f15066");
 MODULE_ALIAS("snd-hda-codec-id:14f15067");
 MODULE_ALIAS("snd-hda-codec-id:14f15068");
 MODULE_ALIAS("snd-hda-codec-id:14f15069");
+MODULE_ALIAS("snd-hda-codec-id:14f1506e");
 MODULE_ALIAS("snd-hda-codec-id:14f15097");
 MODULE_ALIAS("snd-hda-codec-id:14f15098");
 MODULE_ALIAS("snd-hda-codec-id:14f150a1");
index 2d5b83f..ec0fa2d 100644 (file)
@@ -642,6 +642,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
                        hdmi_ai->ver            = 0x01;
                        hdmi_ai->len            = 0x0a;
                        hdmi_ai->CC02_CT47      = channels - 1;
+                       hdmi_ai->CA             = ca;
                        hdmi_checksum_audio_infoframe(hdmi_ai);
                } else if (spec->sink_eld[i].conn_type == 1) { /* DisplayPort */
                        struct dp_audio_infoframe *dp_ai;
@@ -651,6 +652,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
                        dp_ai->len              = 0x1b;
                        dp_ai->ver              = 0x11 << 2;
                        dp_ai->CC02_CT47        = channels - 1;
+                       dp_ai->CA               = ca;
                } else {
                        snd_printd("HDMI: unknown connection type at pin %d\n",
                                   pin_nid);
@@ -1632,6 +1634,9 @@ static struct hda_codec_preset snd_hda_preset_hdmi[] = {
 { .id = 0x10de0012, .name = "GPU 12 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
 { .id = 0x10de0013, .name = "GPU 13 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
 { .id = 0x10de0014, .name = "GPU 14 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0015, .name = "GPU 15 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0016, .name = "GPU 16 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+/* 17 is known to be absent */
 { .id = 0x10de0018, .name = "GPU 18 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
 { .id = 0x10de0019, .name = "GPU 19 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
 { .id = 0x10de001a, .name = "GPU 1a HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
@@ -1674,6 +1679,8 @@ MODULE_ALIAS("snd-hda-codec-id:10de0011");
 MODULE_ALIAS("snd-hda-codec-id:10de0012");
 MODULE_ALIAS("snd-hda-codec-id:10de0013");
 MODULE_ALIAS("snd-hda-codec-id:10de0014");
+MODULE_ALIAS("snd-hda-codec-id:10de0015");
+MODULE_ALIAS("snd-hda-codec-id:10de0016");
 MODULE_ALIAS("snd-hda-codec-id:10de0018");
 MODULE_ALIAS("snd-hda-codec-id:10de0019");
 MODULE_ALIAS("snd-hda-codec-id:10de001a");
index be4df4c..4261bb8 100644 (file)
@@ -1133,11 +1133,8 @@ static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
                nid = spec->autocfg.hp_pins[i];
                if (!nid)
                        break;
-               if (snd_hda_jack_detect(codec, nid)) {
-                       spec->jack_present = 1;
-                       break;
-               }
-               alc_report_jack(codec, spec->autocfg.hp_pins[i]);
+               alc_report_jack(codec, nid);
+               spec->jack_present |= snd_hda_jack_detect(codec, nid);
        }
 
        mute = spec->jack_present ? HDA_AMP_MUTE : 0;
@@ -2290,6 +2287,29 @@ static struct snd_kcontrol_new alc888_base_mixer[] = {
        { } /* end */
 };
 
+static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0f, 2, 0x0,
+               HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0f, 2, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Side Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Side Playback Switch", 0x0e, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       { } /* end */
+};
+
+
 static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
@@ -10359,7 +10379,7 @@ static struct alc_config_preset alc882_presets[] = {
                .init_hook = alc_automute_amp,
        },
        [ALC888_ACER_ASPIRE_4930G] = {
-               .mixers = { alc888_base_mixer,
+               .mixers = { alc888_acer_aspire_4930g_mixer,
                                alc883_chmode_mixer },
                .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
                                alc888_acer_aspire_4930g_verbs },
@@ -14954,9 +14974,11 @@ static struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
        SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
        SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
-       SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
-       SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
+       SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
+       SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
+       SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE),
+       SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
        SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
        {}
@@ -14990,7 +15012,7 @@ static struct snd_pci_quirk alc269_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
        SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
        SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269VB_AMIC),
        SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
        SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
        SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),
@@ -18800,6 +18822,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = {
                                        ALC662_3ST_6ch_DIG),
        SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
                           ALC663_ASUS_H13),
+       SND_PCI_QUIRK(0x1991, 0x5628, "Ordissimo EVE", ALC662_LENOVO_101E),
        {}
 };
 
@@ -19492,6 +19515,7 @@ static const struct alc_fixup alc662_fixups[] = {
 };
 
 static struct snd_pci_quirk alc662_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
        SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
        SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
index 9ea48b4..bd7b123 100644 (file)
@@ -586,7 +586,12 @@ static hda_nid_t stac92hd83xxx_pin_nids[10] = {
        0x0f, 0x10, 0x11, 0x1f, 0x20,
 };
 
-static hda_nid_t stac92hd88xxx_pin_nids[10] = {
+static hda_nid_t stac92hd87xxx_pin_nids[6] = {
+       0x0a, 0x0b, 0x0c, 0x0d,
+       0x0f, 0x11,
+};
+
+static hda_nid_t stac92hd88xxx_pin_nids[8] = {
        0x0a, 0x0b, 0x0c, 0x0d,
        0x0f, 0x11, 0x1f, 0x20,
 };
@@ -5430,12 +5435,13 @@ again:
        switch (codec->vendor_id) {
        case 0x111d76d1:
        case 0x111d76d9:
+       case 0x111d76e5:
                spec->dmic_nids = stac92hd87b_dmic_nids;
                spec->num_dmics = stac92xx_connected_ports(codec,
                                stac92hd87b_dmic_nids,
                                STAC92HD87B_NUM_DMICS);
-               spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids);
-               spec->pin_nids = stac92hd88xxx_pin_nids;
+               spec->num_pins = ARRAY_SIZE(stac92hd87xxx_pin_nids);
+               spec->pin_nids = stac92hd87xxx_pin_nids;
                spec->mono_nid = 0;
                spec->num_pwrs = 0;
                break;
@@ -5443,6 +5449,7 @@ again:
        case 0x111d7667:
        case 0x111d7668:
        case 0x111d7669:
+       case 0x111d76e3:
                spec->num_dmics = stac92xx_connected_ports(codec,
                                stac92hd88xxx_dmic_nids,
                                STAC92HD88XXX_NUM_DMICS);
@@ -6387,6 +6394,8 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = {
        { .id = 0x111d76cd, .name = "92HD89F2", .patch = patch_stac92hd73xx },
        { .id = 0x111d76ce, .name = "92HD89F1", .patch = patch_stac92hd73xx },
        { .id = 0x111d76e0, .name = "92HD91BXX", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d76e3, .name = "92HD98BXX", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d76e5, .name = "92HD99BXX", .patch = patch_stac92hd83xxx},
        { .id = 0x111d76e7, .name = "92HD90BXX", .patch = patch_stac92hd83xxx},
        {} /* terminator */
 };
index a76c326..63b0054 100644 (file)
@@ -567,7 +567,7 @@ static void via_auto_init_analog_input(struct hda_codec *codec)
                hda_nid_t nid = cfg->inputs[i].pin;
                if (spec->smart51_enabled && is_smart51_pins(spec, nid))
                        ctl = PIN_OUT;
-               else if (i == AUTO_PIN_MIC)
+               else if (cfg->inputs[i].type == AUTO_PIN_MIC)
                        ctl = PIN_VREF50;
                else
                        ctl = PIN_IN;
index c2ae63d..f53897a 100644 (file)
@@ -92,6 +92,8 @@ struct oxygen_model {
        void (*update_dac_volume)(struct oxygen *chip);
        void (*update_dac_mute)(struct oxygen *chip);
        void (*update_center_lfe_mix)(struct oxygen *chip, bool mixed);
+       unsigned int (*adjust_dac_routing)(struct oxygen *chip,
+                                          unsigned int play_routing);
        void (*gpio_changed)(struct oxygen *chip);
        void (*uart_input)(struct oxygen *chip);
        void (*ac97_switch)(struct oxygen *chip,
index 9bff14d..26c7e8b 100644 (file)
@@ -180,6 +180,8 @@ void oxygen_update_dac_routing(struct oxygen *chip)
                            (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
                            (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
                            (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT);
+       if (chip->model.adjust_dac_routing)
+               reg_value = chip->model.adjust_dac_routing(chip, reg_value);
        oxygen_write16_masked(chip, OXYGEN_PLAY_ROUTING, reg_value,
                              OXYGEN_PLAY_DAC0_SOURCE_MASK |
                              OXYGEN_PLAY_DAC1_SOURCE_MASK |
index 9f72d42..2527191 100644 (file)
@@ -392,7 +392,7 @@ static void dump_d1_registers(struct oxygen *chip,
        unsigned int i;
 
        snd_iprintf(buffer, "\nCS4398: 7?");
-       for (i = 2; i <= 8; ++i)
+       for (i = 2; i < 8; ++i)
                snd_iprintf(buffer, " %02x", data->cs4398_regs[i]);
        snd_iprintf(buffer, "\n");
        dump_cs4362a_registers(data, buffer);
index e1fa602..bc6eb58 100644 (file)
  *
  *   SPI 0 -> CS4245
  *
+ *   I²S 1 -> CS4245
+ *   I²S 2 -> CS4361 (center/LFE)
+ *   I²S 3 -> CS4361 (surround)
+ *   I²S 4 -> CS4361 (front)
+ *
  *   GPIO 3 <- ?
  *   GPIO 4 <- headphone detect
  *   GPIO 5 -> route input jack to line-in (0) or mic-in (1)
@@ -36,6 +41,7 @@
  *   input 1 <- aux
  *   input 2 <- front mic
  *   input 4 <- line/mic
+ *   DAC out -> headphones
  *   aux out -> front panel headphones
  */
 
@@ -207,6 +213,35 @@ static void set_cs4245_adc_params(struct oxygen *chip,
        cs4245_write_cached(chip, CS4245_ADC_CTRL, value);
 }
 
+static inline unsigned int shift_bits(unsigned int value,
+                                     unsigned int shift_from,
+                                     unsigned int shift_to,
+                                     unsigned int mask)
+{
+       if (shift_from < shift_to)
+               return (value << (shift_to - shift_from)) & mask;
+       else
+               return (value >> (shift_from - shift_to)) & mask;
+}
+
+static unsigned int adjust_dg_dac_routing(struct oxygen *chip,
+                                         unsigned int play_routing)
+{
+       return (play_routing & OXYGEN_PLAY_DAC0_SOURCE_MASK) |
+              shift_bits(play_routing,
+                         OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
+                         OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
+                         OXYGEN_PLAY_DAC1_SOURCE_MASK) |
+              shift_bits(play_routing,
+                         OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
+                         OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
+                         OXYGEN_PLAY_DAC2_SOURCE_MASK) |
+              shift_bits(play_routing,
+                         OXYGEN_PLAY_DAC0_SOURCE_SHIFT,
+                         OXYGEN_PLAY_DAC3_SOURCE_SHIFT,
+                         OXYGEN_PLAY_DAC3_SOURCE_MASK);
+}
+
 static int output_switch_info(struct snd_kcontrol *ctl,
                              struct snd_ctl_elem_info *info)
 {
@@ -557,6 +592,7 @@ struct oxygen_model model_xonar_dg = {
        .resume = dg_resume,
        .set_dac_params = set_cs4245_dac_params,
        .set_adc_params = set_cs4245_adc_params,
+       .adjust_dac_routing = adjust_dg_dac_routing,
        .dump_registers = dump_cs4245_registers,
        .model_data_size = sizeof(struct dg),
        .device_config = PLAYBACK_0_TO_I2S |
index bd26e09..6ce9ad7 100644 (file)
@@ -22,7 +22,7 @@
 #define __PDAUDIOCF_H
 
 #include <sound/pcm.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/interrupt.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
index 989e04a..fe33e12 100644 (file)
@@ -23,8 +23,8 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
+#include <linux/io.h>
 #include <sound/core.h>
-#include <asm/io.h>
 #include "vxpocket.h"
 
 
index da2208e..5e4d499 100644 (file)
@@ -129,7 +129,7 @@ static struct snd_soc_dai_link afeb9260_dai = {
        .cpu_dai_name = "atmel-ssc-dai.0",
        .codec_dai_name = "tlv320aic23-hifi",
        .platform_name = "atmel_pcm-audio",
-       .codec_name = "tlv320aic23-codec.0-0x1a",
+       .codec_name = "tlv320aic23-codec.0-001a",
        .init = afeb9260_tlv320aic23_init,
        .ops = &afeb9260_ops,
 };
index e902b24..ad28663 100644 (file)
@@ -119,7 +119,7 @@ static struct snd_soc_dai_link bf5xx_ssm2602_dai = {
        .cpu_dai_name = "bf5xx-i2s",
        .codec_dai_name = "ssm2602-hifi",
        .platform_name = "bf5xx-pcm-audio",
-       .codec_name = "ssm2602-codec.0-0x1b",
+       .codec_name = "ssm2602-codec.0-001b",
        .ops = &bf5xx_ssm2602_ops,
 };
 
index 46dbfd0..347a567 100644 (file)
@@ -153,7 +153,7 @@ static int cq93vc_resume(struct snd_soc_codec *codec)
 
 static int cq93vc_probe(struct snd_soc_codec *codec)
 {
-       struct davinci_vc *davinci_vc = codec->dev->platform_data;
+       struct davinci_vc *davinci_vc = snd_soc_codec_get_drvdata(codec);
 
        davinci_vc->cq93vc.codec = codec;
        codec->control_data = davinci_vc;
index 03d1e86..0bb424a 100644 (file)
@@ -367,9 +367,12 @@ static int cx20442_codec_remove(struct snd_soc_codec *codec)
        return 0;
 }
 
+static const u8 cx20442_reg;
+
 static struct snd_soc_codec_driver cx20442_codec_dev = {
        .probe =        cx20442_codec_probe,
        .remove =       cx20442_codec_remove,
+       .reg_cache_default = &cx20442_reg,
        .reg_cache_size = 1,
        .reg_word_size = sizeof(u8),
        .read = cx20442_read_reg_cache,
index 987476a..017d99c 100644 (file)
@@ -1482,7 +1482,7 @@ int wm8903_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
                            WM8903_MICDET_EINT | WM8903_MICSHRT_EINT,
                            irq_mask);
 
-       if (det && shrt) {
+       if (det || shrt) {
                /* Enable mic detection, this may not have been set through
                 * platform data (eg, if the defaults are OK). */
                snd_soc_update_bits(codec, WM8903_WRITE_SEQUENCER_0,
index e8490f3..e3ec243 100644 (file)
@@ -165,7 +165,7 @@ extern int wm8903_mic_detect(struct snd_soc_codec *codec,
 
 #define WM8903_VMID_RES_50K                          2
 #define WM8903_VMID_RES_250K                         3
-#define WM8903_VMID_RES_5K                           4
+#define WM8903_VMID_RES_5K                           6
 
 /*
  * R8 (0x08) - Analogue DAC 0
index 4bbc344..8dfb0a0 100644 (file)
@@ -145,18 +145,18 @@ static const struct snd_kcontrol_new wm8978_snd_controls[] = {
        SOC_SINGLE("DAC Playback Limiter Threshold",
                WM8978_DAC_LIMITER_2, 4, 7, 0),
        SOC_SINGLE("DAC Playback Limiter Boost",
-               WM8978_DAC_LIMITER_2, 0, 15, 0),
+               WM8978_DAC_LIMITER_2, 0, 12, 0),
 
        SOC_ENUM("ALC Enable Switch", alc1),
        SOC_SINGLE("ALC Capture Min Gain", WM8978_ALC_CONTROL_1, 0, 7, 0),
        SOC_SINGLE("ALC Capture Max Gain", WM8978_ALC_CONTROL_1, 3, 7, 0),
 
-       SOC_SINGLE("ALC Capture Hold", WM8978_ALC_CONTROL_2, 4, 7, 0),
+       SOC_SINGLE("ALC Capture Hold", WM8978_ALC_CONTROL_2, 4, 10, 0),
        SOC_SINGLE("ALC Capture Target", WM8978_ALC_CONTROL_2, 0, 15, 0),
 
        SOC_ENUM("ALC Capture Mode", alc3),
-       SOC_SINGLE("ALC Capture Decay", WM8978_ALC_CONTROL_3, 4, 15, 0),
-       SOC_SINGLE("ALC Capture Attack", WM8978_ALC_CONTROL_3, 0, 15, 0),
+       SOC_SINGLE("ALC Capture Decay", WM8978_ALC_CONTROL_3, 4, 10, 0),
+       SOC_SINGLE("ALC Capture Attack", WM8978_ALC_CONTROL_3, 0, 10, 0),
 
        SOC_SINGLE("ALC Capture Noise Gate Switch", WM8978_NOISE_GATE, 3, 1, 0),
        SOC_SINGLE("ALC Capture Noise Gate Threshold",
@@ -211,8 +211,10 @@ static const struct snd_kcontrol_new wm8978_snd_controls[] = {
                WM8978_LOUT2_SPK_CONTROL, WM8978_ROUT2_SPK_CONTROL, 6, 1, 1),
 
        /* DAC / ADC oversampling */
-       SOC_SINGLE("DAC 128x Oversampling Switch", WM8978_DAC_CONTROL, 8, 1, 0),
-       SOC_SINGLE("ADC 128x Oversampling Switch", WM8978_ADC_CONTROL, 8, 1, 0),
+       SOC_SINGLE("DAC 128x Oversampling Switch", WM8978_DAC_CONTROL,
+                  5, 1, 0),
+       SOC_SINGLE("ADC 128x Oversampling Switch", WM8978_ADC_CONTROL,
+                  5, 1, 0),
 };
 
 /* Mixer #1: Output (OUT1, OUT2) Mixer: mix AUX, Input mixer output and DAC */
index 247a6a9..c6c958e 100644 (file)
@@ -107,6 +107,12 @@ struct wm8994_priv {
 
        int revision;
        struct wm8994_pdata *pdata;
+
+       unsigned int aif1clk_enable:1;
+       unsigned int aif2clk_enable:1;
+
+       unsigned int aif1clk_disable:1;
+       unsigned int aif2clk_disable:1;
 };
 
 static int wm8994_readable(unsigned int reg)
@@ -1004,6 +1010,110 @@ static void wm8994_update_class_w(struct snd_soc_codec *codec)
        }
 }
 
+static int late_enable_ev(struct snd_soc_dapm_widget *w,
+                         struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (wm8994->aif1clk_enable) {
+                       snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
+                                           WM8994_AIF1CLK_ENA_MASK,
+                                           WM8994_AIF1CLK_ENA);
+                       wm8994->aif1clk_enable = 0;
+               }
+               if (wm8994->aif2clk_enable) {
+                       snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1,
+                                           WM8994_AIF2CLK_ENA_MASK,
+                                           WM8994_AIF2CLK_ENA);
+                       wm8994->aif2clk_enable = 0;
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static int late_disable_ev(struct snd_soc_dapm_widget *w,
+                          struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMD:
+               if (wm8994->aif1clk_disable) {
+                       snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
+                                           WM8994_AIF1CLK_ENA_MASK, 0);
+                       wm8994->aif1clk_disable = 0;
+               }
+               if (wm8994->aif2clk_disable) {
+                       snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1,
+                                           WM8994_AIF2CLK_ENA_MASK, 0);
+                       wm8994->aif2clk_disable = 0;
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static int aif1clk_ev(struct snd_soc_dapm_widget *w,
+                     struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               wm8994->aif1clk_enable = 1;
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               wm8994->aif1clk_disable = 1;
+               break;
+       }
+
+       return 0;
+}
+
+static int aif2clk_ev(struct snd_soc_dapm_widget *w,
+                     struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               wm8994->aif2clk_enable = 1;
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               wm8994->aif2clk_disable = 1;
+               break;
+       }
+
+       return 0;
+}
+
+static int adc_mux_ev(struct snd_soc_dapm_widget *w,
+                     struct snd_kcontrol *kcontrol, int event)
+{
+       late_enable_ev(w, kcontrol, event);
+       return 0;
+}
+
+static int dac_ev(struct snd_soc_dapm_widget *w,
+                 struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       unsigned int mask = 1 << w->shift;
+
+       snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5,
+                           mask, mask);
+       return 0;
+}
+
 static const char *hp_mux_text[] = {
        "Mixer",
        "DAC",
@@ -1272,6 +1382,59 @@ static const struct soc_enum aif2dacr_src_enum =
 static const struct snd_kcontrol_new aif2dacr_src_mux =
        SOC_DAPM_ENUM("AIF2DACR Mux", aif2dacr_src_enum);
 
+static const struct snd_soc_dapm_widget wm8994_lateclk_revd_widgets[] = {
+SND_SOC_DAPM_SUPPLY("AIF1CLK", SND_SOC_NOPM, 0, 0, aif1clk_ev,
+       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("AIF2CLK", SND_SOC_NOPM, 0, 0, aif2clk_ev,
+       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+SND_SOC_DAPM_PGA_E("Late DAC1L Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
+       late_enable_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_PGA_E("Late DAC1R Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
+       late_enable_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_PGA_E("Late DAC2L Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
+       late_enable_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_PGA_E("Late DAC2R Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
+       late_enable_ev, SND_SOC_DAPM_PRE_PMU),
+
+SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev)
+};
+
+static const struct snd_soc_dapm_widget wm8994_lateclk_widgets[] = {
+SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0)
+};
+
+static const struct snd_soc_dapm_widget wm8994_dac_revd_widgets[] = {
+SND_SOC_DAPM_DAC_E("DAC2L", NULL, SND_SOC_NOPM, 3, 0,
+       dac_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_DAC_E("DAC2R", NULL, SND_SOC_NOPM, 2, 0,
+       dac_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_DAC_E("DAC1L", NULL, SND_SOC_NOPM, 1, 0,
+       dac_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_DAC_E("DAC1R", NULL, SND_SOC_NOPM, 0, 0,
+       dac_ev, SND_SOC_DAPM_PRE_PMU),
+};
+
+static const struct snd_soc_dapm_widget wm8994_dac_widgets[] = {
+SND_SOC_DAPM_DAC("DAC2L", NULL, WM8994_POWER_MANAGEMENT_5, 3, 0),
+SND_SOC_DAPM_DAC("DAC2R", NULL, WM8994_POWER_MANAGEMENT_5, 2, 0),
+SND_SOC_DAPM_DAC("DAC1L", NULL, WM8994_POWER_MANAGEMENT_5, 1, 0),
+SND_SOC_DAPM_DAC("DAC1R", NULL, WM8994_POWER_MANAGEMENT_5, 0, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8994_adc_revd_widgets[] = {
+SND_SOC_DAPM_MUX_E("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux,
+                  adc_mux_ev, SND_SOC_DAPM_PRE_PMU),
+SND_SOC_DAPM_MUX_E("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux,
+                  adc_mux_ev, SND_SOC_DAPM_PRE_PMU),
+};
+
+static const struct snd_soc_dapm_widget wm8994_adc_widgets[] = {
+SND_SOC_DAPM_MUX("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux),
+SND_SOC_DAPM_MUX("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux),
+};
+
 static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = {
 SND_SOC_DAPM_INPUT("DMIC1DAT"),
 SND_SOC_DAPM_INPUT("DMIC2DAT"),
@@ -1284,12 +1447,9 @@ SND_SOC_DAPM_SUPPLY("DSP1CLK", WM8994_CLOCKING_1, 3, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("DSP2CLK", WM8994_CLOCKING_1, 2, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("DSPINTCLK", WM8994_CLOCKING_1, 1, 0, NULL, 0),
 
-SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, NULL, 0),
-SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0),
-
-SND_SOC_DAPM_AIF_OUT("AIF1ADC1L", "AIF1 Capture",
+SND_SOC_DAPM_AIF_OUT("AIF1ADC1L", NULL,
                     0, WM8994_POWER_MANAGEMENT_4, 9, 0),
-SND_SOC_DAPM_AIF_OUT("AIF1ADC1R", "AIF1 Capture",
+SND_SOC_DAPM_AIF_OUT("AIF1ADC1R", NULL,
                     0, WM8994_POWER_MANAGEMENT_4, 8, 0),
 SND_SOC_DAPM_AIF_IN_E("AIF1DAC1L", NULL, 0,
                      WM8994_POWER_MANAGEMENT_5, 9, 0, wm8958_aif_ev,
@@ -1298,9 +1458,9 @@ SND_SOC_DAPM_AIF_IN_E("AIF1DAC1R", NULL, 0,
                      WM8994_POWER_MANAGEMENT_5, 8, 0, wm8958_aif_ev,
                      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
-SND_SOC_DAPM_AIF_OUT("AIF1ADC2L", "AIF1 Capture",
+SND_SOC_DAPM_AIF_OUT("AIF1ADC2L", NULL,
                     0, WM8994_POWER_MANAGEMENT_4, 11, 0),
-SND_SOC_DAPM_AIF_OUT("AIF1ADC2R", "AIF1 Capture",
+SND_SOC_DAPM_AIF_OUT("AIF1ADC2R", NULL,
                     0, WM8994_POWER_MANAGEMENT_4, 10, 0),
 SND_SOC_DAPM_AIF_IN_E("AIF1DAC2L", NULL, 0,
                      WM8994_POWER_MANAGEMENT_5, 11, 0, wm8958_aif_ev,
@@ -1345,6 +1505,7 @@ SND_SOC_DAPM_AIF_IN_E("AIF2DACR", NULL, 0,
 
 SND_SOC_DAPM_AIF_IN("AIF1DACDAT", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
 SND_SOC_DAPM_AIF_IN("AIF2DACDAT", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1ADCDAT", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
 SND_SOC_DAPM_AIF_OUT("AIF2ADCDAT", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
 
 SND_SOC_DAPM_MUX("AIF1DAC Mux", SND_SOC_NOPM, 0, 0, &aif1dac_mux),
@@ -1368,14 +1529,6 @@ SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8994_POWER_MANAGEMENT_4, 2, 0),
 SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 1, 0),
 SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0),
 
-SND_SOC_DAPM_MUX("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux),
-SND_SOC_DAPM_MUX("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux),
-
-SND_SOC_DAPM_DAC("DAC2L", NULL, WM8994_POWER_MANAGEMENT_5, 3, 0),
-SND_SOC_DAPM_DAC("DAC2R", NULL, WM8994_POWER_MANAGEMENT_5, 2, 0),
-SND_SOC_DAPM_DAC("DAC1L", NULL, WM8994_POWER_MANAGEMENT_5, 1, 0),
-SND_SOC_DAPM_DAC("DAC1R", NULL, WM8994_POWER_MANAGEMENT_5, 0, 0),
-
 SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux),
 SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux),
 
@@ -1515,14 +1668,12 @@ static const struct snd_soc_dapm_route intercon[] = {
        { "AIF2ADC Mux", "AIF3DACDAT", "AIF3ADCDAT" },
 
        /* DAC1 inputs */
-       { "DAC1L", NULL, "DAC1L Mixer" },
        { "DAC1L Mixer", "AIF2 Switch", "AIF2DACL" },
        { "DAC1L Mixer", "AIF1.2 Switch", "AIF1DAC2L" },
        { "DAC1L Mixer", "AIF1.1 Switch", "AIF1DAC1L" },
        { "DAC1L Mixer", "Left Sidetone Switch", "Left Sidetone" },
        { "DAC1L Mixer", "Right Sidetone Switch", "Right Sidetone" },
 
-       { "DAC1R", NULL, "DAC1R Mixer" },
        { "DAC1R Mixer", "AIF2 Switch", "AIF2DACR" },
        { "DAC1R Mixer", "AIF1.2 Switch", "AIF1DAC2R" },
        { "DAC1R Mixer", "AIF1.1 Switch", "AIF1DAC1R" },
@@ -1531,7 +1682,6 @@ static const struct snd_soc_dapm_route intercon[] = {
 
        /* DAC2/AIF2 outputs  */
        { "AIF2ADCL", NULL, "AIF2DAC2L Mixer" },
-       { "DAC2L", NULL, "AIF2DAC2L Mixer" },
        { "AIF2DAC2L Mixer", "AIF2 Switch", "AIF2DACL" },
        { "AIF2DAC2L Mixer", "AIF1.2 Switch", "AIF1DAC2L" },
        { "AIF2DAC2L Mixer", "AIF1.1 Switch", "AIF1DAC1L" },
@@ -1539,13 +1689,17 @@ static const struct snd_soc_dapm_route intercon[] = {
        { "AIF2DAC2L Mixer", "Right Sidetone Switch", "Right Sidetone" },
 
        { "AIF2ADCR", NULL, "AIF2DAC2R Mixer" },
-       { "DAC2R", NULL, "AIF2DAC2R Mixer" },
        { "AIF2DAC2R Mixer", "AIF2 Switch", "AIF2DACR" },
        { "AIF2DAC2R Mixer", "AIF1.2 Switch", "AIF1DAC2R" },
        { "AIF2DAC2R Mixer", "AIF1.1 Switch", "AIF1DAC1R" },
        { "AIF2DAC2R Mixer", "Left Sidetone Switch", "Left Sidetone" },
        { "AIF2DAC2R Mixer", "Right Sidetone Switch", "Right Sidetone" },
 
+       { "AIF1ADCDAT", NULL, "AIF1ADC1L" },
+       { "AIF1ADCDAT", NULL, "AIF1ADC1R" },
+       { "AIF1ADCDAT", NULL, "AIF1ADC2L" },
+       { "AIF1ADCDAT", NULL, "AIF1ADC2R" },
+
        { "AIF2ADCDAT", NULL, "AIF2ADC Mux" },
 
        /* AIF3 output */
@@ -1578,6 +1732,31 @@ static const struct snd_soc_dapm_route intercon[] = {
        { "Right Headphone Mux", "DAC", "DAC1R" },
 };
 
+static const struct snd_soc_dapm_route wm8994_lateclk_revd_intercon[] = {
+       { "DAC1L", NULL, "Late DAC1L Enable PGA" },
+       { "Late DAC1L Enable PGA", NULL, "DAC1L Mixer" },
+       { "DAC1R", NULL, "Late DAC1R Enable PGA" },
+       { "Late DAC1R Enable PGA", NULL, "DAC1R Mixer" },
+       { "DAC2L", NULL, "Late DAC2L Enable PGA" },
+       { "Late DAC2L Enable PGA", NULL, "AIF2DAC2L Mixer" },
+       { "DAC2R", NULL, "Late DAC2R Enable PGA" },
+       { "Late DAC2R Enable PGA", NULL, "AIF2DAC2R Mixer" }
+};
+
+static const struct snd_soc_dapm_route wm8994_lateclk_intercon[] = {
+       { "DAC1L", NULL, "DAC1L Mixer" },
+       { "DAC1R", NULL, "DAC1R Mixer" },
+       { "DAC2L", NULL, "AIF2DAC2L Mixer" },
+       { "DAC2R", NULL, "AIF2DAC2R Mixer" },
+};
+
+static const struct snd_soc_dapm_route wm8994_revd_intercon[] = {
+       { "AIF1DACDAT", NULL, "AIF2DACDAT" },
+       { "AIF2DACDAT", NULL, "AIF1DACDAT" },
+       { "AIF1ADCDAT", NULL, "AIF2ADCDAT" },
+       { "AIF2ADCDAT", NULL, "AIF1ADCDAT" },
+};
+
 static const struct snd_soc_dapm_route wm8994_intercon[] = {
        { "AIF2DACL", NULL, "AIF2DAC Mux" },
        { "AIF2DACR", NULL, "AIF2DAC Mux" },
@@ -2386,7 +2565,7 @@ static int wm8994_set_tristate(struct snd_soc_dai *codec_dai, int tristate)
        else
                val = 0;
 
-       return snd_soc_update_bits(codec, reg, mask, reg);
+       return snd_soc_update_bits(codec, reg, mask, val);
 }
 
 #define WM8994_RATES SNDRV_PCM_RATE_8000_96000
@@ -2501,6 +2680,22 @@ static int wm8994_resume(struct snd_soc_codec *codec)
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        int i, ret;
+       unsigned int val, mask;
+
+       if (wm8994->revision < 4) {
+               /* force a HW read */
+               val = wm8994_reg_read(codec->control_data,
+                                     WM8994_POWER_MANAGEMENT_5);
+
+               /* modify the cache only */
+               codec->cache_only = 1;
+               mask =  WM8994_DAC1R_ENA | WM8994_DAC1L_ENA |
+                       WM8994_DAC2R_ENA | WM8994_DAC2L_ENA;
+               val &= mask;
+               snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5,
+                                   mask, val);
+               codec->cache_only = 0;
+       }
 
        /* Restore the registers */
        ret = snd_soc_cache_sync(codec);
@@ -2834,11 +3029,10 @@ static void wm8958_default_micdet(u16 status, void *data)
                report |= SND_JACK_BTN_5;
 
 done:
-       snd_soc_jack_report(wm8994->micdet[0].jack,
+       snd_soc_jack_report(wm8994->micdet[0].jack, report,
                            SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 |
                            SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5 |
-                           SND_JACK_MICROPHONE | SND_JACK_VIDEOOUT,
-                           report);
+                           SND_JACK_MICROPHONE | SND_JACK_VIDEOOUT);
 }
 
 /**
@@ -3112,10 +3306,31 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        case WM8994:
                snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets,
                                          ARRAY_SIZE(wm8994_specific_dapm_widgets));
+               if (wm8994->revision < 4) {
+                       snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets,
+                                                 ARRAY_SIZE(wm8994_lateclk_revd_widgets));
+                       snd_soc_dapm_new_controls(dapm, wm8994_adc_revd_widgets,
+                                                 ARRAY_SIZE(wm8994_adc_revd_widgets));
+                       snd_soc_dapm_new_controls(dapm, wm8994_dac_revd_widgets,
+                                                 ARRAY_SIZE(wm8994_dac_revd_widgets));
+               } else {
+                       snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets,
+                                                 ARRAY_SIZE(wm8994_lateclk_widgets));
+                       snd_soc_dapm_new_controls(dapm, wm8994_adc_widgets,
+                                                 ARRAY_SIZE(wm8994_adc_widgets));
+                       snd_soc_dapm_new_controls(dapm, wm8994_dac_widgets,
+                                                 ARRAY_SIZE(wm8994_dac_widgets));
+               }
                break;
        case WM8958:
                snd_soc_add_controls(codec, wm8958_snd_controls,
                                     ARRAY_SIZE(wm8958_snd_controls));
+               snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets,
+                                         ARRAY_SIZE(wm8994_lateclk_widgets));
+               snd_soc_dapm_new_controls(dapm, wm8994_adc_widgets,
+                                         ARRAY_SIZE(wm8994_adc_widgets));
+               snd_soc_dapm_new_controls(dapm, wm8994_dac_widgets,
+                                         ARRAY_SIZE(wm8994_dac_widgets));
                snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
                                          ARRAY_SIZE(wm8958_dapm_widgets));
                break;
@@ -3129,8 +3344,20 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        case WM8994:
                snd_soc_dapm_add_routes(dapm, wm8994_intercon,
                                        ARRAY_SIZE(wm8994_intercon));
+
+               if (wm8994->revision < 4) {
+                       snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon,
+                                               ARRAY_SIZE(wm8994_revd_intercon));
+                       snd_soc_dapm_add_routes(dapm, wm8994_lateclk_revd_intercon,
+                                               ARRAY_SIZE(wm8994_lateclk_revd_intercon));
+               } else {
+                       snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon,
+                                               ARRAY_SIZE(wm8994_lateclk_intercon));
+               }
                break;
        case WM8958:
+               snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon,
+                                       ARRAY_SIZE(wm8994_lateclk_intercon));
                snd_soc_dapm_add_routes(dapm, wm8958_intercon,
                                        ARRAY_SIZE(wm8958_intercon));
                break;
index 6045cbd..608c84c 100644 (file)
@@ -1223,7 +1223,7 @@ static int wm8995_set_tristate(struct snd_soc_dai *codec_dai, int tristate)
        else
                val = 0;
 
-       return snd_soc_update_bits(codec, reg, mask, reg);
+       return snd_soc_update_bits(codec, reg, mask, val);
 }
 
 /* The size in bits of the FLL divide multiplied by 10
index 43825b2..cce704c 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/device.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
@@ -1341,6 +1342,10 @@ static __devinit int wm9081_i2c_probe(struct i2c_client *i2c,
        wm9081->control_type = SND_SOC_I2C;
        wm9081->control_data = i2c;
 
+       if (dev_get_platdata(&i2c->dev))
+               memcpy(&wm9081->retune, dev_get_platdata(&i2c->dev),
+                      sizeof(wm9081->retune));
+
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_wm9081, &wm9081_dai, 1);
        if (ret < 0)
index c466982..5168927 100644 (file)
@@ -91,6 +91,7 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op)
 static void calibrate_dc_servo(struct snd_soc_codec *codec)
 {
        struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+       s8 offset;
        u16 reg, reg_l, reg_r, dcs_cfg;
 
        /* If we're using a digital only path and have a previously
@@ -149,16 +150,14 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
                        hubs->dcs_codes);
 
                /* HPOUT1L */
-               if (reg_l + hubs->dcs_codes > 0 &&
-                   reg_l + hubs->dcs_codes < 0xff)
-                       reg_l += hubs->dcs_codes;
-               dcs_cfg = reg_l << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
+               offset = reg_l;
+               offset += hubs->dcs_codes;
+               dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
 
                /* HPOUT1R */
-               if (reg_r + hubs->dcs_codes > 0 &&
-                   reg_r + hubs->dcs_codes < 0xff)
-                       reg_r += hubs->dcs_codes;
-               dcs_cfg |= reg_r;
+               offset = reg_r;
+               offset += hubs->dcs_codes;
+               dcs_cfg |= (u8)offset;
 
                dev_dbg(codec->dev, "DCS result: %x\n", dcs_cfg);
 
@@ -675,6 +674,9 @@ SND_SOC_DAPM_OUTPUT("LINEOUT2N"),
 };
 
 static const struct snd_soc_dapm_route analogue_routes[] = {
+       { "MICBIAS1", NULL, "CLK_SYS" },
+       { "MICBIAS2", NULL, "CLK_SYS" },
+
        { "IN1L PGA", "IN1LP Switch", "IN1LP" },
        { "IN1L PGA", "IN1LN Switch", "IN1LN" },
 
index 0c2d6ba..fe79842 100644 (file)
@@ -218,12 +218,24 @@ static struct snd_soc_dai_link dm6467_evm_dai[] = {
                .ops = &evm_spdif_ops,
        },
 };
-static struct snd_soc_dai_link da8xx_evm_dai = {
+
+static struct snd_soc_dai_link da830_evm_dai = {
+       .name = "TLV320AIC3X",
+       .stream_name = "AIC3X",
+       .cpu_dai_name = "davinci-mcasp.1",
+       .codec_dai_name = "tlv320aic3x-hifi",
+       .codec_name = "tlv320aic3x-codec.1-0018",
+       .platform_name = "davinci-pcm-audio",
+       .init = evm_aic3x_init,
+       .ops = &evm_ops,
+};
+
+static struct snd_soc_dai_link da850_evm_dai = {
        .name = "TLV320AIC3X",
        .stream_name = "AIC3X",
        .cpu_dai_name= "davinci-mcasp.0",
        .codec_dai_name = "tlv320aic3x-hifi",
-       .codec_name = "tlv320aic3x-codec.0-001a",
+       .codec_name = "tlv320aic3x-codec.1-0018",
        .platform_name = "davinci-pcm-audio",
        .init = evm_aic3x_init,
        .ops = &evm_ops,
@@ -259,13 +271,13 @@ static struct snd_soc_card dm6467_snd_soc_card_evm = {
 
 static struct snd_soc_card da830_snd_soc_card = {
        .name = "DA830/OMAP-L137 EVM",
-       .dai_link = &da8xx_evm_dai,
+       .dai_link = &da830_evm_dai,
        .num_links = 1,
 };
 
 static struct snd_soc_card da850_snd_soc_card = {
        .name = "DA850/OMAP-L138 EVM",
-       .dai_link = &da8xx_evm_dai,
+       .dai_link = &da850_evm_dai,
        .num_links = 1,
 };
 
index e20c9e1..1e9bcca 100644 (file)
@@ -79,7 +79,7 @@ static struct snd_soc_dai_link eukrea_tlv320_dai = {
        .name           = "tlv320aic23",
        .stream_name    = "TLV320AIC23",
        .codec_dai_name = "tlv320aic23-hifi",
-       .platform_name  = "imx-pcm-audio.0",
+       .platform_name  = "imx-fiq-pcm-audio.0",
        .codec_name     = "tlv320aic23-codec.0-001a",
        .cpu_dai_name   = "imx-ssi.0",
        .ops            = &eukrea_tlv320_snd_ops,
index 1617504..73dde4a 100644 (file)
@@ -139,7 +139,7 @@ static struct snd_soc_dai_link am3517evm_dai = {
        .cpu_dai_name ="omap-mcbsp-dai.0",
        .codec_dai_name = "tlv320aic23-hifi",
        .platform_name = "omap-pcm-audio",
-       .codec_name = "tlv320aic23-codec",
+       .codec_name = "tlv320aic23-codec.2-001a",
        .init = am3517evm_aic23_init,
        .ops = &am3517evm_ops,
 };
index 2101bdc..3167be6 100644 (file)
@@ -507,8 +507,6 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
        /* Set up digital mute if not provided by the codec */
        if (!codec_dai->driver->ops) {
                codec_dai->driver->ops = &ams_delta_dai_ops;
-       } else if (!codec_dai->driver->ops->digital_mute) {
-               codec_dai->driver->ops->digital_mute = ams_delta_digital_mute;
        } else {
                ams_delta_ops.startup = ams_delta_startup;
                ams_delta_ops.shutdown = ams_delta_shutdown;
index fc592f0..784cff5 100644 (file)
@@ -307,10 +307,10 @@ static int corgi_wm8731_init(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_dai_link corgi_dai = {
        .name = "WM8731",
        .stream_name = "WM8731",
-       .cpu_dai_name = "pxa-is2-dai",
+       .cpu_dai_name = "pxa2xx-i2s",
        .codec_dai_name = "wm8731-hifi",
        .platform_name = "pxa-pcm-audio",
-       .codec_name = "wm8731-codec-0.001a",
+       .codec_name = "wm8731-codec-0.001b",
        .init = corgi_wm8731_init,
        .ops = &corgi_ops,
 };
index 28333e7..dc65650 100644 (file)
@@ -117,7 +117,7 @@ static struct snd_soc_dai_link e740_dai[] = {
        {
                .name = "AC97",
                .stream_name = "AC97 HiFi",
-               .cpu_dai_name = "pxa-ac97.0",
+               .cpu_dai_name = "pxa2xx-ac97",
                .codec_dai_name = "wm9705-hifi",
                .platform_name = "pxa-pcm-audio",
                .codec_name = "wm9705-codec",
@@ -126,7 +126,7 @@ static struct snd_soc_dai_link e740_dai[] = {
        {
                .name = "AC97 Aux",
                .stream_name = "AC97 Aux",
-               .cpu_dai_name = "pxa-ac97.1",
+               .cpu_dai_name = "pxa2xx-ac97-aux",
                .codec_dai_name = "wm9705-aux",
                .platform_name = "pxa-pcm-audio",
                .codec_name = "wm9705-codec",
index 01bf316..51897fc 100644 (file)
@@ -99,7 +99,7 @@ static struct snd_soc_dai_link e750_dai[] = {
        {
                .name = "AC97",
                .stream_name = "AC97 HiFi",
-               .cpu_dai_name = "pxa-ac97.0",
+               .cpu_dai_name = "pxa2xx-ac97",
                .codec_dai_name = "wm9705-hifi",
                .platform_name = "pxa-pcm-audio",
                .codec_name = "wm9705-codec",
@@ -109,7 +109,7 @@ static struct snd_soc_dai_link e750_dai[] = {
        {
                .name = "AC97 Aux",
                .stream_name = "AC97 Aux",
-               .cpu_dai_name = "pxa-ac97.1",
+               .cpu_dai_name = "pxa2xx-ac97-aux",
                .codec_dai_name ="wm9705-aux",
                .platform_name = "pxa-pcm-audio",
                .codec_name = "wm9705-codec",
index c6a37c6..053ed20 100644 (file)
@@ -89,7 +89,7 @@ static struct snd_soc_dai_link e800_dai[] = {
        {
                .name = "AC97",
                .stream_name = "AC97 HiFi",
-               .cpu_dai_name = "pxa-ac97.0",
+               .cpu_dai_name = "pxa2xx-ac97",
                .codec_dai_name = "wm9712-hifi",
                .platform_name = "pxa-pcm-audio",
                .codec_name = "wm9712-codec",
@@ -98,7 +98,7 @@ static struct snd_soc_dai_link e800_dai[] = {
        {
                .name = "AC97 Aux",
                .stream_name = "AC97 Aux",
-               .cpu_dai_name = "pxa-ac97.1",
+               .cpu_dai_name = "pxa2xx-ac97-aux",
                .codec_dai_name ="wm9712-aux",
                .platform_name = "pxa-pcm-audio",
                .codec_name = "wm9712-codec",
index fc22e6e..b13a425 100644 (file)
@@ -37,7 +37,7 @@ static struct snd_soc_dai_link em_x270_dai[] = {
        {
                .name = "AC97",
                .stream_name = "AC97 HiFi",
-               .cpu_dai_name = "pxa-ac97.0",
+               .cpu_dai_name = "pxa2xx-ac97",
                .codec_dai_name = "wm9712-hifi",
                .platform_name = "pxa-pcm-audio",
                .codec_name = "wm9712-codec",
@@ -45,7 +45,7 @@ static struct snd_soc_dai_link em_x270_dai[] = {
        {
                .name = "AC97 Aux",
                .stream_name = "AC97 Aux",
-               .cpu_dai_name = "pxa-ac97.1",
+               .cpu_dai_name = "pxa2xx-ac97-aux",
                .codec_dai_name ="wm9712-aux",
                .platform_name = "pxa-pcm-audio",
                .codec_name = "wm9712-codec",
index 0d70fc8..38ca675 100644 (file)
@@ -162,7 +162,7 @@ static struct snd_soc_dai_link mioa701_dai[] = {
        {
                .name = "AC97",
                .stream_name = "AC97 HiFi",
-               .cpu_dai_name = "pxa-ac97.0",
+               .cpu_dai_name = "pxa2xx-ac97",
                .codec_dai_name = "wm9713-hifi",
                .codec_name = "wm9713-codec",
                .init = mioa701_wm9713_init,
@@ -172,7 +172,7 @@ static struct snd_soc_dai_link mioa701_dai[] = {
        {
                .name = "AC97 Aux",
                .stream_name = "AC97 Aux",
-               .cpu_dai_name = "pxa-ac97.1",
+               .cpu_dai_name = "pxa2xx-ac97-aux",
                .codec_dai_name ="wm9713-aux",
                .codec_name = "wm9713-codec",
                .platform_name = "pxa-pcm-audio",
index 857db96..504e400 100644 (file)
@@ -132,7 +132,7 @@ static struct snd_soc_dai_link palm27x_dai[] = {
 {
        .name = "AC97 HiFi",
        .stream_name = "AC97 HiFi",
-       .cpu_dai_name = "pxa-ac97.0",
+       .cpu_dai_name = "pxa2xx-ac97",
        .codec_dai_name =  "wm9712-hifi",
        .codec_name = "wm9712-codec",
        .platform_name = "pxa-pcm-audio",
@@ -141,7 +141,7 @@ static struct snd_soc_dai_link palm27x_dai[] = {
 {
        .name = "AC97 Aux",
        .stream_name = "AC97 Aux",
-       .cpu_dai_name = "pxa-ac97.1",
+       .cpu_dai_name = "pxa2xx-ac97-aux",
        .codec_dai_name = "wm9712-aux",
        .codec_name = "wm9712-codec",
        .platform_name = "pxa-pcm-audio",
index 6298ee1..a7d4999 100644 (file)
@@ -276,7 +276,7 @@ static struct snd_soc_dai_link poodle_dai = {
        .cpu_dai_name = "pxa2xx-i2s",
        .codec_dai_name = "wm8731-hifi",
        .platform_name = "pxa-pcm-audio",
-       .codec_name = "wm8731-codec.0-001a",
+       .codec_name = "wm8731-codec.0-001b",
        .init = poodle_wm8731_init,
        .ops = &poodle_ops,
 };
index c2acb69..8e15713 100644 (file)
@@ -315,10 +315,10 @@ static int spitz_wm8750_init(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_dai_link spitz_dai = {
        .name = "wm8750",
        .stream_name = "WM8750",
-       .cpu_dai_name = "pxa-is2",
+       .cpu_dai_name = "pxa2xx-i2s",
        .codec_dai_name = "wm8750-hifi",
        .platform_name = "pxa-pcm-audio",
-       .codec_name = "wm8750-codec.0-001a",
+       .codec_name = "wm8750-codec.0-001b",
        .init = spitz_wm8750_init,
        .ops = &spitz_ops,
 };
index f75804e..4b6e5d6 100644 (file)
@@ -219,7 +219,7 @@ static struct snd_soc_dai_link tosa_dai[] = {
 {
        .name = "AC97",
        .stream_name = "AC97 HiFi",
-       .cpu_dai_name = "pxa-ac97.0",
+       .cpu_dai_name = "pxa2xx-ac97",
        .codec_dai_name = "wm9712-hifi",
        .platform_name = "pxa-pcm-audio",
        .codec_name = "wm9712-codec",
@@ -229,7 +229,7 @@ static struct snd_soc_dai_link tosa_dai[] = {
 {
        .name = "AC97 Aux",
        .stream_name = "AC97 Aux",
-       .cpu_dai_name = "pxa-ac97.1",
+       .cpu_dai_name = "pxa2xx-ac97-aux",
        .codec_dai_name = "wm9712-aux",
        .platform_name = "pxa-pcm-audio",
        .codec_name = "wm9712-codec",
index b222a7d..25bba10 100644 (file)
@@ -166,7 +166,7 @@ static struct snd_soc_dai_link zylonite_dai[] = {
        .stream_name = "AC97 HiFi",
        .codec_name = "wm9713-codec",
        .platform_name = "pxa-pcm-audio",
-       .cpu_dai_name = "pxa-ac97.0",
+       .cpu_dai_name = "pxa2xx-ac97",
        .codec_name = "wm9713-hifi",
        .init = zylonite_wm9713_init,
 },
@@ -175,7 +175,7 @@ static struct snd_soc_dai_link zylonite_dai[] = {
        .stream_name = "AC97 Aux",
        .codec_name = "wm9713-codec",
        .platform_name = "pxa-pcm-audio",
-       .cpu_dai_name = "pxa-ac97.1",
+       .cpu_dai_name = "pxa2xx-ac97-aux",
        .codec_name = "wm9713-aux",
 },
 {
index 3eec610..0d0ae2b 100644 (file)
@@ -397,11 +397,11 @@ static struct snd_soc_dai_link neo1973_gta02_dai[] = {
 { /* Hifi Playback - for similatious use with voice below */
        .name = "WM8753",
        .stream_name = "WM8753 HiFi",
-       .cpu_dai_name = "s3c24xx-i2s",
+       .cpu_dai_name = "s3c24xx-iis",
        .codec_dai_name = "wm8753-hifi",
        .init = neo1973_gta02_wm8753_init,
        .platform_name = "samsung-audio",
-       .codec_name = "wm8753-codec.0-0x1a",
+       .codec_name = "wm8753-codec.0-001a",
        .ops = &neo1973_gta02_hifi_ops,
 },
 { /* Voice via BT */
@@ -410,7 +410,7 @@ static struct snd_soc_dai_link neo1973_gta02_dai[] = {
        .cpu_dai_name = "bluetooth-dai",
        .codec_dai_name = "wm8753-voice",
        .ops = &neo1973_gta02_voice_ops,
-       .codec_name = "wm8753-codec.0-0x1a",
+       .codec_name = "wm8753-codec.0-001a",
        .platform_name = "samsung-audio",
 },
 };
index c7a2451..d20815d 100644 (file)
@@ -559,9 +559,9 @@ static struct snd_soc_dai_link neo1973_dai[] = {
        .name = "WM8753",
        .stream_name = "WM8753 HiFi",
        .platform_name = "samsung-audio",
-       .cpu_dai_name = "s3c24xx-i2s",
+       .cpu_dai_name = "s3c24xx-iis",
        .codec_dai_name = "wm8753-hifi",
-       .codec_name = "wm8753-codec.0-0x1a",
+       .codec_name = "wm8753-codec.0-001a",
        .init = neo1973_wm8753_init,
        .ops = &neo1973_hifi_ops,
 },
@@ -571,7 +571,7 @@ static struct snd_soc_dai_link neo1973_dai[] = {
        .platform_name = "samsung-audio",
        .cpu_dai_name = "bluetooth-dai",
        .codec_dai_name = "wm8753-voice",
-       .codec_name = "wm8753-codec.0-0x1a",
+       .codec_name = "wm8753-codec.0-001a",
        .ops = &neo1973_voice_ops,
 },
 };
index bb4292e..08fcaaa 100644 (file)
@@ -94,8 +94,8 @@ static int simtec_hermes_init(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_dai_link simtec_dai_aic33 = {
        .name           = "tlv320aic33",
        .stream_name    = "TLV320AIC33",
-       .codec_name     = "tlv320aic3x-codec.0-0x1a",
-       .cpu_dai_name   = "s3c24xx-i2s",
+       .codec_name     = "tlv320aic3x-codec.0-001a",
+       .cpu_dai_name   = "s3c24xx-iis",
        .codec_dai_name = "tlv320aic3x-hifi",
        .platform_name  = "samsung-audio",
        .init           = simtec_hermes_init,
index fbba4e3..116e3e6 100644 (file)
@@ -85,8 +85,8 @@ static int simtec_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_dai_link simtec_dai_aic23 = {
        .name           = "tlv320aic23",
        .stream_name    = "TLV320AIC23",
-       .codec_name     = "tlv320aic3x-codec.0-0x1a",
-       .cpu_dai_name   = "s3c24xx-i2s",
+       .codec_name     = "tlv320aic3x-codec.0-001a",
+       .cpu_dai_name   = "s3c24xx-iis",
        .codec_dai_name = "tlv320aic3x-hifi",
        .platform_name  = "samsung-audio",
        .init           = simtec_tlv320aic23_init,
index cdc8ecb..2c09e93 100644 (file)
@@ -228,7 +228,7 @@ static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
        .stream_name = "UDA134X",
        .codec_name = "uda134x-hifi",
        .codec_dai_name = "uda134x-hifi",
-       .cpu_dai_name = "s3c24xx-i2s",
+       .cpu_dai_name = "s3c24xx-iis",
        .ops = &s3c24xx_uda134x_ops,
        .platform_name  = "samsung-audio",
 };
index bac7291..c3f6f1e 100644 (file)
@@ -1449,6 +1449,7 @@ static int soc_post_component_init(struct snd_soc_card *card,
                rtd = &card->rtd_aux[num];
                name = aux_dev->name;
        }
+       rtd->card = card;
 
        /* machine controls, routes and widgets are not prefixed */
        temp = codec->name_prefix;
@@ -1471,7 +1472,6 @@ static int soc_post_component_init(struct snd_soc_card *card,
 
        /* register the rtd device */
        rtd->codec = codec;
-       rtd->card = card;
        rtd->dev.parent = card->dev;
        rtd->dev.release = rtd_release;
        rtd->dev.init_name = name;
@@ -1664,9 +1664,6 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
        goto out;
 
 found:
-       if (!try_module_get(codec->dev->driver->owner))
-               return -ENODEV;
-
        ret = soc_probe_codec(card, codec);
        if (ret < 0)
                return ret;
index 499730a..1790f83 100644 (file)
@@ -712,7 +712,15 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
                    !path->connected(path->source, path->sink))
                        continue;
 
-               if (path->sink && path->sink->power_check &&
+               if (!path->sink)
+                       continue;
+
+               if (path->sink->force) {
+                       power = 1;
+                       break;
+               }
+
+               if (path->sink->power_check &&
                    path->sink->power_check(path->sink)) {
                        power = 1;
                        break;
@@ -933,7 +941,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
        }
 
        if (!list_empty(&pending))
-               dapm_seq_run_coalesced(dapm, &pending);
+               dapm_seq_run_coalesced(cur_dapm, &pending);
 }
 
 static void dapm_widget_update(struct snd_soc_dapm_context *dapm)
@@ -1627,6 +1635,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
 int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
 {
        struct snd_soc_dapm_widget *w;
+       unsigned int val;
 
        list_for_each_entry(w, &dapm->card->widgets, list)
        {
@@ -1675,6 +1684,18 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
                case snd_soc_dapm_post:
                        break;
                }
+
+               /* Read the initial power state from the device */
+               if (w->reg >= 0) {
+                       val = snd_soc_read(w->codec, w->reg);
+                       val &= 1 << w->shift;
+                       if (w->invert)
+                               val = !val;
+
+                       if (val)
+                               w->power = 1;
+               }
+
                w->new = 1;
        }
 
@@ -1742,7 +1763,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
        int max = mc->max;
        unsigned int mask = (1 << fls(max)) - 1;
        unsigned int invert = mc->invert;
-       unsigned int val, val_mask;
+       unsigned int val;
        int connect, change;
        struct snd_soc_dapm_update update;
 
@@ -1750,13 +1771,13 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
 
        if (invert)
                val = max - val;
-       val_mask = mask << shift;
+       mask = mask << shift;
        val = val << shift;
 
        mutex_lock(&widget->codec->mutex);
        widget->value = val;
 
-       change = snd_soc_test_bits(widget->codec, reg, val_mask, val);
+       change = snd_soc_test_bits(widget->codec, reg, mask, val);
        if (change) {
                if (val)
                        /* new connection */
index 68b9747..66eabaf 100644 (file)
@@ -785,7 +785,7 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev)
        }
 
        dev->pcm->private_data = dev;
-       strcpy(dev->pcm->name, dev->product_name);
+       strlcpy(dev->pcm->name, dev->product_name, sizeof(dev->pcm->name));
 
        memset(dev->sub_playback, 0, sizeof(dev->sub_playback));
        memset(dev->sub_capture, 0, sizeof(dev->sub_capture));
index 2f218c7..a1a4708 100644 (file)
@@ -136,7 +136,7 @@ int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device)
        if (ret < 0)
                return ret;
 
-       strcpy(rmidi->name, device->product_name);
+       strlcpy(rmidi->name, device->product_name, sizeof(rmidi->name));
 
        rmidi->info_flags = SNDRV_RAWMIDI_INFO_DUPLEX;
        rmidi->private_data = device;
index 800f7cb..c0f8270 100644 (file)
@@ -323,6 +323,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
                return -ENOMEM;
        }
 
+       mutex_init(&chip->shutdown_mutex);
        chip->index = idx;
        chip->dev = dev;
        chip->card = card;
@@ -531,6 +532,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
        chip = ptr;
        card = chip->card;
        mutex_lock(&register_mutex);
+       mutex_lock(&chip->shutdown_mutex);
        chip->shutdown = 1;
        chip->num_interfaces--;
        if (chip->num_interfaces <= 0) {
@@ -548,9 +550,11 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
                        snd_usb_mixer_disconnect(p);
                }
                usb_chip[chip->index] = NULL;
+               mutex_unlock(&chip->shutdown_mutex);
                mutex_unlock(&register_mutex);
                snd_card_free_when_closed(card);
        } else {
+               mutex_unlock(&chip->shutdown_mutex);
                mutex_unlock(&register_mutex);
        }
 }
index 7df89b3..85af605 100644 (file)
@@ -95,7 +95,7 @@ enum {
 };
 
 
-/*E-mu 0202(0404) eXtension Unit(XU) control*/
+/*E-mu 0202/0404/0204 eXtension Unit(XU) control*/
 enum {
        USB_XU_CLOCK_RATE               = 0xe301,
        USB_XU_CLOCK_SOURCE             = 0xe302,
@@ -1566,7 +1566,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw
                        cval->initialized = 1;
                } else {
                        if (type == USB_XU_CLOCK_RATE) {
-                               /* E-Mu USB 0404/0202/TrackerPre
+                               /* E-Mu USB 0404/0202/TrackerPre/0204
                                 * samplerate control quirk
                                 */
                                cval->min = 0;
index 4132522..e3f6805 100644 (file)
@@ -361,6 +361,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
        }
 
        if (changed) {
+               mutex_lock(&subs->stream->chip->shutdown_mutex);
                /* format changed */
                snd_usb_release_substream_urbs(subs, 0);
                /* influenced: period_bytes, channels, rate, format, */
@@ -368,6 +369,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
                                                  params_rate(hw_params),
                                                  snd_pcm_format_physical_width(params_format(hw_params)) *
                                                        params_channels(hw_params));
+               mutex_unlock(&subs->stream->chip->shutdown_mutex);
        }
 
        return ret;
@@ -385,8 +387,9 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
        subs->cur_audiofmt = NULL;
        subs->cur_rate = 0;
        subs->period_bytes = 0;
-       if (!subs->stream->chip->shutdown)
-               snd_usb_release_substream_urbs(subs, 0);
+       mutex_lock(&subs->stream->chip->shutdown_mutex);
+       snd_usb_release_substream_urbs(subs, 0);
+       mutex_unlock(&subs->stream->chip->shutdown_mutex);
        return snd_pcm_lib_free_vmalloc_buffer(substream);
 }
 
index 3599987..921a86f 100644 (file)
        .idProduct = 0x3f0a,
        .bInterfaceClass = USB_CLASS_AUDIO,
 },
+{
+       /* E-Mu 0204 USB */
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+       .idVendor = 0x041e,
+       .idProduct = 0x3f19,
+       .bInterfaceClass = USB_CLASS_AUDIO,
+},
 
 /*
  * Logitech QuickCam: bDeviceClass is vendor-specific, so generic interface
index cf8bf08..e314cdb 100644 (file)
@@ -532,7 +532,7 @@ int snd_usb_is_big_endian_format(struct snd_usb_audio *chip, struct audioformat
 }
 
 /*
- * For E-Mu 0404USB/0202USB/TrackerPre sample rate should be set for device,
+ * For E-Mu 0404USB/0202USB/TrackerPre/0204 sample rate should be set for device,
  * not for interface.
  */
 
@@ -589,6 +589,7 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
        case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */
        case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */
        case USB_ID(0x041e, 0x3f0a): /* E-Mu Tracker Pre */
+       case USB_ID(0x041e, 0x3f19): /* E-Mu 0204 USB */
                set_format_emu_quirk(subs, fmt);
                break;
        }
index db3eb21..6e66fff 100644 (file)
@@ -36,6 +36,7 @@ struct snd_usb_audio {
        struct snd_card *card;
        u32 usb_id;
        int shutdown;
+       struct mutex shutdown_mutex;
        unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */
        int num_interfaces;
        int num_suspended_intf;
index cb43289..416684b 100644 (file)
@@ -1,4 +1,3 @@
-PERF-BUILD-OPTIONS
 PERF-CFLAGS
 PERF-GUI-VARS
 PERF-VERSION-FILE
index bd498d4..4626a39 100644 (file)
@@ -178,8 +178,8 @@ install-pdf: pdf
        $(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir)
        $(INSTALL) -m 644 user-manual.pdf $(DESTDIR)$(pdfdir)
 
-install-html: html
-       '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir)
+#install-html: html
+#      '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir)
 
 ../PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
        $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) PERF-VERSION-FILE
@@ -288,15 +288,16 @@ $(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt
        sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b xhtml11 - >$@+ && \
        mv $@+ $@
 
-install-webdoc : html
-       '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(WEBDOC_DEST)
+# UNIMPLEMENTED
+#install-webdoc : html
+#      '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(WEBDOC_DEST)
 
-quick-install: quick-install-man
+quick-install: quick-install-man
 
-quick-install-man:
-       '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(DOC_REF) $(DESTDIR)$(mandir)
+quick-install-man:
+#      '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(DOC_REF) $(DESTDIR)$(mandir)
 
-quick-install-html:
-       '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir)
+#quick-install-html:
+#      '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir)
 
 .PHONY: .FORCE-PERF-VERSION-FILE
index 399751b..7a527f7 100644 (file)
@@ -8,7 +8,7 @@ perf-list - List all symbolic event types
 SYNOPSIS
 --------
 [verse]
-'perf list'
+'perf list' [hw|sw|cache|tracepoint|event_glob]
 
 DESCRIPTION
 -----------
@@ -63,7 +63,26 @@ details. Some of them are referenced in the SEE ALSO section below.
 
 OPTIONS
 -------
-None
+
+Without options all known events will be listed.
+
+To limit the list use:
+
+. 'hw' or 'hardware' to list hardware events such as cache-misses, etc.
+
+. 'sw' or 'software' to list software events such as context switches, etc.
+
+. 'cache' or 'hwcache' to list hardware cache events such as L1-dcache-loads, etc.
+
+. 'tracepoint' to list all tracepoint events, alternatively use
+  'subsys_glob:event_glob' to filter by tracepoint subsystems such as sched,
+  block, etc.
+
+. If none of the above is matched, it will apply the supplied glob to all
+  events, printing the ones that match.
+
+One or more types can be used at the same time, listing the events for the
+types specified.
 
 SEE ALSO
 --------
index 921de25..4a26a2f 100644 (file)
@@ -24,8 +24,8 @@ and statistics with this 'perf lock' command.
 
   'perf lock report' reports statistical data.
 
-OPTIONS
--------
+COMMON OPTIONS
+--------------
 
 -i::
 --input=<file>::
@@ -39,6 +39,14 @@ OPTIONS
 --dump-raw-trace::
         Dump raw trace in ASCII.
 
+REPORT OPTIONS
+--------------
+
+-k::
+--key=<value>::
+        Sorting key. Possible values: acquired (default), contended,
+        wait_total, wait_max, wait_min.
+
 SEE ALSO
 --------
 linkperf:perf[1]
index 86b797a..02bafce 100644 (file)
@@ -16,7 +16,7 @@ or
 or
 'perf probe' --list
 or
-'perf probe' [options] --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
+'perf probe' [options] --line='LINE'
 or
 'perf probe' [options] --vars='PROBEPOINT'
 
@@ -73,6 +73,17 @@ OPTIONS
        (Only for --vars) Show external defined variables in addition to local
        variables.
 
+-F::
+--funcs::
+       Show available functions in given module or kernel.
+
+--filter=FILTER::
+       (Only for --vars and --funcs) Set filter. FILTER is a combination of glob
+       pattern, see FILTER PATTERN for detail.
+       Default FILTER is "!__k???tab_* & !__crc_*" for --vars, and "!_*"
+       for --funcs.
+       If several filters are specified, only the last filter is used.
+
 -f::
 --force::
        Forcibly add events with existing name.
@@ -117,13 +128,14 @@ LINE SYNTAX
 -----------
 Line range is described by following syntax.
 
- "FUNC[:RLN[+NUM|-RLN2]]|SRC[:ALN[+NUM|-ALN2]]"
+ "FUNC[@SRC][:RLN[+NUM|-RLN2]]|SRC[:ALN[+NUM|-ALN2]]"
 
 FUNC specifies the function name of showing lines. 'RLN' is the start line
 number from function entry line, and 'RLN2' is the end line number. As same as
 probe syntax, 'SRC' means the source file path, 'ALN' is start line number,
 and 'ALN2' is end line number in the file. It is also possible to specify how
-many lines to show by using 'NUM'.
+many lines to show by using 'NUM'. Moreover, 'FUNC@SRC' combination is good
+for searching a specific function when several functions share same name.
 So, "source.c:100-120" shows lines between 100th to l20th in source.c file. And "func:10+20" shows 20 lines from 10th line of func function.
 
 LAZY MATCHING
@@ -135,6 +147,14 @@ e.g.
 
 This provides some sort of flexibility and robustness to probe point definitions against minor code changes. For example, actual 10th line of schedule() can be moved easily by modifying schedule(), but the same line matching 'rq=cpu_rq*' may still exist in the function.)
 
+FILTER PATTERN
+--------------
+ The filter pattern is a glob matching pattern(s) to filter variables.
+ In addition, you can use "!" for specifying filter-out rule. You also can give several rules combined with "&" or "|", and fold those rules as one rule by using "(" ")".
+
+e.g.
+ With --filter "foo* | bar*", perf probe -V shows variables which start with "foo" or "bar".
+ With --filter "!foo* & *bar", perf probe -V shows variables which don't start with "foo" and end with "bar", like "fizzbar". But "foobar" is filtered out.
 
 EXAMPLES
 --------
index e032716..5a520f8 100644 (file)
@@ -137,6 +137,17 @@ Do not update the builid cache. This saves some overhead in situations
 where the information in the perf.data file (which includes buildids)
 is sufficient.
 
+-G name,...::
+--cgroup name,...::
+monitor only in the container (cgroup) called "name". This option is available only
+in per-cpu mode. The cgroup filesystem must be mounted. All threads belonging to
+container "name" are monitored when they run on the monitored CPUs. Multiple cgroups
+can be provided. Each cgroup is applied to the corresponding event, i.e., first cgroup
+to first event, second cgroup to second event and so on. It is possible to provide
+an empty cgroup (monitor all the time) using, e.g., -G foo,,bar. Cgroups must have
+corresponding events, i.e., they always refer to events defined earlier on the command
+line.
+
 SEE ALSO
 --------
 linkperf:perf-stat[1], linkperf:perf-list[1]
index b6da7af..918cc38 100644 (file)
@@ -83,6 +83,17 @@ This option is only valid in system-wide mode.
 print counts using a CSV-style output to make it easy to import directly into
 spreadsheets. Columns are separated by the string specified in SEP.
 
+-G name::
+--cgroup name::
+monitor only in the container (cgroup) called "name". This option is available only
+in per-cpu mode. The cgroup filesystem must be mounted. All threads belonging to
+container "name" are monitored when they run on the monitored CPUs. Multiple cgroups
+can be provided. Each cgroup is applied to the corresponding event, i.e., first cgroup
+to first event, second cgroup to second event and so on. It is possible to provide
+an empty cgroup (monitor all the time) using, e.g., -G foo,,bar. Cgroups must have
+corresponding events, i.e., they always refer to events defined earlier on the command
+line.
+
 EXAMPLES
 --------
 
index 7141c42..9b84218 100644 (file)
@@ -3,7 +3,7 @@ ifeq ("$(origin O)", "command line")
 endif
 
 # The default target of this Makefile is...
-all::
+all:
 
 ifneq ($(OUTPUT),)
 # check that the output directory actually exists
@@ -11,152 +11,12 @@ OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
 $(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
 endif
 
-# Define V=1 to have a more verbose compile.
-# Define V=2 to have an even more verbose compile.
-#
-# Define SNPRINTF_RETURNS_BOGUS if your are on a system which snprintf()
-# or vsnprintf() return -1 instead of number of characters which would
-# have been written to the final string if enough space had been available.
-#
-# Define FREAD_READS_DIRECTORIES if your are on a system which succeeds
-# when attempting to read from an fopen'ed directory.
-#
-# Define NO_OPENSSL environment variable if you do not have OpenSSL.
-# This also implies MOZILLA_SHA1.
-#
-# Define CURLDIR=/foo/bar if your curl header and library files are in
-# /foo/bar/include and /foo/bar/lib directories.
-#
-# Define EXPATDIR=/foo/bar if your expat header and library files are in
-# /foo/bar/include and /foo/bar/lib directories.
-#
-# Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent.
-#
-# Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks
-# d_type in struct dirent (latest Cygwin -- will be fixed soonish).
-#
-# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.)
-# do not support the 'size specifiers' introduced by C99, namely ll, hh,
-# j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t).
-# some C compilers supported these specifiers prior to C99 as an extension.
-#
-# Define NO_STRCASESTR if you don't have strcasestr.
-#
-# Define NO_MEMMEM if you don't have memmem.
-#
-# Define NO_STRTOUMAX if you don't have strtoumax in the C library.
-# If your compiler also does not support long long or does not have
-# strtoull, define NO_STRTOULL.
-#
-# Define NO_SETENV if you don't have setenv in the C library.
-#
-# Define NO_UNSETENV if you don't have unsetenv in the C library.
-#
-# Define NO_MKDTEMP if you don't have mkdtemp in the C library.
-#
-# Define NO_SYS_SELECT_H if you don't have sys/select.h.
-#
-# Define NO_SYMLINK_HEAD if you never want .perf/HEAD to be a symbolic link.
-# Enable it on Windows.  By default, symrefs are still used.
-#
-# Define NO_SVN_TESTS if you want to skip time-consuming SVN interoperability
-# tests.  These tests take up a significant amount of the total test time
-# but are not needed unless you plan to talk to SVN repos.
-#
-# Define NO_FINK if you are building on Darwin/Mac OS X, have Fink
-# installed in /sw, but don't want PERF to link against any libraries
-# installed there.  If defined you may specify your own (or Fink's)
-# include directories and library directories by defining CFLAGS
-# and LDFLAGS appropriately.
-#
-# Define NO_DARWIN_PORTS if you are building on Darwin/Mac OS X,
-# have DarwinPorts installed in /opt/local, but don't want PERF to
-# link against any libraries installed there.  If defined you may
-# specify your own (or DarwinPort's) include directories and
-# library directories by defining CFLAGS and LDFLAGS appropriately.
-#
-# Define PPC_SHA1 environment variable when running make to make use of
-# a bundled SHA1 routine optimized for PowerPC.
-#
-# Define ARM_SHA1 environment variable when running make to make use of
-# a bundled SHA1 routine optimized for ARM.
-#
-# Define MOZILLA_SHA1 environment variable when running make to make use of
-# a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast
-# on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default
-# choice) has very fast version optimized for i586.
-#
-# Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin).
-#
-# Define NEEDS_LIBICONV if linking with libc is not enough (Darwin).
-#
-# Define NEEDS_SOCKET if linking with libc is not enough (SunOS,
-# Patrick Mauritz).
-#
-# Define NO_MMAP if you want to avoid mmap.
-#
-# Define NO_PTHREADS if you do not have or do not want to use Pthreads.
-#
-# Define NO_PREAD if you have a problem with pread() system call (e.g.
-# cygwin.dll before v1.5.22).
-#
-# Define NO_FAST_WORKING_DIRECTORY if accessing objects in pack files is
-# generally faster on your platform than accessing the working directory.
-#
-# Define NO_TRUSTABLE_FILEMODE if your filesystem may claim to support
-# the executable mode bit, but doesn't really do so.
-#
-# Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
-#
-# Define NO_SOCKADDR_STORAGE if your platform does not have struct
-# sockaddr_storage.
-#
-# Define NO_ICONV if your libc does not properly support iconv.
-#
-# Define OLD_ICONV if your library has an old iconv(), where the second
-# (input buffer pointer) parameter is declared with type (const char **).
-#
-# Define NO_DEFLATE_BOUND if your zlib does not have deflateBound.
-#
-# Define NO_R_TO_GCC_LINKER if your gcc does not like "-R/path/lib"
-# that tells runtime paths to dynamic libraries;
-# "-Wl,-rpath=/path/lib" is used instead.
-#
-# Define USE_NSEC below if you want perf to care about sub-second file mtimes
-# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and
-# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely
-# randomly break unless your underlying filesystem supports those sub-second
-# times (my ext3 doesn't).
-#
-# Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of
-# "st_ctim"
-#
-# Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec"
-# available.  This automatically turns USE_NSEC off.
-#
-# Define USE_STDEV below if you want perf to care about the underlying device
-# change being considered an inode change from the update-index perspective.
-#
-# Define NO_ST_BLOCKS_IN_STRUCT_STAT if your platform does not have st_blocks
-# field that counts the on-disk footprint in 512-byte blocks.
+# Define V to have a more verbose compile.
 #
 # Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8
 #
 # Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72.
 #
-# Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's
-# MakeMaker (e.g. using ActiveState under Cygwin).
-#
-# Define NO_PERL if you do not want Perl scripts or libraries at all.
-#
-# Define INTERNAL_QSORT to use Git's implementation of qsort(), which
-# is a simplified version of the merge sort used in glibc. This is
-# recommended if Git triggers O(n^2) behavior in your platform's qsort().
-#
-# Define NO_EXTERNAL_GREP if you don't want "perf grep" to ever call
-# your external grep (e.g., if your system lacks grep, if its grep is
-# broken, or spawning external process is slower than built-in grep perf has).
-#
 # Define LDFLAGS=-static to build a static binary.
 #
 # Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.
@@ -167,12 +27,7 @@ $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
        @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
 -include $(OUTPUT)PERF-VERSION-FILE
 
-uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
-uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo not')
-uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not')
-uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
-uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not')
-uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not')
+uname_M := $(shell uname -m 2>/dev/null || echo not)
 
 ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
                                  -e s/arm.*/arm/ -e s/sa110/arm/ \
@@ -191,8 +46,6 @@ ifeq ($(ARCH),x86_64)
        ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S
 endif
 
-# CFLAGS and LDFLAGS are for the users to override from the command line.
-
 #
 # Include saner warnings here, which can catch bugs:
 #
@@ -270,22 +123,13 @@ CC = $(CROSS_COMPILE)gcc
 AR = $(CROSS_COMPILE)ar
 RM = rm -f
 MKDIR = mkdir
-TAR = tar
 FIND = find
 INSTALL = install
-RPMBUILD = rpmbuild
-PTHREAD_LIBS = -lpthread
 
 # sparse is architecture-neutral, which means that we need to tell it
 # explicitly what architecture to check for. Fix this up for yours..
 SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
 
-ifeq ($(V), 2)
-       QUIET_STDERR = ">/dev/null"
-else
-       QUIET_STDERR = ">/dev/null 2>&1"
-endif
-
 -include feature-tests.mak
 
 ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y)
@@ -310,49 +154,37 @@ BASIC_LDFLAGS =
 
 # Guard against environment variables
 BUILTIN_OBJS =
-BUILT_INS =
-COMPAT_CFLAGS =
-COMPAT_OBJS =
 LIB_H =
 LIB_OBJS =
-SCRIPT_PERL =
+PYRF_OBJS =
 SCRIPT_SH =
-TEST_PROGRAMS =
 
 SCRIPT_SH += perf-archive.sh
 
 grep-libs = $(filter -l%,$(1))
 strip-libs = $(filter-out -l%,$(1))
 
+$(OUTPUT)python/perf.so: $(PYRF_OBJS)
+       $(QUIET_GEN)python util/setup.py --quiet  build_ext --build-lib='$(OUTPUT)python' \
+                                               --build-temp='$(OUTPUT)python/temp'
 #
 # No Perl scripts right now:
 #
 
-# SCRIPT_PERL += perf-add--interactive.perl
-
-SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
-         $(patsubst %.perl,%,$(SCRIPT_PERL))
-
-# Empty...
-EXTRA_PROGRAMS =
-
-# ... and all the rest that could be moved out of bindir to perfexecdir
-PROGRAMS += $(EXTRA_PROGRAMS)
+SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
 
 #
 # Single 'perf' binary right now:
 #
 PROGRAMS += $(OUTPUT)perf
 
-# List built-in command $C whose implementation cmd_$C() is not in
-# builtin-$C.o but is linked in as part of some other command.
-#
+LANG_BINDINGS =
 
 # what 'all' will build and 'install' will install, in perfexecdir
 ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
 
 # what 'all' will build but not install in perfexecdir
-OTHER_PROGRAMS = $(OUTPUT)perf$X
+OTHER_PROGRAMS = $(OUTPUT)perf
 
 # Set paths to tools early so that they can be used for version tests.
 ifndef SHELL_PATH
@@ -395,6 +227,7 @@ LIB_H += util/include/dwarf-regs.h
 LIB_H += util/include/asm/dwarf2.h
 LIB_H += util/include/asm/cpufeature.h
 LIB_H += perf.h
+LIB_H += util/annotate.h
 LIB_H += util/cache.h
 LIB_H += util/callchain.h
 LIB_H += util/build-id.h
@@ -402,6 +235,7 @@ LIB_H += util/debug.h
 LIB_H += util/debugfs.h
 LIB_H += util/event.h
 LIB_H += util/evsel.h
+LIB_H += util/evlist.h
 LIB_H += util/exec_cmd.h
 LIB_H += util/types.h
 LIB_H += util/levenshtein.h
@@ -416,6 +250,7 @@ LIB_H += util/help.h
 LIB_H += util/session.h
 LIB_H += util/strbuf.h
 LIB_H += util/strlist.h
+LIB_H += util/strfilter.h
 LIB_H += util/svghelper.h
 LIB_H += util/run-command.h
 LIB_H += util/sigchain.h
@@ -425,21 +260,26 @@ LIB_H += util/values.h
 LIB_H += util/sort.h
 LIB_H += util/hist.h
 LIB_H += util/thread.h
+LIB_H += util/thread_map.h
 LIB_H += util/trace-event.h
 LIB_H += util/probe-finder.h
 LIB_H += util/probe-event.h
 LIB_H += util/pstack.h
 LIB_H += util/cpumap.h
+LIB_H += util/top.h
 LIB_H += $(ARCH_INCLUDE)
+LIB_H += util/cgroup.h
 
 LIB_OBJS += $(OUTPUT)util/abspath.o
 LIB_OBJS += $(OUTPUT)util/alias.o
+LIB_OBJS += $(OUTPUT)util/annotate.o
 LIB_OBJS += $(OUTPUT)util/build-id.o
 LIB_OBJS += $(OUTPUT)util/config.o
 LIB_OBJS += $(OUTPUT)util/ctype.o
 LIB_OBJS += $(OUTPUT)util/debugfs.o
 LIB_OBJS += $(OUTPUT)util/environment.o
 LIB_OBJS += $(OUTPUT)util/event.o
+LIB_OBJS += $(OUTPUT)util/evlist.o
 LIB_OBJS += $(OUTPUT)util/evsel.o
 LIB_OBJS += $(OUTPUT)util/exec_cmd.o
 LIB_OBJS += $(OUTPUT)util/help.o
@@ -455,6 +295,8 @@ LIB_OBJS += $(OUTPUT)util/quote.o
 LIB_OBJS += $(OUTPUT)util/strbuf.o
 LIB_OBJS += $(OUTPUT)util/string.o
 LIB_OBJS += $(OUTPUT)util/strlist.o
+LIB_OBJS += $(OUTPUT)util/strfilter.o
+LIB_OBJS += $(OUTPUT)util/top.o
 LIB_OBJS += $(OUTPUT)util/usage.o
 LIB_OBJS += $(OUTPUT)util/wrapper.o
 LIB_OBJS += $(OUTPUT)util/sigchain.o
@@ -469,6 +311,7 @@ LIB_OBJS += $(OUTPUT)util/map.o
 LIB_OBJS += $(OUTPUT)util/pstack.o
 LIB_OBJS += $(OUTPUT)util/session.o
 LIB_OBJS += $(OUTPUT)util/thread.o
+LIB_OBJS += $(OUTPUT)util/thread_map.o
 LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
 LIB_OBJS += $(OUTPUT)util/trace-event-read.o
 LIB_OBJS += $(OUTPUT)util/trace-event-info.o
@@ -480,6 +323,7 @@ LIB_OBJS += $(OUTPUT)util/probe-event.o
 LIB_OBJS += $(OUTPUT)util/util.o
 LIB_OBJS += $(OUTPUT)util/xyarray.o
 LIB_OBJS += $(OUTPUT)util/cpumap.o
+LIB_OBJS += $(OUTPUT)util/cgroup.o
 
 BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
 
@@ -514,6 +358,20 @@ BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
 
 PERFLIBS = $(LIB_FILE)
 
+# Files needed for the python binding, perf.so
+# pyrf is just an internal name needed for all those wrappers.
+# This has to be in sync with what is in the 'sources' variable in
+# tools/perf/util/setup.py
+
+PYRF_OBJS += $(OUTPUT)util/cpumap.o
+PYRF_OBJS += $(OUTPUT)util/ctype.o
+PYRF_OBJS += $(OUTPUT)util/evlist.o
+PYRF_OBJS += $(OUTPUT)util/evsel.o
+PYRF_OBJS += $(OUTPUT)util/python.o
+PYRF_OBJS += $(OUTPUT)util/thread_map.o
+PYRF_OBJS += $(OUTPUT)util/util.o
+PYRF_OBJS += $(OUTPUT)util/xyarray.o
+
 #
 # Platform specific tweaks
 #
@@ -535,22 +393,6 @@ endif # NO_DWARF
 
 -include arch/$(ARCH)/Makefile
 
-ifeq ($(uname_S),Darwin)
-       ifndef NO_FINK
-               ifeq ($(shell test -d /sw/lib && echo y),y)
-                       BASIC_CFLAGS += -I/sw/include
-                       BASIC_LDFLAGS += -L/sw/lib
-               endif
-       endif
-       ifndef NO_DARWIN_PORTS
-               ifeq ($(shell test -d /opt/local/lib && echo y),y)
-                       BASIC_CFLAGS += -I/opt/local/include
-                       BASIC_LDFLAGS += -L/opt/local/lib
-               endif
-       endif
-       PTHREAD_LIBS =
-endif
-
 ifneq ($(OUTPUT),)
        BASIC_CFLAGS += -I$(OUTPUT)
 endif
@@ -595,6 +437,7 @@ else
                LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o
                LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o
                LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o
+               LIB_OBJS += $(OUTPUT)util/ui/browsers/top.o
                LIB_OBJS += $(OUTPUT)util/ui/helpline.o
                LIB_OBJS += $(OUTPUT)util/ui/progress.o
                LIB_OBJS += $(OUTPUT)util/ui/util.o
@@ -604,6 +447,7 @@ else
                LIB_H += util/ui/libslang.h
                LIB_H += util/ui/progress.h
                LIB_H += util/ui/util.h
+               LIB_H += util/ui/ui.h
        endif
 endif
 
@@ -635,12 +479,14 @@ else
        PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null`
        FLAGS_PYTHON_EMBED=$(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
        ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y)
+               msg := $(warning No Python.h found, install python-dev[el] to have python support in 'perf script' and to build the python bindings)
                BASIC_CFLAGS += -DNO_LIBPYTHON
        else
                ALL_LDFLAGS += $(PYTHON_EMBED_LDFLAGS)
                EXTLIBS += $(PYTHON_EMBED_LIBADD)
                LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
                LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
+               LANG_BINDINGS += $(OUTPUT)python/perf.so
        endif
 endif
 
@@ -690,201 +536,13 @@ else
        endif
 endif
 
-ifndef CC_LD_DYNPATH
-       ifdef NO_R_TO_GCC_LINKER
-               # Some gcc does not accept and pass -R to the linker to specify
-               # the runtime dynamic library path.
-               CC_LD_DYNPATH = -Wl,-rpath,
-       else
-               CC_LD_DYNPATH = -R
-       endif
-endif
-
-ifdef NEEDS_SOCKET
-       EXTLIBS += -lsocket
-endif
-ifdef NEEDS_NSL
-       EXTLIBS += -lnsl
-endif
-ifdef NO_D_TYPE_IN_DIRENT
-       BASIC_CFLAGS += -DNO_D_TYPE_IN_DIRENT
-endif
-ifdef NO_D_INO_IN_DIRENT
-       BASIC_CFLAGS += -DNO_D_INO_IN_DIRENT
-endif
-ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
-       BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
-endif
-ifdef USE_NSEC
-       BASIC_CFLAGS += -DUSE_NSEC
-endif
-ifdef USE_ST_TIMESPEC
-       BASIC_CFLAGS += -DUSE_ST_TIMESPEC
-endif
-ifdef NO_NSEC
-       BASIC_CFLAGS += -DNO_NSEC
-endif
-ifdef NO_C99_FORMAT
-       BASIC_CFLAGS += -DNO_C99_FORMAT
-endif
-ifdef SNPRINTF_RETURNS_BOGUS
-       COMPAT_CFLAGS += -DSNPRINTF_RETURNS_BOGUS
-       COMPAT_OBJS += $(OUTPUT)compat/snprintf.o
-endif
-ifdef FREAD_READS_DIRECTORIES
-       COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES
-       COMPAT_OBJS += $(OUTPUT)compat/fopen.o
-endif
-ifdef NO_SYMLINK_HEAD
-       BASIC_CFLAGS += -DNO_SYMLINK_HEAD
-endif
-ifdef NO_STRCASESTR
-       COMPAT_CFLAGS += -DNO_STRCASESTR
-       COMPAT_OBJS += $(OUTPUT)compat/strcasestr.o
-endif
-ifdef NO_STRTOUMAX
-       COMPAT_CFLAGS += -DNO_STRTOUMAX
-       COMPAT_OBJS += $(OUTPUT)compat/strtoumax.o
-endif
-ifdef NO_STRTOULL
-       COMPAT_CFLAGS += -DNO_STRTOULL
-endif
-ifdef NO_SETENV
-       COMPAT_CFLAGS += -DNO_SETENV
-       COMPAT_OBJS += $(OUTPUT)compat/setenv.o
-endif
-ifdef NO_MKDTEMP
-       COMPAT_CFLAGS += -DNO_MKDTEMP
-       COMPAT_OBJS += $(OUTPUT)compat/mkdtemp.o
-endif
-ifdef NO_UNSETENV
-       COMPAT_CFLAGS += -DNO_UNSETENV
-       COMPAT_OBJS += $(OUTPUT)compat/unsetenv.o
-endif
-ifdef NO_SYS_SELECT_H
-       BASIC_CFLAGS += -DNO_SYS_SELECT_H
-endif
-ifdef NO_MMAP
-       COMPAT_CFLAGS += -DNO_MMAP
-       COMPAT_OBJS += $(OUTPUT)compat/mmap.o
-else
-       ifdef USE_WIN32_MMAP
-               COMPAT_CFLAGS += -DUSE_WIN32_MMAP
-               COMPAT_OBJS += $(OUTPUT)compat/win32mmap.o
-       endif
-endif
-ifdef NO_PREAD
-       COMPAT_CFLAGS += -DNO_PREAD
-       COMPAT_OBJS += $(OUTPUT)compat/pread.o
-endif
-ifdef NO_FAST_WORKING_DIRECTORY
-       BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY
-endif
-ifdef NO_TRUSTABLE_FILEMODE
-       BASIC_CFLAGS += -DNO_TRUSTABLE_FILEMODE
-endif
-ifdef NO_IPV6
-       BASIC_CFLAGS += -DNO_IPV6
-endif
-ifdef NO_UINTMAX_T
-       BASIC_CFLAGS += -Duintmax_t=uint32_t
-endif
-ifdef NO_SOCKADDR_STORAGE
-ifdef NO_IPV6
-       BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in
-else
-       BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in6
-endif
-endif
-ifdef NO_INET_NTOP
-       LIB_OBJS += $(OUTPUT)compat/inet_ntop.o
-endif
-ifdef NO_INET_PTON
-       LIB_OBJS += $(OUTPUT)compat/inet_pton.o
-endif
-
-ifdef NO_ICONV
-       BASIC_CFLAGS += -DNO_ICONV
-endif
-
-ifdef OLD_ICONV
-       BASIC_CFLAGS += -DOLD_ICONV
-endif
-
-ifdef NO_DEFLATE_BOUND
-       BASIC_CFLAGS += -DNO_DEFLATE_BOUND
-endif
-
-ifdef PPC_SHA1
-       SHA1_HEADER = "ppc/sha1.h"
-       LIB_OBJS += $(OUTPUT)ppc/sha1.o ppc/sha1ppc.o
-else
-ifdef ARM_SHA1
-       SHA1_HEADER = "arm/sha1.h"
-       LIB_OBJS += $(OUTPUT)arm/sha1.o $(OUTPUT)arm/sha1_arm.o
-else
-ifdef MOZILLA_SHA1
-       SHA1_HEADER = "mozilla-sha1/sha1.h"
-       LIB_OBJS += $(OUTPUT)mozilla-sha1/sha1.o
-else
-       SHA1_HEADER = <openssl/sha.h>
-       EXTLIBS += $(LIB_4_CRYPTO)
-endif
-endif
-endif
-ifdef NO_PERL_MAKEMAKER
-       export NO_PERL_MAKEMAKER
-endif
-ifdef NO_HSTRERROR
-       COMPAT_CFLAGS += -DNO_HSTRERROR
-       COMPAT_OBJS += $(OUTPUT)compat/hstrerror.o
-endif
-ifdef NO_MEMMEM
-       COMPAT_CFLAGS += -DNO_MEMMEM
-       COMPAT_OBJS += $(OUTPUT)compat/memmem.o
-endif
-ifdef INTERNAL_QSORT
-       COMPAT_CFLAGS += -DINTERNAL_QSORT
-       COMPAT_OBJS += $(OUTPUT)compat/qsort.o
-endif
-ifdef RUNTIME_PREFIX
-       COMPAT_CFLAGS += -DRUNTIME_PREFIX
-endif
-
-ifdef DIR_HAS_BSD_GROUP_SEMANTICS
-       COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS
-endif
-ifdef NO_EXTERNAL_GREP
-       BASIC_CFLAGS += -DNO_EXTERNAL_GREP
-endif
-
-ifeq ($(PERL_PATH),)
-NO_PERL=NoThanks
-endif
-
-QUIET_SUBDIR0  = +$(MAKE) -C # space to separate -C and subdir
-QUIET_SUBDIR1  =
-
-ifneq ($(findstring $(MAKEFLAGS),w),w)
-PRINT_DIR = --no-print-directory
-else # "make -w"
-NO_SUBDIR = :
-endif
-
 ifneq ($(findstring $(MAKEFLAGS),s),s)
 ifndef V
        QUIET_CC       = @echo '   ' CC $@;
        QUIET_AR       = @echo '   ' AR $@;
        QUIET_LINK     = @echo '   ' LINK $@;
        QUIET_MKDIR    = @echo '   ' MKDIR $@;
-       QUIET_BUILT_IN = @echo '   ' BUILTIN $@;
        QUIET_GEN      = @echo '   ' GEN $@;
-       QUIET_SUBDIR0  = +@subdir=
-       QUIET_SUBDIR1  = ;$(NO_SUBDIR) echo '   ' SUBDIR $$subdir; \
-                        $(MAKE) $(PRINT_DIR) -C $$subdir
-       export V
-       export QUIET_GEN
-       export QUIET_BUILT_IN
 endif
 endif
 
@@ -894,7 +552,6 @@ endif
 
 # Shell quote (do not use $(call) to accommodate ancient setups);
 
-SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER))
 ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
 
 DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
@@ -908,46 +565,36 @@ htmldir_SQ = $(subst ','\'',$(htmldir))
 prefix_SQ = $(subst ','\'',$(prefix))
 
 SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
-PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
 
 LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive $(EXTLIBS)
 
-BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \
-       $(COMPAT_CFLAGS)
-LIB_OBJS += $(COMPAT_OBJS)
-
 ALL_CFLAGS += $(BASIC_CFLAGS)
 ALL_CFLAGS += $(ARCH_CFLAGS)
 ALL_LDFLAGS += $(BASIC_LDFLAGS)
 
-export TAR INSTALL DESTDIR SHELL_PATH
+export INSTALL SHELL_PATH
 
 
 ### Build rules
 
 SHELL = $(SHELL_PATH)
 
-all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) $(OUTPUT)PERF-BUILD-OPTIONS
-ifneq (,$X)
-       $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';)
-endif
-
-all::
+all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS)
 
 please_set_SHELL_PATH_to_a_more_modern_shell:
        @$$(:)
 
 shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
 
-strip: $(PROGRAMS) $(OUTPUT)perf$X
-       $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf$X
+strip: $(PROGRAMS) $(OUTPUT)perf
+       $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf
 
 $(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
        $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \
                '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
                $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@
 
-$(OUTPUT)perf$X: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS)
+$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(OUTPUT)perf.o \
                $(BUILTIN_OBJS) $(LIBS) -o $@
 
@@ -963,39 +610,17 @@ $(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPU
                '-DPERF_MAN_PATH="$(mandir_SQ)"' \
                '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
 
-$(BUILT_INS): $(OUTPUT)perf$X
-       $(QUIET_BUILT_IN)$(RM) $@ && \
-       ln perf$X $@ 2>/dev/null || \
-       ln -s perf$X $@ 2>/dev/null || \
-       cp perf$X $@
-
 $(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt
 
 $(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt)
        $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@
 
-$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
-       $(QUIET_GEN)$(RM) $(OUTPUT)$@ $(OUTPUT)$@+ && \
-       sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
-           -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
-           -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
-           -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \
-           -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
-           $@.sh > $(OUTPUT)$@+ && \
-       chmod +x $(OUTPUT)$@+ && \
-       mv $(OUTPUT)$@+ $(OUTPUT)$@
-
-configure: configure.ac
-       $(QUIET_GEN)$(RM) $@ $<+ && \
-       sed -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \
-           $< > $<+ && \
-       autoconf -o $@ $<+ && \
-       $(RM) $<+
+$(SCRIPTS) : % : %.sh
+       $(QUIET_GEN)$(INSTALL) '$@.sh' '$(OUTPUT)$@'
 
 # These can record PERF_VERSION
 $(OUTPUT)perf.o perf.spec \
-       $(patsubst %.sh,%,$(SCRIPT_SH)) \
-       $(patsubst %.perl,%,$(SCRIPT_PERL)) \
+       $(SCRIPTS) \
        : $(OUTPUT)PERF-VERSION-FILE
 
 $(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
@@ -1012,9 +637,6 @@ $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
                '-DPREFIX="$(prefix_SQ)"' \
                $<
 
-$(OUTPUT)builtin-init-db.o: builtin-init-db.c $(OUTPUT)PERF-CFLAGS
-       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DDEFAULT_PERF_TEMPLATE_DIR='"$(template_dir_SQ)"' $<
-
 $(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
        $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
 
@@ -1024,6 +646,9 @@ $(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS
 $(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
        $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
 
+$(OUTPUT)util/ui/browsers/top.o: util/ui/browsers/top.c $(OUTPUT)PERF-CFLAGS
+       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
+
 $(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
        $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
 
@@ -1045,12 +670,11 @@ $(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/tra
 $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
        $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
 
-$(OUTPUT)perf-%$X: %.o $(PERFLIBS)
+$(OUTPUT)perf-%: %.o $(PERFLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
 
 $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
-$(patsubst perf-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
-builtin-revert.o wt-status.o: wt-status.h
+$(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
 
 # we compile into subdirectories. if the target directory is not the source directory, they might not exists. So
 # we depend the various files onto their directories.
@@ -1063,6 +687,36 @@ $(sort $(dir $(DIRECTORY_DEPS))):
 $(LIB_FILE): $(LIB_OBJS)
        $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
 
+help:
+       @echo 'Perf make targets:'
+       @echo '  doc            - make *all* documentation (see below)'
+       @echo '  man            - make manpage documentation (access with man <foo>)'
+       @echo '  html           - make html documentation'
+       @echo '  info           - make GNU info documentation (access with info <foo>)'
+       @echo '  pdf            - make pdf documentation'
+       @echo '  TAGS           - use etags to make tag information for source browsing'
+       @echo '  tags           - use ctags to make tag information for source browsing'
+       @echo '  cscope - use cscope to make interactive browsing database'
+       @echo ''
+       @echo 'Perf install targets:'
+       @echo '  NOTE: documentation build requires asciidoc, xmlto packages to be installed'
+       @echo '  HINT: use "make prefix=<path> <install target>" to install to a particular'
+       @echo '        path like make prefix=/usr/local install install-doc'
+       @echo '  install        - install compiled binaries'
+       @echo '  install-doc    - install *all* documentation'
+       @echo '  install-man    - install manpage documentation'
+       @echo '  install-html   - install html documentation'
+       @echo '  install-info   - install GNU info documentation'
+       @echo '  install-pdf    - install pdf documentation'
+       @echo ''
+       @echo '  quick-install-doc      - alias for quick-install-man'
+       @echo '  quick-install-man      - install the documentation quickly'
+       @echo '  quick-install-html     - install the html documentation quickly'
+       @echo ''
+       @echo 'Perf maintainer targets:'
+       @echo '  distclean              - alias to clean'
+       @echo '  clean                  - clean all binary objects and build output'
+
 doc:
        $(MAKE) -C Documentation all
 
@@ -1101,30 +755,12 @@ $(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
                echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \
             fi
 
-# We need to apply sq twice, once to protect from the shell
-# that runs $(OUTPUT)PERF-BUILD-OPTIONS, and then again to protect it
-# and the first level quoting from the shell that runs "echo".
-$(OUTPUT)PERF-BUILD-OPTIONS: .FORCE-PERF-BUILD-OPTIONS
-       @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@
-       @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
-       @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@
-       @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@
-
 ### Testing rules
 
-#
-# None right now:
-#
-# TEST_PROGRAMS += test-something$X
-
-all:: $(TEST_PROGRAMS)
-
 # GNU make supports exporting all variables by "export" without parameters.
 # However, the environment gets quite big, and some programs have problems
 # with that.
 
-export NO_SVN_TESTS
-
 check: $(OUTPUT)common-cmds.h
        if sparse; \
        then \
@@ -1133,33 +769,21 @@ check: $(OUTPUT)common-cmds.h
                        sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \
                done; \
        else \
-               echo 2>&1 "Did you mean 'make test'?"; \
                exit 1; \
        fi
 
-remove-dashes:
-       ./fixup-builtins $(BUILT_INS) $(PROGRAMS) $(SCRIPTS)
-
 ### Installation rules
 
-ifneq ($(filter /%,$(firstword $(template_dir))),)
-template_instdir = $(template_dir)
-else
-template_instdir = $(prefix)/$(template_dir)
-endif
-export template_instdir
-
 ifneq ($(filter /%,$(firstword $(perfexecdir))),)
 perfexec_instdir = $(perfexecdir)
 else
 perfexec_instdir = $(prefix)/$(perfexecdir)
 endif
 perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
-export perfexec_instdir
 
 install: all
        $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
-       $(INSTALL) $(OUTPUT)perf$X '$(DESTDIR_SQ)$(bindir_SQ)'
+       $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'
        $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
        $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
        $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
@@ -1172,14 +796,6 @@ install: all
        $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
        $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
 
-ifdef BUILT_INS
-       $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
-       $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
-ifneq (,$X)
-       $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) $(OUTPUT)perf$X)), $(RM) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$p';)
-endif
-endif
-
 install-doc:
        $(MAKE) -C Documentation install
 
@@ -1204,104 +820,17 @@ quick-install-man:
 quick-install-html:
        $(MAKE) -C Documentation quick-install-html
 
-
-### Maintainer's dist rules
-#
-# None right now
-#
-#
-# perf.spec: perf.spec.in
-#      sed -e 's/@@VERSION@@/$(PERF_VERSION)/g' < $< > $@+
-#      mv $@+ $@
-#
-# PERF_TARNAME=perf-$(PERF_VERSION)
-# dist: perf.spec perf-archive$(X) configure
-#      ./perf-archive --format=tar \
-#              --prefix=$(PERF_TARNAME)/ HEAD^{tree} > $(PERF_TARNAME).tar
-#      @mkdir -p $(PERF_TARNAME)
-#      @cp perf.spec configure $(PERF_TARNAME)
-#      @echo $(PERF_VERSION) > $(PERF_TARNAME)/version
-#      $(TAR) rf $(PERF_TARNAME).tar \
-#              $(PERF_TARNAME)/perf.spec \
-#              $(PERF_TARNAME)/configure \
-#              $(PERF_TARNAME)/version
-#      @$(RM) -r $(PERF_TARNAME)
-#      gzip -f -9 $(PERF_TARNAME).tar
-#
-# htmldocs = perf-htmldocs-$(PERF_VERSION)
-# manpages = perf-manpages-$(PERF_VERSION)
-# dist-doc:
-#      $(RM) -r .doc-tmp-dir
-#      mkdir .doc-tmp-dir
-#      $(MAKE) -C Documentation WEBDOC_DEST=../.doc-tmp-dir install-webdoc
-#      cd .doc-tmp-dir && $(TAR) cf ../$(htmldocs).tar .
-#      gzip -n -9 -f $(htmldocs).tar
-#      :
-#      $(RM) -r .doc-tmp-dir
-#      mkdir -p .doc-tmp-dir/man1 .doc-tmp-dir/man5 .doc-tmp-dir/man7
-#      $(MAKE) -C Documentation DESTDIR=./ \
-#              man1dir=../.doc-tmp-dir/man1 \
-#              man5dir=../.doc-tmp-dir/man5 \
-#              man7dir=../.doc-tmp-dir/man7 \
-#              install
-#      cd .doc-tmp-dir && $(TAR) cf ../$(manpages).tar .
-#      gzip -n -9 -f $(manpages).tar
-#      $(RM) -r .doc-tmp-dir
-#
-# rpm: dist
-#      $(RPMBUILD) -ta $(PERF_TARNAME).tar.gz
-
 ### Cleaning rules
 
-distclean: clean
-#      $(RM) configure
-
 clean:
-       $(RM) *.o */*.o */*/*.o */*/*/*.o $(LIB_FILE)
-       $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X
-       $(RM) $(TEST_PROGRAMS)
+       $(RM) $(OUTPUT){*.o,*/*.o,*/*/*.o,*/*/*/*.o,$(LIB_FILE),perf-archive}
+       $(RM) $(ALL_PROGRAMS) perf
        $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
-       $(RM) -r autom4te.cache
-       $(RM) config.log config.mak.autogen config.mak.append config.status config.cache
-       $(RM) -r $(PERF_TARNAME) .doc-tmp-dir
-       $(RM) $(PERF_TARNAME).tar.gz perf-core_$(PERF_VERSION)-*.tar.gz
-       $(RM) $(htmldocs).tar.gz $(manpages).tar.gz
        $(MAKE) -C Documentation/ clean
-       $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-BUILD-OPTIONS
+       $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS
+       @python util/setup.py clean --build-lib='$(OUTPUT)python' \
+                                  --build-temp='$(OUTPUT)python/temp'
 
 .PHONY: all install clean strip
 .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
 .PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
-.PHONY: .FORCE-PERF-BUILD-OPTIONS
-
-### Make sure built-ins do not have dups and listed in perf.c
-#
-check-builtins::
-       ./check-builtins.sh
-
-### Test suite coverage testing
-#
-# None right now
-#
-# .PHONY: coverage coverage-clean coverage-build coverage-report
-#
-# coverage:
-#      $(MAKE) coverage-build
-#      $(MAKE) coverage-report
-#
-# coverage-clean:
-#      rm -f *.gcda *.gcno
-#
-# COVERAGE_CFLAGS = $(CFLAGS) -O0 -ftest-coverage -fprofile-arcs
-# COVERAGE_LDFLAGS = $(CFLAGS)  -O0 -lgcov
-#
-# coverage-build: coverage-clean
-#      $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" all
-#      $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" \
-#              -j1 test
-#
-# coverage-report:
-#      gcov -b *.c */*.c
-#      grep '^function.*called 0 ' *.c.gcov */*.c.gcov \
-#              | sed -e 's/\([^:]*\)\.gcov: *function \([^ ]*\) called.*/\1: \2/' \
-#              | tee coverage-untested-functions
index d9ab3ce..0c7454f 100644 (file)
@@ -55,7 +55,7 @@ int bench_sched_pipe(int argc, const char **argv,
         * discarding returned value of read(), write()
         * causes error in building environment for perf
         */
-       int ret, wait_stat;
+       int __used ret, wait_stat;
        pid_t pid, retpid;
 
        argc = parse_options(argc, argv, options,
index 8879463..695de4b 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "util/util.h"
 
+#include "util/util.h"
 #include "util/color.h"
 #include <linux/list.h>
 #include "util/cache.h"
@@ -18,6 +19,9 @@
 #include "perf.h"
 #include "util/debug.h"
 
+#include "util/evlist.h"
+#include "util/evsel.h"
+#include "util/annotate.h"
 #include "util/event.h"
 #include "util/parse-options.h"
 #include "util/parse-events.h"
@@ -36,9 +40,13 @@ static bool          print_line;
 
 static const char *sym_hist_filter;
 
-static int hists__add_entry(struct hists *self, struct addr_location *al)
+static int perf_evlist__add_sample(struct perf_evlist *evlist,
+                                  struct perf_sample *sample,
+                                  struct addr_location *al)
 {
+       struct perf_evsel *evsel;
        struct hist_entry *he;
+       int ret;
 
        if (sym_hist_filter != NULL &&
            (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) {
@@ -51,25 +59,51 @@ static int hists__add_entry(struct hists *self, struct addr_location *al)
                return 0;
        }
 
-       he = __hists__add_entry(self, al, NULL, 1);
+       evsel = perf_evlist__id2evsel(evlist, sample->id);
+       if (evsel == NULL) {
+               /*
+                * FIXME: Propagate this back, but at least we're in a builtin,
+                * where exit() is allowed. ;-)
+                */
+               ui__warning("Invalid %s file, contains samples with id not in "
+                           "its header!\n", input_name);
+               exit_browser(0);
+               exit(1);
+       }
+
+       he = __hists__add_entry(&evsel->hists, al, NULL, 1);
        if (he == NULL)
                return -ENOMEM;
 
-       return hist_entry__inc_addr_samples(he, al->addr);
+       ret = 0;
+       if (he->ms.sym != NULL) {
+               struct annotation *notes = symbol__annotation(he->ms.sym);
+               if (notes->src == NULL &&
+                   symbol__alloc_hist(he->ms.sym, evlist->nr_entries) < 0)
+                       return -ENOMEM;
+
+               ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
+       }
+
+       evsel->hists.stats.total_period += sample->period;
+       hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
+       return ret;
 }
 
-static int process_sample_event(event_t *event, struct sample_data *sample,
+static int process_sample_event(union perf_event *event,
+                               struct perf_sample *sample,
                                struct perf_session *session)
 {
        struct addr_location al;
 
-       if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) {
+       if (perf_event__preprocess_sample(event, session, &al, sample,
+                                         symbol__annotate_init) < 0) {
                pr_warning("problem processing %d event, skipping it.\n",
                           event->header.type);
                return -1;
        }
 
-       if (!al.filtered && hists__add_entry(&session->hists, &al)) {
+       if (!al.filtered && perf_evlist__add_sample(session->evlist, sample, &al)) {
                pr_warning("problem incrementing symbol count, "
                           "skipping event\n");
                return -1;
@@ -78,261 +112,26 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
        return 0;
 }
 
-static int objdump_line__print(struct objdump_line *self,
-                              struct list_head *head,
-                              struct hist_entry *he, u64 len)
-{
-       struct symbol *sym = he->ms.sym;
-       static const char *prev_line;
-       static const char *prev_color;
-
-       if (self->offset != -1) {
-               const char *path = NULL;
-               unsigned int hits = 0;
-               double percent = 0.0;
-               const char *color;
-               struct sym_priv *priv = symbol__priv(sym);
-               struct sym_ext *sym_ext = priv->ext;
-               struct sym_hist *h = priv->hist;
-               s64 offset = self->offset;
-               struct objdump_line *next = objdump__get_next_ip_line(head, self);
-
-               while (offset < (s64)len &&
-                      (next == NULL || offset < next->offset)) {
-                       if (sym_ext) {
-                               if (path == NULL)
-                                       path = sym_ext[offset].path;
-                               percent += sym_ext[offset].percent;
-                       } else
-                               hits += h->ip[offset];
-
-                       ++offset;
-               }
-
-               if (sym_ext == NULL && h->sum)
-                       percent = 100.0 * hits / h->sum;
-
-               color = get_percent_color(percent);
-
-               /*
-                * Also color the filename and line if needed, with
-                * the same color than the percentage. Don't print it
-                * twice for close colored ip with the same filename:line
-                */
-               if (path) {
-                       if (!prev_line || strcmp(prev_line, path)
-                                      || color != prev_color) {
-                               color_fprintf(stdout, color, " %s", path);
-                               prev_line = path;
-                               prev_color = color;
-                       }
-               }
-
-               color_fprintf(stdout, color, " %7.2f", percent);
-               printf(" :      ");
-               color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", self->line);
-       } else {
-               if (!*self->line)
-                       printf("         :\n");
-               else
-                       printf("         :      %s\n", self->line);
-       }
-
-       return 0;
-}
-
-static struct rb_root root_sym_ext;
-
-static void insert_source_line(struct sym_ext *sym_ext)
-{
-       struct sym_ext *iter;
-       struct rb_node **p = &root_sym_ext.rb_node;
-       struct rb_node *parent = NULL;
-
-       while (*p != NULL) {
-               parent = *p;
-               iter = rb_entry(parent, struct sym_ext, node);
-
-               if (sym_ext->percent > iter->percent)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
-       }
-
-       rb_link_node(&sym_ext->node, parent, p);
-       rb_insert_color(&sym_ext->node, &root_sym_ext);
-}
-
-static void free_source_line(struct hist_entry *he, int len)
-{
-       struct sym_priv *priv = symbol__priv(he->ms.sym);
-       struct sym_ext *sym_ext = priv->ext;
-       int i;
-
-       if (!sym_ext)
-               return;
-
-       for (i = 0; i < len; i++)
-               free(sym_ext[i].path);
-       free(sym_ext);
-
-       priv->ext = NULL;
-       root_sym_ext = RB_ROOT;
-}
-
-/* Get the filename:line for the colored entries */
-static void
-get_source_line(struct hist_entry *he, int len, const char *filename)
-{
-       struct symbol *sym = he->ms.sym;
-       u64 start;
-       int i;
-       char cmd[PATH_MAX * 2];
-       struct sym_ext *sym_ext;
-       struct sym_priv *priv = symbol__priv(sym);
-       struct sym_hist *h = priv->hist;
-
-       if (!h->sum)
-               return;
-
-       sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext));
-       if (!priv->ext)
-               return;
-
-       start = he->ms.map->unmap_ip(he->ms.map, sym->start);
-
-       for (i = 0; i < len; i++) {
-               char *path = NULL;
-               size_t line_len;
-               u64 offset;
-               FILE *fp;
-
-               sym_ext[i].percent = 100.0 * h->ip[i] / h->sum;
-               if (sym_ext[i].percent <= 0.5)
-                       continue;
-
-               offset = start + i;
-               sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);
-               fp = popen(cmd, "r");
-               if (!fp)
-                       continue;
-
-               if (getline(&path, &line_len, fp) < 0 || !line_len)
-                       goto next;
-
-               sym_ext[i].path = malloc(sizeof(char) * line_len + 1);
-               if (!sym_ext[i].path)
-                       goto next;
-
-               strcpy(sym_ext[i].path, path);
-               insert_source_line(&sym_ext[i]);
-
-       next:
-               pclose(fp);
-       }
-}
-
-static void print_summary(const char *filename)
-{
-       struct sym_ext *sym_ext;
-       struct rb_node *node;
-
-       printf("\nSorted summary for file %s\n", filename);
-       printf("----------------------------------------------\n\n");
-
-       if (RB_EMPTY_ROOT(&root_sym_ext)) {
-               printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
-               return;
-       }
-
-       node = rb_first(&root_sym_ext);
-       while (node) {
-               double percent;
-               const char *color;
-               char *path;
-
-               sym_ext = rb_entry(node, struct sym_ext, node);
-               percent = sym_ext->percent;
-               color = get_percent_color(percent);
-               path = sym_ext->path;
-
-               color_fprintf(stdout, color, " %7.2f %s", percent, path);
-               node = rb_next(node);
-       }
-}
-
-static void hist_entry__print_hits(struct hist_entry *self)
-{
-       struct symbol *sym = self->ms.sym;
-       struct sym_priv *priv = symbol__priv(sym);
-       struct sym_hist *h = priv->hist;
-       u64 len = sym->end - sym->start, offset;
-
-       for (offset = 0; offset < len; ++offset)
-               if (h->ip[offset] != 0)
-                       printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
-                              sym->start + offset, h->ip[offset]);
-       printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
-}
-
-static int hist_entry__tty_annotate(struct hist_entry *he)
+static int hist_entry__tty_annotate(struct hist_entry *he, int evidx)
 {
-       struct map *map = he->ms.map;
-       struct dso *dso = map->dso;
-       struct symbol *sym = he->ms.sym;
-       const char *filename = dso->long_name, *d_filename;
-       u64 len;
-       LIST_HEAD(head);
-       struct objdump_line *pos, *n;
-
-       if (hist_entry__annotate(he, &head, 0) < 0)
-               return -1;
-
-       if (full_paths)
-               d_filename = filename;
-       else
-               d_filename = basename(filename);
-
-       len = sym->end - sym->start;
-
-       if (print_line) {
-               get_source_line(he, len, filename);
-               print_summary(filename);
-       }
-
-       printf("\n\n------------------------------------------------\n");
-       printf(" Percent |      Source code & Disassembly of %s\n", d_filename);
-       printf("------------------------------------------------\n");
-
-       if (verbose)
-               hist_entry__print_hits(he);
-
-       list_for_each_entry_safe(pos, n, &head, node) {
-               objdump_line__print(pos, &head, he, len);
-               list_del(&pos->node);
-               objdump_line__free(pos);
-       }
-
-       if (print_line)
-               free_source_line(he, len);
-
-       return 0;
+       return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx,
+                                   print_line, full_paths, 0, 0);
 }
 
-static void hists__find_annotations(struct hists *self)
+static void hists__find_annotations(struct hists *self, int evidx)
 {
        struct rb_node *nd = rb_first(&self->entries), *next;
        int key = KEY_RIGHT;
 
        while (nd) {
                struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
-               struct sym_priv *priv;
+               struct annotation *notes;
 
                if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned)
                        goto find_next;
 
-               priv = symbol__priv(he->ms.sym);
-               if (priv->hist == NULL) {
+               notes = symbol__annotation(he->ms.sym);
+               if (notes->src == NULL) {
 find_next:
                        if (key == KEY_LEFT)
                                nd = rb_prev(nd);
@@ -342,7 +141,7 @@ find_next:
                }
 
                if (use_browser > 0) {
-                       key = hist_entry__tui_annotate(he);
+                       key = hist_entry__tui_annotate(he, evidx);
                        switch (key) {
                        case KEY_RIGHT:
                                next = rb_next(nd);
@@ -357,24 +156,24 @@ find_next:
                        if (next != NULL)
                                nd = next;
                } else {
-                       hist_entry__tty_annotate(he);
+                       hist_entry__tty_annotate(he, evidx);
                        nd = rb_next(nd);
                        /*
                         * Since we have a hist_entry per IP for the same
-                        * symbol, free he->ms.sym->hist to signal we already
+                        * symbol, free he->ms.sym->src to signal we already
                         * processed this symbol.
                         */
-                       free(priv->hist);
-                       priv->hist = NULL;
+                       free(notes->src);
+                       notes->src = NULL;
                }
        }
 }
 
 static struct perf_event_ops event_ops = {
        .sample = process_sample_event,
-       .mmap   = event__process_mmap,
-       .comm   = event__process_comm,
-       .fork   = event__process_task,
+       .mmap   = perf_event__process_mmap,
+       .comm   = perf_event__process_comm,
+       .fork   = perf_event__process_task,
        .ordered_samples = true,
        .ordering_requires_timestamps = true,
 };
@@ -383,6 +182,8 @@ static int __cmd_annotate(void)
 {
        int ret;
        struct perf_session *session;
+       struct perf_evsel *pos;
+       u64 total_nr_samples;
 
        session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
        if (session == NULL)
@@ -403,12 +204,36 @@ static int __cmd_annotate(void)
        if (verbose > 2)
                perf_session__fprintf_dsos(session, stdout);
 
-       hists__collapse_resort(&session->hists);
-       hists__output_resort(&session->hists);
-       hists__find_annotations(&session->hists);
-out_delete:
-       perf_session__delete(session);
+       total_nr_samples = 0;
+       list_for_each_entry(pos, &session->evlist->entries, node) {
+               struct hists *hists = &pos->hists;
+               u32 nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
+
+               if (nr_samples > 0) {
+                       total_nr_samples += nr_samples;
+                       hists__collapse_resort(hists);
+                       hists__output_resort(hists);
+                       hists__find_annotations(hists, pos->idx);
+               }
+       }
 
+       if (total_nr_samples == 0) {
+               ui__warning("The %s file has no samples!\n", input_name);
+               goto out_delete;
+       }
+out_delete:
+       /*
+        * Speed up the exit process, for large files this can
+        * take quite a while.
+        *
+        * XXX Enable this when using valgrind or if we ever
+        * librarize this command.
+        *
+        * Also experiment with obstacks to see how much speed
+        * up we'll get here.
+        *
+        * perf_session__delete(session);
+        */
        return ret;
 }
 
@@ -451,9 +276,9 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
        else if (use_tui)
                use_browser = 1;
 
-       setup_browser();
+       setup_browser(true);
 
-       symbol_conf.priv_size = sizeof(struct sym_priv);
+       symbol_conf.priv_size = sizeof(struct annotation);
        symbol_conf.try_vmlinux_path = true;
 
        if (symbol__init() < 0)
index 3153e49..6b7d911 100644 (file)
@@ -30,13 +30,13 @@ static int hists__add_entry(struct hists *self,
        return -ENOMEM;
 }
 
-static int diff__process_sample_event(event_t *event,
-                                     struct sample_data *sample,
+static int diff__process_sample_event(union perf_event *event,
+                                     struct perf_sample *sample,
                                      struct perf_session *session)
 {
        struct addr_location al;
 
-       if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) {
+       if (perf_event__preprocess_sample(event, session, &al, sample, NULL) < 0) {
                pr_warning("problem processing %d event, skipping it.\n",
                           event->header.type);
                return -1;
@@ -56,11 +56,11 @@ static int diff__process_sample_event(event_t *event,
 
 static struct perf_event_ops event_ops = {
        .sample = diff__process_sample_event,
-       .mmap   = event__process_mmap,
-       .comm   = event__process_comm,
-       .exit   = event__process_task,
-       .fork   = event__process_task,
-       .lost   = event__process_lost,
+       .mmap   = perf_event__process_mmap,
+       .comm   = perf_event__process_comm,
+       .exit   = perf_event__process_task,
+       .fork   = perf_event__process_task,
+       .lost   = perf_event__process_lost,
        .ordered_samples = true,
        .ordering_requires_timestamps = true,
 };
index 0c78ffa..e29f04e 100644 (file)
@@ -16,8 +16,8 @@
 static char            const *input_name = "-";
 static bool            inject_build_ids;
 
-static int event__repipe_synth(event_t *event,
-                              struct perf_session *session __used)
+static int perf_event__repipe_synth(union perf_event *event,
+                                   struct perf_session *session __used)
 {
        uint32_t size;
        void *buf = event;
@@ -36,41 +36,44 @@ static int event__repipe_synth(event_t *event,
        return 0;
 }
 
-static int event__repipe(event_t *event, struct sample_data *sample __used,
-                        struct perf_session *session)
+static int perf_event__repipe(union perf_event *event,
+                             struct perf_sample *sample __used,
+                             struct perf_session *session)
 {
-       return event__repipe_synth(event, session);
+       return perf_event__repipe_synth(event, session);
 }
 
-static int event__repipe_mmap(event_t *self, struct sample_data *sample,
-                             struct perf_session *session)
+static int perf_event__repipe_mmap(union perf_event *event,
+                                  struct perf_sample *sample,
+                                  struct perf_session *session)
 {
        int err;
 
-       err = event__process_mmap(self, sample, session);
-       event__repipe(self, sample, session);
+       err = perf_event__process_mmap(event, sample, session);
+       perf_event__repipe(event, sample, session);
 
        return err;
 }
 
-static int event__repipe_task(event_t *self, struct sample_data *sample,
-                             struct perf_session *session)
+static int perf_event__repipe_task(union perf_event *event,
+                                  struct perf_sample *sample,
+                                  struct perf_session *session)
 {
        int err;
 
-       err = event__process_task(self, sample, session);
-       event__repipe(self, sample, session);
+       err = perf_event__process_task(event, sample, session);
+       perf_event__repipe(event, sample, session);
 
        return err;
 }
 
-static int event__repipe_tracing_data(event_t *self,
-                                     struct perf_session *session)
+static int perf_event__repipe_tracing_data(union perf_event *event,
+                                          struct perf_session *session)
 {
        int err;
 
-       event__repipe_synth(self, session);
-       err = event__process_tracing_data(self, session);
+       perf_event__repipe_synth(event, session);
+       err = perf_event__process_tracing_data(event, session);
 
        return err;
 }
@@ -109,8 +112,8 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
        if (self->kernel)
                misc = PERF_RECORD_MISC_KERNEL;
 
-       err = event__synthesize_build_id(self, misc, event__repipe,
-                                        machine, session);
+       err = perf_event__synthesize_build_id(self, misc, perf_event__repipe,
+                                             machine, session);
        if (err) {
                pr_err("Can't synthesize build_id event for %s\n", self->long_name);
                return -1;
@@ -119,8 +122,9 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
        return 0;
 }
 
-static int event__inject_buildid(event_t *event, struct sample_data *sample,
-                                struct perf_session *session)
+static int perf_event__inject_buildid(union perf_event *event,
+                                     struct perf_sample *sample,
+                                     struct perf_session *session)
 {
        struct addr_location al;
        struct thread *thread;
@@ -155,24 +159,24 @@ static int event__inject_buildid(event_t *event, struct sample_data *sample,
        }
 
 repipe:
-       event__repipe(event, sample, session);
+       perf_event__repipe(event, sample, session);
        return 0;
 }
 
 struct perf_event_ops inject_ops = {
-       .sample         = event__repipe,
-       .mmap           = event__repipe,
-       .comm           = event__repipe,
-       .fork           = event__repipe,
-       .exit           = event__repipe,
-       .lost           = event__repipe,
-       .read           = event__repipe,
-       .throttle       = event__repipe,
-       .unthrottle     = event__repipe,
-       .attr           = event__repipe_synth,
-       .event_type     = event__repipe_synth,
-       .tracing_data   = event__repipe_synth,
-       .build_id       = event__repipe_synth,
+       .sample         = perf_event__repipe,
+       .mmap           = perf_event__repipe,
+       .comm           = perf_event__repipe,
+       .fork           = perf_event__repipe,
+       .exit           = perf_event__repipe,
+       .lost           = perf_event__repipe,
+       .read           = perf_event__repipe,
+       .throttle       = perf_event__repipe,
+       .unthrottle     = perf_event__repipe,
+       .attr           = perf_event__repipe_synth,
+       .event_type     = perf_event__repipe_synth,
+       .tracing_data   = perf_event__repipe_synth,
+       .build_id       = perf_event__repipe_synth,
 };
 
 extern volatile int session_done;
@@ -190,10 +194,10 @@ static int __cmd_inject(void)
        signal(SIGINT, sig_handler);
 
        if (inject_build_ids) {
-               inject_ops.sample       = event__inject_buildid;
-               inject_ops.mmap         = event__repipe_mmap;
-               inject_ops.fork         = event__repipe_task;
-               inject_ops.tracing_data = event__repipe_tracing_data;
+               inject_ops.sample       = perf_event__inject_buildid;
+               inject_ops.mmap         = perf_event__repipe_mmap;
+               inject_ops.fork         = perf_event__repipe_task;
+               inject_ops.tracing_data = perf_event__repipe_tracing_data;
        }
 
        session = perf_session__new(input_name, O_RDONLY, false, true, &inject_ops);
index d97256d..7f618f4 100644 (file)
@@ -275,9 +275,8 @@ static void process_free_event(void *data,
        s_alloc->alloc_cpu = -1;
 }
 
-static void
-process_raw_event(event_t *raw_event __used, void *data,
-                 int cpu, u64 timestamp, struct thread *thread)
+static void process_raw_event(union perf_event *raw_event __used, void *data,
+                             int cpu, u64 timestamp, struct thread *thread)
 {
        struct event *event;
        int type;
@@ -304,7 +303,8 @@ process_raw_event(event_t *raw_event __used, void *data,
        }
 }
 
-static int process_sample_event(event_t *event, struct sample_data *sample,
+static int process_sample_event(union perf_event *event,
+                               struct perf_sample *sample,
                                struct perf_session *session)
 {
        struct thread *thread = perf_session__findnew(session, event->ip.pid);
@@ -325,7 +325,7 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
 
 static struct perf_event_ops event_ops = {
        .sample                 = process_sample_event,
-       .comm                   = event__process_comm,
+       .comm                   = perf_event__process_comm,
        .ordered_samples        = true,
 };
 
index d88c696..6313b6e 100644 (file)
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2009, Thomas Gleixner <tglx@linutronix.de>
  * Copyright (C) 2008-2009, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
+ * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
  */
 #include "builtin.h"
 
 #include "util/parse-events.h"
 #include "util/cache.h"
 
-int cmd_list(int argc __used, const char **argv __used, const char *prefix __used)
+int cmd_list(int argc, const char **argv, const char *prefix __used)
 {
        setup_pager();
-       print_events();
+
+       if (argc == 1)
+               print_events(NULL);
+       else {
+               int i;
+
+               for (i = 1; i < argc; ++i) {
+                       if (i > 1)
+                               putchar('\n');
+                       if (strncmp(argv[i], "tracepoint", 10) == 0)
+                               print_tracepoint_events(NULL, NULL);
+                       else if (strcmp(argv[i], "hw") == 0 ||
+                                strcmp(argv[i], "hardware") == 0)
+                               print_events_type(PERF_TYPE_HARDWARE);
+                       else if (strcmp(argv[i], "sw") == 0 ||
+                                strcmp(argv[i], "software") == 0)
+                               print_events_type(PERF_TYPE_SOFTWARE);
+                       else if (strcmp(argv[i], "cache") == 0 ||
+                                strcmp(argv[i], "hwcache") == 0)
+                               print_hwcache_events(NULL);
+                       else {
+                               char *sep = strchr(argv[i], ':'), *s;
+                               int sep_idx;
+
+                               if (sep == NULL) {
+                                       print_events(argv[i]);
+                                       continue;
+                               }
+                               sep_idx = sep - argv[i];
+                               s = strdup(argv[i]);
+                               if (s == NULL)
+                                       return -1;
+
+                               s[sep_idx] = '\0';
+                               print_tracepoint_events(s, s + sep_idx + 1);
+                               free(s);
+                       }
+               }
+       }
        return 0;
 }
index 2b36def..2e93f99 100644 (file)
@@ -834,14 +834,14 @@ static void dump_info(void)
                die("Unknown type of information\n");
 }
 
-static int process_sample_event(event_t *self, struct sample_data *sample,
+static int process_sample_event(union perf_event *event, struct perf_sample *sample,
                                struct perf_session *s)
 {
        struct thread *thread = perf_session__findnew(s, sample->tid);
 
        if (thread == NULL) {
                pr_debug("problem processing %d event, skipping it.\n",
-                       self->header.type);
+                       event->header.type);
                return -1;
        }
 
@@ -852,7 +852,7 @@ static int process_sample_event(event_t *self, struct sample_data *sample,
 
 static struct perf_event_ops eops = {
        .sample                 = process_sample_event,
-       .comm                   = event__process_comm,
+       .comm                   = perf_event__process_comm,
        .ordered_samples        = true,
 };
 
@@ -893,7 +893,7 @@ static const char * const report_usage[] = {
 
 static const struct option report_options[] = {
        OPT_STRING('k', "key", &sort_key, "acquired",
-                   "key for sorting"),
+                   "key for sorting (acquired / contended / wait_total / wait_max / wait_min)"),
        /* TODO: type */
        OPT_END()
 };
index add163c..2c0e64d 100644 (file)
@@ -36,6 +36,7 @@
 #include "builtin.h"
 #include "util/util.h"
 #include "util/strlist.h"
+#include "util/strfilter.h"
 #include "util/symbol.h"
 #include "util/debug.h"
 #include "util/debugfs.h"
@@ -43,6 +44,8 @@
 #include "util/probe-finder.h"
 #include "util/probe-event.h"
 
+#define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"
+#define DEFAULT_FUNC_FILTER "!_*"
 #define MAX_PATH_LEN 256
 
 /* Session management structure */
@@ -52,6 +55,7 @@ static struct {
        bool show_lines;
        bool show_vars;
        bool show_ext_vars;
+       bool show_funcs;
        bool mod_events;
        int nevents;
        struct perf_probe_event events[MAX_PROBES];
@@ -59,6 +63,7 @@ static struct {
        struct line_range line_range;
        const char *target_module;
        int max_probe_points;
+       struct strfilter *filter;
 } params;
 
 /* Parse an event definition. Note that any error must die. */
@@ -157,6 +162,27 @@ static int opt_show_vars(const struct option *opt __used,
 }
 #endif
 
+static int opt_set_filter(const struct option *opt __used,
+                         const char *str, int unset __used)
+{
+       const char *err;
+
+       if (str) {
+               pr_debug2("Set filter: %s\n", str);
+               if (params.filter)
+                       strfilter__delete(params.filter);
+               params.filter = strfilter__new(str, &err);
+               if (!params.filter) {
+                       pr_err("Filter parse error at %td.\n", err - str + 1);
+                       pr_err("Source: \"%s\"\n", str);
+                       pr_err("         %*c\n", (int)(err - str + 1), '^');
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
 static const char * const probe_usage[] = {
        "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
        "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
@@ -221,6 +247,13 @@ static const struct option options[] = {
        OPT__DRY_RUN(&probe_event_dry_run),
        OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
                 "Set how many probe points can be found for a probe."),
+       OPT_BOOLEAN('F', "funcs", &params.show_funcs,
+                   "Show potential probe-able functions."),
+       OPT_CALLBACK('\0', "filter", NULL,
+                    "[!]FILTER", "Set a filter (with --vars/funcs only)\n"
+                    "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n"
+                    "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)",
+                    opt_set_filter),
        OPT_END()
 };
 
@@ -246,7 +279,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
                params.max_probe_points = MAX_PROBES;
 
        if ((!params.nevents && !params.dellist && !params.list_events &&
-            !params.show_lines))
+            !params.show_lines && !params.show_funcs))
                usage_with_options(probe_usage, options);
 
        /*
@@ -267,12 +300,41 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
                        pr_err(" Error: Don't use --list with --vars.\n");
                        usage_with_options(probe_usage, options);
                }
+               if (params.show_funcs) {
+                       pr_err("  Error: Don't use --list with --funcs.\n");
+                       usage_with_options(probe_usage, options);
+               }
                ret = show_perf_probe_events();
                if (ret < 0)
                        pr_err("  Error: Failed to show event list. (%d)\n",
                               ret);
                return ret;
        }
+       if (params.show_funcs) {
+               if (params.nevents != 0 || params.dellist) {
+                       pr_err("  Error: Don't use --funcs with"
+                              " --add/--del.\n");
+                       usage_with_options(probe_usage, options);
+               }
+               if (params.show_lines) {
+                       pr_err("  Error: Don't use --funcs with --line.\n");
+                       usage_with_options(probe_usage, options);
+               }
+               if (params.show_vars) {
+                       pr_err("  Error: Don't use --funcs with --vars.\n");
+                       usage_with_options(probe_usage, options);
+               }
+               if (!params.filter)
+                       params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
+                                                      NULL);
+               ret = show_available_funcs(params.target_module,
+                                          params.filter);
+               strfilter__delete(params.filter);
+               if (ret < 0)
+                       pr_err("  Error: Failed to show functions."
+                              " (%d)\n", ret);
+               return ret;
+       }
 
 #ifdef DWARF_SUPPORT
        if (params.show_lines) {
@@ -297,10 +359,16 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
                               " --add/--del.\n");
                        usage_with_options(probe_usage, options);
                }
+               if (!params.filter)
+                       params.filter = strfilter__new(DEFAULT_VAR_FILTER,
+                                                      NULL);
+
                ret = show_available_vars(params.events, params.nevents,
                                          params.max_probe_points,
                                          params.target_module,
+                                         params.filter,
                                          params.show_ext_vars);
+               strfilter__delete(params.filter);
                if (ret < 0)
                        pr_err("  Error: Failed to show vars. (%d)\n", ret);
                return ret;
index b2f729f..6febcc1 100644 (file)
 
 #include "util/header.h"
 #include "util/event.h"
+#include "util/evlist.h"
 #include "util/evsel.h"
 #include "util/debug.h"
 #include "util/session.h"
 #include "util/symbol.h"
 #include "util/cpumap.h"
+#include "util/thread_map.h"
 
 #include <unistd.h>
 #include <sched.h>
@@ -37,16 +39,14 @@ enum write_mode_t {
 
 static u64                     user_interval                   = ULLONG_MAX;
 static u64                     default_interval                =      0;
-static u64                     sample_type;
 
-static struct cpu_map          *cpus;
 static unsigned int            page_size;
 static unsigned int            mmap_pages                      =    128;
 static unsigned int            user_freq                       = UINT_MAX;
 static int                     freq                            =   1000;
 static int                     output;
 static int                     pipe_output                     =      0;
-static const char              *output_name                    = "perf.data";
+static const char              *output_name                    = NULL;
 static int                     group                           =      0;
 static int                     realtime_prio                   =      0;
 static bool                    nodelay                         =  false;
@@ -55,7 +55,6 @@ static bool                   sample_id_all_avail             =   true;
 static bool                    system_wide                     =  false;
 static pid_t                   target_pid                      =     -1;
 static pid_t                   target_tid                      =     -1;
-static struct thread_map       *threads;
 static pid_t                   child_pid                       =     -1;
 static bool                    no_inherit                      =  false;
 static enum write_mode_t       write_mode                      = WRITE_FORCE;
@@ -66,51 +65,17 @@ static bool                 sample_address                  =  false;
 static bool                    sample_time                     =  false;
 static bool                    no_buildid                      =  false;
 static bool                    no_buildid_cache                =  false;
+static struct perf_evlist      *evsel_list;
 
 static long                    samples                         =      0;
 static u64                     bytes_written                   =      0;
 
-static struct pollfd           *event_array;
-
-static int                     nr_poll                         =      0;
-static int                     nr_cpu                          =      0;
-
 static int                     file_new                        =      1;
 static off_t                   post_processing_offset;
 
 static struct perf_session     *session;
 static const char              *cpu_list;
 
-struct mmap_data {
-       void                    *base;
-       unsigned int            mask;
-       unsigned int            prev;
-};
-
-static struct mmap_data                mmap_array[MAX_NR_CPUS];
-
-static unsigned long mmap_read_head(struct mmap_data *md)
-{
-       struct perf_event_mmap_page *pc = md->base;
-       long head;
-
-       head = pc->data_head;
-       rmb();
-
-       return head;
-}
-
-static void mmap_write_tail(struct mmap_data *md, unsigned long tail)
-{
-       struct perf_event_mmap_page *pc = md->base;
-
-       /*
-        * ensure all reads are done before we write the tail out.
-        */
-       /* mb(); */
-       pc->data_tail = tail;
-}
-
 static void advance_output(size_t size)
 {
        bytes_written += size;
@@ -131,42 +96,26 @@ static void write_output(void *buf, size_t size)
        }
 }
 
-static int process_synthesized_event(event_t *event,
-                                    struct sample_data *sample __used,
+static int process_synthesized_event(union perf_event *event,
+                                    struct perf_sample *sample __used,
                                     struct perf_session *self __used)
 {
        write_output(event, event->header.size);
        return 0;
 }
 
-static void mmap_read(struct mmap_data *md)
+static void mmap_read(struct perf_mmap *md)
 {
-       unsigned int head = mmap_read_head(md);
+       unsigned int head = perf_mmap__read_head(md);
        unsigned int old = md->prev;
        unsigned char *data = md->base + page_size;
        unsigned long size;
        void *buf;
-       int diff;
 
-       /*
-        * If we're further behind than half the buffer, there's a chance
-        * the writer will bite our tail and mess up the samples under us.
-        *
-        * If we somehow ended up ahead of the head, we got messed up.
-        *
-        * In either case, truncate and restart at head.
-        */
-       diff = head - old;
-       if (diff < 0) {
-               fprintf(stderr, "WARNING: failed to keep up with mmap data\n");
-               /*
-                * head points to a known good entry, start there.
-                */
-               old = head;
-       }
+       if (old == head)
+               return;
 
-       if (old != head)
-               samples++;
+       samples++;
 
        size = head - old;
 
@@ -185,7 +134,7 @@ static void mmap_read(struct mmap_data *md)
        write_output(buf, size);
 
        md->prev = old;
-       mmap_write_tail(md, old);
+       perf_mmap__write_tail(md, old);
 }
 
 static volatile int done = 0;
@@ -209,53 +158,10 @@ static void sig_atexit(void)
        kill(getpid(), signr);
 }
 
-static int group_fd;
-
-static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr)
-{
-       struct perf_header_attr *h_attr;
-
-       if (nr < session->header.attrs) {
-               h_attr = session->header.attr[nr];
-       } else {
-               h_attr = perf_header_attr__new(a);
-               if (h_attr != NULL)
-                       if (perf_header__add_attr(&session->header, h_attr) < 0) {
-                               perf_header_attr__delete(h_attr);
-                               h_attr = NULL;
-                       }
-       }
-
-       return h_attr;
-}
-
-static void create_counter(struct perf_evsel *evsel, int cpu)
+static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist)
 {
-       char *filter = evsel->filter;
        struct perf_event_attr *attr = &evsel->attr;
-       struct perf_header_attr *h_attr;
        int track = !evsel->idx; /* only the first counter needs these */
-       int thread_index;
-       int ret;
-       struct {
-               u64 count;
-               u64 time_enabled;
-               u64 time_running;
-               u64 id;
-       } read_data;
-       /*
-        * Check if parse_single_tracepoint_event has already asked for
-        * PERF_SAMPLE_TIME.
-        *
-        * XXX this is kludgy but short term fix for problems introduced by
-        * eac23d1c that broke 'perf script' by having different sample_types
-        * when using multiple tracepoint events when we use a perf binary
-        * that tries to use sample_id_all on an older kernel.
-        *
-        * We need to move counter creation to perf_session, support
-        * different sample_types, etc.
-        */
-       bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
 
        attr->read_format       = PERF_FORMAT_TOTAL_TIME_ENABLED |
                                  PERF_FORMAT_TOTAL_TIME_RUNNING |
@@ -263,7 +169,7 @@ static void create_counter(struct perf_evsel *evsel, int cpu)
 
        attr->sample_type       |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
 
-       if (nr_counters > 1)
+       if (evlist->nr_entries > 1)
                attr->sample_type |= PERF_SAMPLE_ID;
 
        /*
@@ -315,19 +221,58 @@ static void create_counter(struct perf_evsel *evsel, int cpu)
 
        attr->mmap              = track;
        attr->comm              = track;
-       attr->inherit           = !no_inherit;
+
        if (target_pid == -1 && target_tid == -1 && !system_wide) {
                attr->disabled = 1;
                attr->enable_on_exec = 1;
        }
-retry_sample_id:
-       attr->sample_id_all = sample_id_all_avail ? 1 : 0;
+}
 
-       for (thread_index = 0; thread_index < threads->nr; thread_index++) {
-try_again:
-               FD(evsel, nr_cpu, thread_index) = sys_perf_event_open(attr, threads->map[thread_index], cpu, group_fd, 0);
+static bool perf_evlist__equal(struct perf_evlist *evlist,
+                              struct perf_evlist *other)
+{
+       struct perf_evsel *pos, *pair;
+
+       if (evlist->nr_entries != other->nr_entries)
+               return false;
+
+       pair = list_entry(other->entries.next, struct perf_evsel, node);
 
-               if (FD(evsel, nr_cpu, thread_index) < 0) {
+       list_for_each_entry(pos, &evlist->entries, node) {
+               if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
+                       return false;
+               pair = list_entry(pair->node.next, struct perf_evsel, node);
+       }
+
+       return true;
+}
+
+static void open_counters(struct perf_evlist *evlist)
+{
+       struct perf_evsel *pos;
+
+       list_for_each_entry(pos, &evlist->entries, node) {
+               struct perf_event_attr *attr = &pos->attr;
+               /*
+                * Check if parse_single_tracepoint_event has already asked for
+                * PERF_SAMPLE_TIME.
+                *
+                * XXX this is kludgy but short term fix for problems introduced by
+                * eac23d1c that broke 'perf script' by having different sample_types
+                * when using multiple tracepoint events when we use a perf binary
+                * that tries to use sample_id_all on an older kernel.
+                *
+                * We need to move counter creation to perf_session, support
+                * different sample_types, etc.
+                */
+               bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
+
+               config_attr(pos, evlist);
+retry_sample_id:
+               attr->sample_id_all = sample_id_all_avail ? 1 : 0;
+try_again:
+               if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group,
+                                    !no_inherit) < 0) {
                        int err = errno;
 
                        if (err == EPERM || err == EACCES)
@@ -364,7 +309,7 @@ try_again:
                        }
                        printf("\n");
                        error("sys_perf_event_open() syscall returned with %d (%s).  /bin/dmesg may provide additional information.\n",
-                             FD(evsel, nr_cpu, thread_index), strerror(err));
+                             err, strerror(err));
 
 #if defined(__i386__) || defined(__x86_64__)
                        if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
@@ -375,90 +320,28 @@ try_again:
 #endif
 
                        die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
-                       exit(-1);
                }
+       }
 
-               h_attr = get_header_attr(attr, evsel->idx);
-               if (h_attr == NULL)
-                       die("nomem\n");
+       if (perf_evlist__set_filters(evlist)) {
+               error("failed to set filter with %d (%s)\n", errno,
+                       strerror(errno));
+               exit(-1);
+       }
 
-               if (!file_new) {
-                       if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
-                               fprintf(stderr, "incompatible append\n");
-                               exit(-1);
-                       }
-               }
+       if (perf_evlist__mmap(evlist, mmap_pages, false) < 0)
+               die("failed to mmap with %d (%s)\n", errno, strerror(errno));
 
-               if (read(FD(evsel, nr_cpu, thread_index), &read_data, sizeof(read_data)) == -1) {
-                       perror("Unable to read perf file descriptor");
+       if (file_new)
+               session->evlist = evlist;
+       else {
+               if (!perf_evlist__equal(session->evlist, evlist)) {
+                       fprintf(stderr, "incompatible append\n");
                        exit(-1);
                }
+       }
 
-               if (perf_header_attr__add_id(h_attr, read_data.id) < 0) {
-                       pr_warning("Not enough memory to add id\n");
-                       exit(-1);
-               }
-
-               assert(FD(evsel, nr_cpu, thread_index) >= 0);
-               fcntl(FD(evsel, nr_cpu, thread_index), F_SETFL, O_NONBLOCK);
-
-               /*
-                * First counter acts as the group leader:
-                */
-               if (group && group_fd == -1)
-                       group_fd = FD(evsel, nr_cpu, thread_index);
-
-               if (evsel->idx || thread_index) {
-                       struct perf_evsel *first;
-                       first = list_entry(evsel_list.next, struct perf_evsel, node);
-                       ret = ioctl(FD(evsel, nr_cpu, thread_index),
-                                   PERF_EVENT_IOC_SET_OUTPUT,
-                                   FD(first, nr_cpu, 0));
-                       if (ret) {
-                               error("failed to set output: %d (%s)\n", errno,
-                                               strerror(errno));
-                               exit(-1);
-                       }
-               } else {
-                       mmap_array[nr_cpu].prev = 0;
-                       mmap_array[nr_cpu].mask = mmap_pages*page_size - 1;
-                       mmap_array[nr_cpu].base = mmap(NULL, (mmap_pages+1)*page_size,
-                               PROT_READ | PROT_WRITE, MAP_SHARED, FD(evsel, nr_cpu, thread_index), 0);
-                       if (mmap_array[nr_cpu].base == MAP_FAILED) {
-                               error("failed to mmap with %d (%s)\n", errno, strerror(errno));
-                               exit(-1);
-                       }
-
-                       event_array[nr_poll].fd = FD(evsel, nr_cpu, thread_index);
-                       event_array[nr_poll].events = POLLIN;
-                       nr_poll++;
-               }
-
-               if (filter != NULL) {
-                       ret = ioctl(FD(evsel, nr_cpu, thread_index),
-                                   PERF_EVENT_IOC_SET_FILTER, filter);
-                       if (ret) {
-                               error("failed to set filter with %d (%s)\n", errno,
-                                               strerror(errno));
-                               exit(-1);
-                       }
-               }
-       }
-
-       if (!sample_type)
-               sample_type = attr->sample_type;
-}
-
-static void open_counters(int cpu)
-{
-       struct perf_evsel *pos;
-
-       group_fd = -1;
-
-       list_for_each_entry(pos, &evsel_list, node)
-               create_counter(pos, cpu);
-
-       nr_cpu++;
+       perf_session__update_sample_type(session);
 }
 
 static int process_buildids(void)
@@ -481,14 +364,14 @@ static void atexit_header(void)
 
                if (!no_buildid)
                        process_buildids();
-               perf_header__write(&session->header, output, true);
+               perf_session__write_header(session, evsel_list, output, true);
                perf_session__delete(session);
-               perf_evsel_list__delete();
+               perf_evlist__delete(evsel_list);
                symbol__exit();
        }
 }
 
-static void event__synthesize_guest_os(struct machine *machine, void *data)
+static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
 {
        int err;
        struct perf_session *psession = data;
@@ -504,8 +387,8 @@ static void event__synthesize_guest_os(struct machine *machine, void *data)
         *method is used to avoid symbol missing when the first addr is
         *in module instead of in guest kernel.
         */
-       err = event__synthesize_modules(process_synthesized_event,
-                                       psession, machine);
+       err = perf_event__synthesize_modules(process_synthesized_event,
+                                            psession, machine);
        if (err < 0)
                pr_err("Couldn't record guest kernel [%d]'s reference"
                       " relocation symbol.\n", machine->pid);
@@ -514,11 +397,12 @@ static void event__synthesize_guest_os(struct machine *machine, void *data)
         * We use _stext for guest kernel because guest kernel's /proc/kallsyms
         * have no _text sometimes.
         */
-       err = event__synthesize_kernel_mmap(process_synthesized_event,
-                                           psession, machine, "_text");
+       err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
+                                                psession, machine, "_text");
        if (err < 0)
-               err = event__synthesize_kernel_mmap(process_synthesized_event,
-                                                   psession, machine, "_stext");
+               err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
+                                                        psession, machine,
+                                                        "_stext");
        if (err < 0)
                pr_err("Couldn't record guest kernel [%d]'s reference"
                       " relocation symbol.\n", machine->pid);
@@ -533,9 +417,9 @@ static void mmap_read_all(void)
 {
        int i;
 
-       for (i = 0; i < nr_cpu; i++) {
-               if (mmap_array[i].base)
-                       mmap_read(&mmap_array[i]);
+       for (i = 0; i < evsel_list->cpus->nr; i++) {
+               if (evsel_list->mmap[i].base)
+                       mmap_read(&evsel_list->mmap[i]);
        }
 
        if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
@@ -566,18 +450,26 @@ static int __cmd_record(int argc, const char **argv)
                exit(-1);
        }
 
-       if (!strcmp(output_name, "-"))
-               pipe_output = 1;
-       else if (!stat(output_name, &st) && st.st_size) {
-               if (write_mode == WRITE_FORCE) {
-                       char oldname[PATH_MAX];
-                       snprintf(oldname, sizeof(oldname), "%s.old",
-                                output_name);
-                       unlink(oldname);
-                       rename(output_name, oldname);
+       if (!output_name) {
+               if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
+                       pipe_output = 1;
+               else
+                       output_name = "perf.data";
+       }
+       if (output_name) {
+               if (!strcmp(output_name, "-"))
+                       pipe_output = 1;
+               else if (!stat(output_name, &st) && st.st_size) {
+                       if (write_mode == WRITE_FORCE) {
+                               char oldname[PATH_MAX];
+                               snprintf(oldname, sizeof(oldname), "%s.old",
+                                        output_name);
+                               unlink(oldname);
+                               rename(output_name, oldname);
+                       }
+               } else if (write_mode == WRITE_APPEND) {
+                       write_mode = WRITE_FORCE;
                }
-       } else if (write_mode == WRITE_APPEND) {
-               write_mode = WRITE_FORCE;
        }
 
        flags = O_CREAT|O_RDWR;
@@ -606,19 +498,14 @@ static int __cmd_record(int argc, const char **argv)
                perf_header__set_feat(&session->header, HEADER_BUILD_ID);
 
        if (!file_new) {
-               err = perf_header__read(session, output);
+               err = perf_session__read_header(session, output);
                if (err < 0)
                        goto out_delete_session;
        }
 
-       if (have_tracepoints(&evsel_list))
+       if (have_tracepoints(&evsel_list->entries))
                perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
 
-       /*
-        * perf_session__delete(session) will be called at atexit_header()
-        */
-       atexit(atexit_header);
-
        if (forks) {
                child_pid = fork();
                if (child_pid < 0) {
@@ -659,7 +546,7 @@ static int __cmd_record(int argc, const char **argv)
                }
 
                if (!system_wide && target_tid == -1 && target_pid == -1)
-                       threads->map[0] = child_pid;
+                       evsel_list->threads->map[0] = child_pid;
 
                close(child_ready_pipe[1]);
                close(go_pipe[0]);
@@ -673,46 +560,42 @@ static int __cmd_record(int argc, const char **argv)
                close(child_ready_pipe[0]);
        }
 
-       if (!system_wide && no_inherit && !cpu_list) {
-               open_counters(-1);
-       } else {
-               for (i = 0; i < cpus->nr; i++)
-                       open_counters(cpus->map[i]);
-       }
+       open_counters(evsel_list);
 
-       perf_session__set_sample_type(session, sample_type);
+       /*
+        * perf_session__delete(session) will be called at atexit_header()
+        */
+       atexit(atexit_header);
 
        if (pipe_output) {
                err = perf_header__write_pipe(output);
                if (err < 0)
                        return err;
        } else if (file_new) {
-               err = perf_header__write(&session->header, output, false);
+               err = perf_session__write_header(session, evsel_list,
+                                                output, false);
                if (err < 0)
                        return err;
        }
 
        post_processing_offset = lseek(output, 0, SEEK_CUR);
 
-       perf_session__set_sample_id_all(session, sample_id_all_avail);
-
        if (pipe_output) {
-               err = event__synthesize_attrs(&session->header,
-                                             process_synthesized_event,
-                                             session);
+               err = perf_session__synthesize_attrs(session,
+                                                    process_synthesized_event);
                if (err < 0) {
                        pr_err("Couldn't synthesize attrs.\n");
                        return err;
                }
 
-               err = event__synthesize_event_types(process_synthesized_event,
-                                                   session);
+               err = perf_event__synthesize_event_types(process_synthesized_event,
+                                                        session);
                if (err < 0) {
                        pr_err("Couldn't synthesize event_types.\n");
                        return err;
                }
 
-               if (have_tracepoints(&evsel_list)) {
+               if (have_tracepoints(&evsel_list->entries)) {
                        /*
                         * FIXME err <= 0 here actually means that
                         * there were no tracepoints so its not really
@@ -721,9 +604,9 @@ static int __cmd_record(int argc, const char **argv)
                         * return this more properly and also
                         * propagate errors that now are calling die()
                         */
-                       err = event__synthesize_tracing_data(output, &evsel_list,
-                                                            process_synthesized_event,
-                                                            session);
+                       err = perf_event__synthesize_tracing_data(output, evsel_list,
+                                                                 process_synthesized_event,
+                                                                 session);
                        if (err <= 0) {
                                pr_err("Couldn't record tracing data.\n");
                                return err;
@@ -738,31 +621,34 @@ static int __cmd_record(int argc, const char **argv)
                return -1;
        }
 
-       err = event__synthesize_kernel_mmap(process_synthesized_event,
-                                           session, machine, "_text");
+       err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
+                                                session, machine, "_text");
        if (err < 0)
-               err = event__synthesize_kernel_mmap(process_synthesized_event,
-                                                   session, machine, "_stext");
+               err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
+                                                        session, machine, "_stext");
        if (err < 0)
                pr_err("Couldn't record kernel reference relocation symbol\n"
                       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
                       "Check /proc/kallsyms permission or run as root.\n");
 
-       err = event__synthesize_modules(process_synthesized_event,
-                                       session, machine);
+       err = perf_event__synthesize_modules(process_synthesized_event,
+                                            session, machine);
        if (err < 0)
                pr_err("Couldn't record kernel module information.\n"
                       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
                       "Check /proc/modules permission or run as root.\n");
 
        if (perf_guest)
-               perf_session__process_machines(session, event__synthesize_guest_os);
+               perf_session__process_machines(session,
+                                              perf_event__synthesize_guest_os);
 
        if (!system_wide)
-               event__synthesize_thread(target_tid, process_synthesized_event,
-                                        session);
+               perf_event__synthesize_thread_map(evsel_list->threads,
+                                                 process_synthesized_event,
+                                                 session);
        else
-               event__synthesize_threads(process_synthesized_event, session);
+               perf_event__synthesize_threads(process_synthesized_event,
+                                              session);
 
        if (realtime_prio) {
                struct sched_param param;
@@ -789,17 +675,17 @@ static int __cmd_record(int argc, const char **argv)
                if (hits == samples) {
                        if (done)
                                break;
-                       err = poll(event_array, nr_poll, -1);
+                       err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
                        waking++;
                }
 
                if (done) {
-                       for (i = 0; i < nr_cpu; i++) {
+                       for (i = 0; i < evsel_list->cpus->nr; i++) {
                                struct perf_evsel *pos;
 
-                               list_for_each_entry(pos, &evsel_list, node) {
+                               list_for_each_entry(pos, &evsel_list->entries, node) {
                                        for (thread = 0;
-                                               thread < threads->nr;
+                                               thread < evsel_list->threads->nr;
                                                thread++)
                                                ioctl(FD(pos, i, thread),
                                                        PERF_EVENT_IOC_DISABLE);
@@ -838,10 +724,10 @@ static const char * const record_usage[] = {
 static bool force, append_file;
 
 const struct option record_options[] = {
-       OPT_CALLBACK('e', "event", NULL, "event",
+       OPT_CALLBACK('e', "event", &evsel_list, "event",
                     "event selector. use 'perf list' to list available events",
                     parse_events),
-       OPT_CALLBACK(0, "filter", NULL, "filter",
+       OPT_CALLBACK(0, "filter", &evsel_list, "filter",
                     "event filter", parse_filter),
        OPT_INTEGER('p', "pid", &target_pid,
                    "record events on existing process id"),
@@ -884,6 +770,9 @@ const struct option record_options[] = {
                    "do not update the buildid cache"),
        OPT_BOOLEAN('B', "no-buildid", &no_buildid,
                    "do not collect buildids in perf.data"),
+       OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
+                    "monitor event in cgroup name only",
+                    parse_cgroups),
        OPT_END()
 };
 
@@ -892,6 +781,10 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
        int err = -ENOMEM;
        struct perf_evsel *pos;
 
+       evsel_list = perf_evlist__new(NULL, NULL);
+       if (evsel_list == NULL)
+               return -ENOMEM;
+
        argc = parse_options(argc, argv, record_options, record_usage,
                            PARSE_OPT_STOP_AT_NON_OPTION);
        if (!argc && target_pid == -1 && target_tid == -1 &&
@@ -908,12 +801,19 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
                write_mode = WRITE_FORCE;
        }
 
+       if (nr_cgroups && !system_wide) {
+               fprintf(stderr, "cgroup monitoring only available in"
+                       " system-wide mode\n");
+               usage_with_options(record_usage, record_options);
+       }
+
        symbol__init();
 
        if (no_buildid_cache || no_buildid)
                disable_buildid_cache();
 
-       if (list_empty(&evsel_list) && perf_evsel_list__create_default() < 0) {
+       if (evsel_list->nr_entries == 0 &&
+           perf_evlist__add_default(evsel_list) < 0) {
                pr_err("Not enough memory for event selector list\n");
                goto out_symbol_exit;
        }
@@ -921,27 +821,19 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
        if (target_pid != -1)
                target_tid = target_pid;
 
-       threads = thread_map__new(target_pid, target_tid);
-       if (threads == NULL) {
-               pr_err("Problems finding threads of monitor\n");
+       if (perf_evlist__create_maps(evsel_list, target_pid,
+                                    target_tid, cpu_list) < 0)
                usage_with_options(record_usage, record_options);
-       }
 
-       cpus = cpu_map__new(cpu_list);
-       if (cpus == NULL) {
-               perror("failed to parse CPUs map");
-               return -1;
-       }
-
-       list_for_each_entry(pos, &evsel_list, node) {
-               if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
+       list_for_each_entry(pos, &evsel_list->entries, node) {
+               if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr,
+                                        evsel_list->threads->nr) < 0)
                        goto out_free_fd;
                if (perf_header__push_event(pos->attr.config, event_name(pos)))
                        goto out_free_fd;
        }
-       event_array = malloc((sizeof(struct pollfd) * MAX_NR_CPUS *
-                             MAX_COUNTERS * threads->nr));
-       if (!event_array)
+
+       if (perf_evlist__alloc_pollfd(evsel_list) < 0)
                goto out_free_fd;
 
        if (user_interval != ULLONG_MAX)
@@ -959,16 +851,12 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
        } else {
                fprintf(stderr, "frequency and count are zero, aborting\n");
                err = -EINVAL;
-               goto out_free_event_array;
+               goto out_free_fd;
        }
 
        err = __cmd_record(argc, argv);
-
-out_free_event_array:
-       free(event_array);
 out_free_fd:
-       thread_map__delete(threads);
-       threads = NULL;
+       perf_evlist__delete_maps(evsel_list);
 out_symbol_exit:
        symbol__exit();
        return err;
index c27e31f..b1b8200 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "util/util.h"
 
+#include "util/annotate.h"
 #include "util/color.h"
 #include <linux/list.h>
 #include "util/cache.h"
@@ -20,6 +21,8 @@
 
 #include "perf.h"
 #include "util/debug.h"
+#include "util/evlist.h"
+#include "util/evsel.h"
 #include "util/header.h"
 #include "util/session.h"
 
@@ -43,120 +46,79 @@ static const char  default_pretty_printing_style[] = "normal";
 static const char      *pretty_printing_style = default_pretty_printing_style;
 
 static char            callchain_default_opt[] = "fractal,0.5";
+static symbol_filter_t annotate_init;
 
-static struct hists *perf_session__hists_findnew(struct perf_session *self,
-                                                u64 event_stream, u32 type,
-                                                u64 config)
-{
-       struct rb_node **p = &self->hists_tree.rb_node;
-       struct rb_node *parent = NULL;
-       struct hists *iter, *new;
-
-       while (*p != NULL) {
-               parent = *p;
-               iter = rb_entry(parent, struct hists, rb_node);
-               if (iter->config == config)
-                       return iter;
-
-
-               if (config > iter->config)
-                       p = &(*p)->rb_right;
-               else
-                       p = &(*p)->rb_left;
-       }
-
-       new = malloc(sizeof(struct hists));
-       if (new == NULL)
-               return NULL;
-       memset(new, 0, sizeof(struct hists));
-       new->event_stream = event_stream;
-       new->config = config;
-       new->type = type;
-       rb_link_node(&new->rb_node, parent, p);
-       rb_insert_color(&new->rb_node, &self->hists_tree);
-       return new;
-}
-
-static int perf_session__add_hist_entry(struct perf_session *self,
+static int perf_session__add_hist_entry(struct perf_session *session,
                                        struct addr_location *al,
-                                       struct sample_data *data)
+                                       struct perf_sample *sample)
 {
-       struct map_symbol *syms = NULL;
        struct symbol *parent = NULL;
-       int err = -ENOMEM;
+       int err = 0;
        struct hist_entry *he;
-       struct hists *hists;
-       struct perf_event_attr *attr;
-
-       if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) {
-               syms = perf_session__resolve_callchain(self, al->thread,
-                                                      data->callchain, &parent);
-               if (syms == NULL)
-                       return -ENOMEM;
+       struct perf_evsel *evsel;
+
+       if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
+               err = perf_session__resolve_callchain(session, al->thread,
+                                                     sample->callchain, &parent);
+               if (err)
+                       return err;
        }
 
-       attr = perf_header__find_attr(data->id, &self->header);
-       if (attr)
-               hists = perf_session__hists_findnew(self, data->id, attr->type, attr->config);
-       else
-               hists = perf_session__hists_findnew(self, data->id, 0, 0);
-       if (hists == NULL)
-               goto out_free_syms;
-       he = __hists__add_entry(hists, al, parent, data->period);
+       evsel = perf_evlist__id2evsel(session->evlist, sample->id);
+       if (evsel == NULL) {
+               /*
+                * FIXME: Propagate this back, but at least we're in a builtin,
+                * where exit() is allowed. ;-)
+                */
+               ui__warning("Invalid %s file, contains samples with id %" PRIu64 " not in "
+                           "its header!\n", input_name, sample->id);
+               exit_browser(0);
+               exit(1);
+       }
+
+       he = __hists__add_entry(&evsel->hists, al, parent, sample->period);
        if (he == NULL)
-               goto out_free_syms;
-       err = 0;
+               return -ENOMEM;
+
        if (symbol_conf.use_callchain) {
-               err = callchain_append(he->callchain, data->callchain, syms,
-                                      data->period);
+               err = callchain_append(he->callchain, &session->callchain_cursor,
+                                      sample->period);
                if (err)
-                       goto out_free_syms;
+                       return err;
        }
        /*
         * Only in the newt browser we are doing integrated annotation,
         * so we don't allocated the extra space needed because the stdio
         * code will not use it.
         */
-       if (use_browser > 0)
-               err = hist_entry__inc_addr_samples(he, al->addr);
-out_free_syms:
-       free(syms);
-       return err;
-}
+       if (al->sym != NULL && use_browser > 0) {
+               struct annotation *notes = symbol__annotation(he->ms.sym);
 
-static int add_event_total(struct perf_session *session,
-                          struct sample_data *data,
-                          struct perf_event_attr *attr)
-{
-       struct hists *hists;
+               assert(evsel != NULL);
 
-       if (attr)
-               hists = perf_session__hists_findnew(session, data->id,
-                                                   attr->type, attr->config);
-       else
-               hists = perf_session__hists_findnew(session, data->id, 0, 0);
+               err = -ENOMEM;
+               if (notes->src == NULL &&
+                   symbol__alloc_hist(he->ms.sym, session->evlist->nr_entries) < 0)
+                       goto out;
 
-       if (!hists)
-               return -ENOMEM;
+               err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
+       }
 
-       hists->stats.total_period += data->period;
-       /*
-        * FIXME: add_event_total should be moved from here to
-        * perf_session__process_event so that the proper hist is passed to
-        * the event_op methods.
-        */
-       hists__inc_nr_events(hists, PERF_RECORD_SAMPLE);
-       session->hists.stats.total_period += data->period;
-       return 0;
+       evsel->hists.stats.total_period += sample->period;
+       hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
+out:
+       return err;
 }
 
-static int process_sample_event(event_t *event, struct sample_data *sample,
+
+static int process_sample_event(union perf_event *event,
+                               struct perf_sample *sample,
                                struct perf_session *session)
 {
        struct addr_location al;
-       struct perf_event_attr *attr;
 
-       if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) {
+       if (perf_event__preprocess_sample(event, session, &al, sample,
+                                         annotate_init) < 0) {
                fprintf(stderr, "problem processing %d event, skipping it.\n",
                        event->header.type);
                return -1;
@@ -170,26 +132,17 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
                return -1;
        }
 
-       attr = perf_header__find_attr(sample->id, &session->header);
-
-       if (add_event_total(session, sample, attr)) {
-               pr_debug("problem adding event period\n");
-               return -1;
-       }
-
        return 0;
 }
 
-static int process_read_event(event_t *event, struct sample_data *sample __used,
-                             struct perf_session *session __used)
+static int process_read_event(union perf_event *event,
+                             struct perf_sample *sample __used,
+                             struct perf_session *session)
 {
-       struct perf_event_attr *attr;
-
-       attr = perf_header__find_attr(event->read.id, &session->header);
-
+       struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist,
+                                                        event->read.id);
        if (show_threads) {
-               const char *name = attr ? __event_name(attr->type, attr->config)
-                                  : "unknown";
+               const char *name = evsel ? event_name(evsel) : "unknown";
                perf_read_values_add_value(&show_threads_values,
                                           event->read.pid, event->read.tid,
                                           event->read.id,
@@ -198,7 +151,7 @@ static int process_read_event(event_t *event, struct sample_data *sample __used,
        }
 
        dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
-                   attr ? __event_name(attr->type, attr->config) : "FAIL",
+                   evsel ? event_name(evsel) : "FAIL",
                    event->read.value);
 
        return 0;
@@ -222,7 +175,7 @@ static int perf_session__setup_sample_type(struct perf_session *self)
        } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE &&
                   !symbol_conf.use_callchain) {
                        symbol_conf.use_callchain = true;
-                       if (register_callchain_param(&callchain_param) < 0) {
+                       if (callchain_register_param(&callchain_param) < 0) {
                                fprintf(stderr, "Can't register callchain"
                                                " params\n");
                                return -EINVAL;
@@ -233,17 +186,17 @@ static int perf_session__setup_sample_type(struct perf_session *self)
 }
 
 static struct perf_event_ops event_ops = {
-       .sample = process_sample_event,
-       .mmap   event__process_mmap,
-       .comm   event__process_comm,
-       .exit   event__process_task,
-       .fork   event__process_task,
-       .lost   event__process_lost,
-       .read   = process_read_event,
-       .attr   event__process_attr,
-       .event_type event__process_event_type,
-       .tracing_data event__process_tracing_data,
-       .build_id event__process_build_id,
+       .sample          = process_sample_event,
+       .mmap            = perf_event__process_mmap,
+       .comm            = perf_event__process_comm,
+       .exit            = perf_event__process_task,
+       .fork            = perf_event__process_task,
+       .lost            = perf_event__process_lost,
+       .read            = process_read_event,
+       .attr            = perf_event__process_attr,
+       .event_type      = perf_event__process_event_type,
+       .tracing_data    = perf_event__process_tracing_data,
+       .build_id        = perf_event__process_build_id,
        .ordered_samples = true,
        .ordering_requires_timestamps = true,
 };
@@ -269,21 +222,21 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
        return ret + fprintf(fp, "\n#\n");
 }
 
-static int hists__tty_browse_tree(struct rb_root *tree, const char *help)
+static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
+                                        const char *help)
 {
-       struct rb_node *next = rb_first(tree);
+       struct perf_evsel *pos;
 
-       while (next) {
-               struct hists *hists = rb_entry(next, struct hists, rb_node);
+       list_for_each_entry(pos, &evlist->entries, node) {
+               struct hists *hists = &pos->hists;
                const char *evname = NULL;
 
                if (rb_first(&hists->entries) != rb_last(&hists->entries))
-                       evname = __event_name(hists->type, hists->config);
+                       evname = event_name(pos);
 
                hists__fprintf_nr_sample_events(hists, evname, stdout);
                hists__fprintf(hists, NULL, false, stdout);
                fprintf(stdout, "\n\n");
-               next = rb_next(&hists->rb_node);
        }
 
        if (sort_order == default_sort_order &&
@@ -304,8 +257,9 @@ static int hists__tty_browse_tree(struct rb_root *tree, const char *help)
 static int __cmd_report(void)
 {
        int ret = -EINVAL;
+       u64 nr_samples;
        struct perf_session *session;
-       struct rb_node *next;
+       struct perf_evsel *pos;
        const char *help = "For a higher level overview, try: perf report --sort comm,dso";
 
        signal(SIGINT, sig_handler);
@@ -336,20 +290,24 @@ static int __cmd_report(void)
        if (verbose > 2)
                perf_session__fprintf_dsos(session, stdout);
 
-       next = rb_first(&session->hists_tree);
-       while (next) {
-               struct hists *hists;
+       nr_samples = 0;
+       list_for_each_entry(pos, &session->evlist->entries, node) {
+               struct hists *hists = &pos->hists;
 
-               hists = rb_entry(next, struct hists, rb_node);
                hists__collapse_resort(hists);
                hists__output_resort(hists);
-               next = rb_next(&hists->rb_node);
+               nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
+       }
+
+       if (nr_samples == 0) {
+               ui__warning("The %s file has no samples!\n", input_name);
+               goto out_delete;
        }
 
        if (use_browser > 0)
-               hists__tui_browse_tree(&session->hists_tree, help);
+               perf_evlist__tui_browse_hists(session->evlist, help);
        else
-               hists__tty_browse_tree(&session->hists_tree, help);
+               perf_evlist__tty_browse_hists(session->evlist, help);
 
 out_delete:
        /*
@@ -424,7 +382,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
        if (tok2)
                callchain_param.print_limit = strtod(tok2, &endptr);
 setup:
-       if (register_callchain_param(&callchain_param) < 0) {
+       if (callchain_register_param(&callchain_param) < 0) {
                fprintf(stderr, "Can't register callchain params\n");
                return -1;
        }
@@ -498,7 +456,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
                use_browser = 1;
 
        if (strcmp(input_name, "-") != 0)
-               setup_browser();
+               setup_browser(true);
        else
                use_browser = 0;
        /*
@@ -507,7 +465,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
         * implementation.
         */
        if (use_browser > 0) {
-               symbol_conf.priv_size = sizeof(struct sym_priv);
+               symbol_conf.priv_size = sizeof(struct annotation);
+               annotate_init         = symbol__annotate_init;
                /*
                 * For searching by name on the "Browse map details".
                 * providing it only in verbose mode not to bloat too
index 29acb89..a32f411 100644 (file)
@@ -369,11 +369,6 @@ static void
 process_sched_event(struct task_desc *this_task __used, struct sched_atom *atom)
 {
        int ret = 0;
-       u64 now;
-       long long delta;
-
-       now = get_nsecs();
-       delta = start_time + atom->timestamp - now;
 
        switch (atom->type) {
                case SCHED_EVENT_RUN:
@@ -562,7 +557,7 @@ static void wait_for_tasks(void)
 
 static void run_one_test(void)
 {
-       u64 T0, T1, delta, avg_delta, fluct, std_dev;
+       u64 T0, T1, delta, avg_delta, fluct;
 
        T0 = get_nsecs();
        wait_for_tasks();
@@ -578,7 +573,6 @@ static void run_one_test(void)
        else
                fluct = delta - avg_delta;
        sum_fluct += fluct;
-       std_dev = sum_fluct / nr_runs / sqrt(nr_runs);
        if (!run_avg)
                run_avg = delta;
        run_avg = (run_avg*9 + delta)/10;
@@ -799,7 +793,7 @@ replay_switch_event(struct trace_switch_event *switch_event,
                    u64 timestamp,
                    struct thread *thread __used)
 {
-       struct task_desc *prev, *next;
+       struct task_desc *prev, __used *next;
        u64 timestamp0;
        s64 delta;
 
@@ -1404,7 +1398,7 @@ map_switch_event(struct trace_switch_event *switch_event,
                 u64 timestamp,
                 struct thread *thread __used)
 {
-       struct thread *sched_out, *sched_in;
+       struct thread *sched_out __used, *sched_in;
        int new_shortname;
        u64 timestamp0;
        s64 delta;
@@ -1580,9 +1574,9 @@ process_sched_migrate_task_event(void *data, struct perf_session *session,
                                                 event, cpu, timestamp, thread);
 }
 
-static void
-process_raw_event(event_t *raw_event __used, struct perf_session *session,
-                 void *data, int cpu, u64 timestamp, struct thread *thread)
+static void process_raw_event(union perf_event *raw_event __used,
+                             struct perf_session *session, void *data, int cpu,
+                             u64 timestamp, struct thread *thread)
 {
        struct event *event;
        int type;
@@ -1607,7 +1601,8 @@ process_raw_event(event_t *raw_event __used, struct perf_session *session,
                process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread);
 }
 
-static int process_sample_event(event_t *event, struct sample_data *sample,
+static int process_sample_event(union perf_event *event,
+                               struct perf_sample *sample,
                                struct perf_session *session)
 {
        struct thread *thread;
@@ -1635,9 +1630,9 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
 
 static struct perf_event_ops event_ops = {
        .sample                 = process_sample_event,
-       .comm                   = event__process_comm,
-       .lost                   = event__process_lost,
-       .fork                   = event__process_task,
+       .comm                   = perf_event__process_comm,
+       .lost                   = perf_event__process_lost,
+       .fork                   = perf_event__process_task,
        .ordered_samples        = true,
 };
 
index b766c2a..5f40df6 100644 (file)
@@ -63,7 +63,8 @@ static int cleanup_scripting(void)
 
 static char const              *input_name = "perf.data";
 
-static int process_sample_event(event_t *event, struct sample_data *sample,
+static int process_sample_event(union perf_event *event,
+                               struct perf_sample *sample,
                                struct perf_session *session)
 {
        struct thread *thread = perf_session__findnew(session, event->ip.pid);
@@ -100,14 +101,14 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
 }
 
 static struct perf_event_ops event_ops = {
-       .sample = process_sample_event,
-       .comm   = event__process_comm,
-       .attr   = event__process_attr,
-       .event_type = event__process_event_type,
-       .tracing_data = event__process_tracing_data,
-       .build_id = event__process_build_id,
-       .ordering_requires_timestamps = true,
+       .sample          = process_sample_event,
+       .comm            = perf_event__process_comm,
+       .attr            = perf_event__process_attr,
+       .event_type      = perf_event__process_event_type,
+       .tracing_data    = perf_event__process_tracing_data,
+       .build_id        = perf_event__process_build_id,
        .ordered_samples = true,
+       .ordering_requires_timestamps = true,
 };
 
 extern volatile int session_done;
index a482a19..21c0252 100644 (file)
 #include "util/parse-options.h"
 #include "util/parse-events.h"
 #include "util/event.h"
+#include "util/evlist.h"
 #include "util/evsel.h"
 #include "util/debug.h"
 #include "util/header.h"
 #include "util/cpumap.h"
 #include "util/thread.h"
+#include "util/thread_map.h"
 
 #include <sys/prctl.h>
 #include <math.h>
@@ -71,8 +73,9 @@ static struct perf_event_attr default_attrs[] = {
 
 };
 
+struct perf_evlist             *evsel_list;
+
 static bool                    system_wide                     =  false;
-static struct cpu_map          *cpus;
 static int                     run_idx                         =  0;
 
 static int                     run_count                       =  1;
@@ -81,7 +84,6 @@ static bool                   scale                           =  true;
 static bool                    no_aggr                         = false;
 static pid_t                   target_pid                      = -1;
 static pid_t                   target_tid                      = -1;
-static struct thread_map       *threads;
 static pid_t                   child_pid                       = -1;
 static bool                    null_run                        =  false;
 static bool                    big_num                         =  true;
@@ -166,7 +168,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
                                    PERF_FORMAT_TOTAL_TIME_RUNNING;
 
        if (system_wide)
-               return perf_evsel__open_per_cpu(evsel, cpus);
+               return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, false, false);
 
        attr->inherit = !no_inherit;
        if (target_pid == -1 && target_tid == -1) {
@@ -174,7 +176,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
                attr->enable_on_exec = 1;
        }
 
-       return perf_evsel__open_per_thread(evsel, threads);
+       return perf_evsel__open_per_thread(evsel, evsel_list->threads, false, false);
 }
 
 /*
@@ -199,7 +201,8 @@ static int read_counter_aggr(struct perf_evsel *counter)
        u64 *count = counter->counts->aggr.values;
        int i;
 
-       if (__perf_evsel__read(counter, cpus->nr, threads->nr, scale) < 0)
+       if (__perf_evsel__read(counter, evsel_list->cpus->nr,
+                              evsel_list->threads->nr, scale) < 0)
                return -1;
 
        for (i = 0; i < 3; i++)
@@ -232,7 +235,7 @@ static int read_counter(struct perf_evsel *counter)
        u64 *count;
        int cpu;
 
-       for (cpu = 0; cpu < cpus->nr; cpu++) {
+       for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) {
                if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0)
                        return -1;
 
@@ -297,7 +300,7 @@ static int run_perf_stat(int argc __used, const char **argv)
                }
 
                if (target_tid == -1 && target_pid == -1 && !system_wide)
-                       threads->map[0] = child_pid;
+                       evsel_list->threads->map[0] = child_pid;
 
                /*
                 * Wait for the child to be ready to exec.
@@ -309,7 +312,7 @@ static int run_perf_stat(int argc __used, const char **argv)
                close(child_ready_pipe[0]);
        }
 
-       list_for_each_entry(counter, &evsel_list, node) {
+       list_for_each_entry(counter, &evsel_list->entries, node) {
                if (create_perf_stat_counter(counter) < 0) {
                        if (errno == -EPERM || errno == -EACCES) {
                                error("You may not have permission to collect %sstats.\n"
@@ -347,14 +350,15 @@ static int run_perf_stat(int argc __used, const char **argv)
        update_stats(&walltime_nsecs_stats, t1 - t0);
 
        if (no_aggr) {
-               list_for_each_entry(counter, &evsel_list, node) {
+               list_for_each_entry(counter, &evsel_list->entries, node) {
                        read_counter(counter);
-                       perf_evsel__close_fd(counter, cpus->nr, 1);
+                       perf_evsel__close_fd(counter, evsel_list->cpus->nr, 1);
                }
        } else {
-               list_for_each_entry(counter, &evsel_list, node) {
+               list_for_each_entry(counter, &evsel_list->entries, node) {
                        read_counter_aggr(counter);
-                       perf_evsel__close_fd(counter, cpus->nr, threads->nr);
+                       perf_evsel__close_fd(counter, evsel_list->cpus->nr,
+                                            evsel_list->threads->nr);
                }
        }
 
@@ -382,10 +386,13 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
        if (no_aggr)
                sprintf(cpustr, "CPU%*d%s",
                        csv_output ? 0 : -4,
-                       cpus->map[cpu], csv_sep);
+                       evsel_list->cpus->map[cpu], csv_sep);
 
        fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(evsel));
 
+       if (evsel->cgrp)
+               fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name);
+
        if (csv_output)
                return;
 
@@ -410,12 +417,15 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
        if (no_aggr)
                sprintf(cpustr, "CPU%*d%s",
                        csv_output ? 0 : -4,
-                       cpus->map[cpu], csv_sep);
+                       evsel_list->cpus->map[cpu], csv_sep);
        else
                cpu = 0;
 
        fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(evsel));
 
+       if (evsel->cgrp)
+               fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name);
+
        if (csv_output)
                return;
 
@@ -456,9 +466,17 @@ static void print_counter_aggr(struct perf_evsel *counter)
        int scaled = counter->counts->scaled;
 
        if (scaled == -1) {
-               fprintf(stderr, "%*s%s%-24s\n",
+               fprintf(stderr, "%*s%s%*s",
                        csv_output ? 0 : 18,
-                       "<not counted>", csv_sep, event_name(counter));
+                       "<not counted>",
+                       csv_sep,
+                       csv_output ? 0 : -24,
+                       event_name(counter));
+
+               if (counter->cgrp)
+                       fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name);
+
+               fputc('\n', stderr);
                return;
        }
 
@@ -483,7 +501,6 @@ static void print_counter_aggr(struct perf_evsel *counter)
                fprintf(stderr, "  (scaled from %.2f%%)",
                                100 * avg_running / avg_enabled);
        }
-
        fprintf(stderr, "\n");
 }
 
@@ -496,19 +513,23 @@ static void print_counter(struct perf_evsel *counter)
        u64 ena, run, val;
        int cpu;
 
-       for (cpu = 0; cpu < cpus->nr; cpu++) {
+       for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) {
                val = counter->counts->cpu[cpu].val;
                ena = counter->counts->cpu[cpu].ena;
                run = counter->counts->cpu[cpu].run;
                if (run == 0 || ena == 0) {
-                       fprintf(stderr, "CPU%*d%s%*s%s%-24s",
+                       fprintf(stderr, "CPU%*d%s%*s%s%*s",
                                csv_output ? 0 : -4,
-                               cpus->map[cpu], csv_sep,
+                               evsel_list->cpus->map[cpu], csv_sep,
                                csv_output ? 0 : 18,
                                "<not counted>", csv_sep,
+                               csv_output ? 0 : -24,
                                event_name(counter));
 
-                       fprintf(stderr, "\n");
+                       if (counter->cgrp)
+                               fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name);
+
+                       fputc('\n', stderr);
                        continue;
                }
 
@@ -525,7 +546,7 @@ static void print_counter(struct perf_evsel *counter)
                                        100.0 * run / ena);
                        }
                }
-               fprintf(stderr, "\n");
+               fputc('\n', stderr);
        }
 }
 
@@ -555,10 +576,10 @@ static void print_stat(int argc, const char **argv)
        }
 
        if (no_aggr) {
-               list_for_each_entry(counter, &evsel_list, node)
+               list_for_each_entry(counter, &evsel_list->entries, node)
                        print_counter(counter);
        } else {
-               list_for_each_entry(counter, &evsel_list, node)
+               list_for_each_entry(counter, &evsel_list->entries, node)
                        print_counter_aggr(counter);
        }
 
@@ -610,7 +631,7 @@ static int stat__set_big_num(const struct option *opt __used,
 }
 
 static const struct option options[] = {
-       OPT_CALLBACK('e', "event", NULL, "event",
+       OPT_CALLBACK('e', "event", &evsel_list, "event",
                     "event selector. use 'perf list' to list available events",
                     parse_events),
        OPT_BOOLEAN('i', "no-inherit", &no_inherit,
@@ -638,6 +659,9 @@ static const struct option options[] = {
                    "disable CPU count aggregation"),
        OPT_STRING('x', "field-separator", &csv_sep, "separator",
                   "print counts with custom separator"),
+       OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
+                    "monitor event in cgroup name only",
+                    parse_cgroups),
        OPT_END()
 };
 
@@ -648,6 +672,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
 
        setlocale(LC_ALL, "");
 
+       evsel_list = perf_evlist__new(NULL, NULL);
+       if (evsel_list == NULL)
+               return -ENOMEM;
+
        argc = parse_options(argc, argv, options, stat_usage,
                PARSE_OPT_STOP_AT_NON_OPTION);
 
@@ -674,49 +702,50 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
        if (run_count <= 0)
                usage_with_options(stat_usage, options);
 
-       /* no_aggr is for system-wide only */
-       if (no_aggr && !system_wide)
+       /* no_aggr, cgroup are for system-wide only */
+       if ((no_aggr || nr_cgroups) && !system_wide) {
+               fprintf(stderr, "both cgroup and no-aggregation "
+                       "modes only available in system-wide mode\n");
+
                usage_with_options(stat_usage, options);
+       }
 
        /* Set attrs and nr_counters if no event is selected and !null_run */
-       if (!null_run && !nr_counters) {
+       if (!null_run && !evsel_list->nr_entries) {
                size_t c;
 
-               nr_counters = ARRAY_SIZE(default_attrs);
-
                for (c = 0; c < ARRAY_SIZE(default_attrs); ++c) {
-                       pos = perf_evsel__new(&default_attrs[c],
-                                             nr_counters);
+                       pos = perf_evsel__new(&default_attrs[c], c);
                        if (pos == NULL)
                                goto out;
-                       list_add(&pos->node, &evsel_list);
+                       perf_evlist__add(evsel_list, pos);
                }
        }
 
        if (target_pid != -1)
                target_tid = target_pid;
 
-       threads = thread_map__new(target_pid, target_tid);
-       if (threads == NULL) {
+       evsel_list->threads = thread_map__new(target_pid, target_tid);
+       if (evsel_list->threads == NULL) {
                pr_err("Problems finding threads of monitor\n");
                usage_with_options(stat_usage, options);
        }
 
        if (system_wide)
-               cpus = cpu_map__new(cpu_list);
+               evsel_list->cpus = cpu_map__new(cpu_list);
        else
-               cpus = cpu_map__dummy_new();
+               evsel_list->cpus = cpu_map__dummy_new();
 
-       if (cpus == NULL) {
+       if (evsel_list->cpus == NULL) {
                perror("failed to parse CPUs map");
                usage_with_options(stat_usage, options);
                return -1;
        }
 
-       list_for_each_entry(pos, &evsel_list, node) {
+       list_for_each_entry(pos, &evsel_list->entries, node) {
                if (perf_evsel__alloc_stat_priv(pos) < 0 ||
-                   perf_evsel__alloc_counts(pos, cpus->nr) < 0 ||
-                   perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
+                   perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0 ||
+                   perf_evsel__alloc_fd(pos, evsel_list->cpus->nr, evsel_list->threads->nr) < 0)
                        goto out_free_fd;
        }
 
@@ -741,11 +770,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
        if (status != -1)
                print_stat(argc, argv);
 out_free_fd:
-       list_for_each_entry(pos, &evsel_list, node)
+       list_for_each_entry(pos, &evsel_list->entries, node)
                perf_evsel__free_stat_priv(pos);
-       perf_evsel_list__delete();
+       perf_evlist__delete_maps(evsel_list);
 out:
-       thread_map__delete(threads);
-       threads = NULL;
+       perf_evlist__delete(evsel_list);
        return status;
 }
index 5dcdba6..1b2106c 100644 (file)
@@ -7,10 +7,11 @@
 
 #include "util/cache.h"
 #include "util/debug.h"
+#include "util/evlist.h"
 #include "util/parse-options.h"
-#include "util/session.h"
+#include "util/parse-events.h"
 #include "util/symbol.h"
-#include "util/thread.h"
+#include "util/thread_map.h"
 
 static long page_size;
 
@@ -238,14 +239,14 @@ out:
 #include "util/evsel.h"
 #include <sys/types.h>
 
-static int trace_event__id(const char *event_name)
+static int trace_event__id(const char *evname)
 {
        char *filename;
        int err = -1, fd;
 
        if (asprintf(&filename,
                     "/sys/kernel/debug/tracing/events/syscalls/%s/id",
-                    event_name) < 0)
+                    evname) < 0)
                return -1;
 
        fd = open(filename, O_RDONLY);
@@ -289,7 +290,7 @@ static int test__open_syscall_event(void)
                goto out_thread_map_delete;
        }
 
-       if (perf_evsel__open_per_thread(evsel, threads) < 0) {
+       if (perf_evsel__open_per_thread(evsel, threads, false, false) < 0) {
                pr_debug("failed to open counter: %s, "
                         "tweak /proc/sys/kernel/perf_event_paranoid?\n",
                         strerror(errno));
@@ -347,9 +348,9 @@ static int test__open_syscall_event_on_all_cpus(void)
        }
 
        cpus = cpu_map__new(NULL);
-       if (threads == NULL) {
-               pr_debug("thread_map__new\n");
-               return -1;
+       if (cpus == NULL) {
+               pr_debug("cpu_map__new\n");
+               goto out_thread_map_delete;
        }
 
 
@@ -364,7 +365,7 @@ static int test__open_syscall_event_on_all_cpus(void)
                goto out_thread_map_delete;
        }
 
-       if (perf_evsel__open(evsel, cpus, threads) < 0) {
+       if (perf_evsel__open(evsel, cpus, threads, false, false) < 0) {
                pr_debug("failed to open counter: %s, "
                         "tweak /proc/sys/kernel/perf_event_paranoid?\n",
                         strerror(errno));
@@ -408,6 +409,8 @@ static int test__open_syscall_event_on_all_cpus(void)
                goto out_close_fd;
        }
 
+       err = 0;
+
        for (cpu = 0; cpu < cpus->nr; ++cpu) {
                unsigned int expected;
 
@@ -416,18 +419,18 @@ static int test__open_syscall_event_on_all_cpus(void)
 
                if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) {
                        pr_debug("perf_evsel__open_read_on_cpu\n");
-                       goto out_close_fd;
+                       err = -1;
+                       break;
                }
 
                expected = nr_open_calls + cpu;
                if (evsel->counts->cpu[cpu].val != expected) {
                        pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n",
                                 expected, cpus->map[cpu], evsel->counts->cpu[cpu].val);
-                       goto out_close_fd;
+                       err = -1;
                }
        }
 
-       err = 0;
 out_close_fd:
        perf_evsel__close_fd(evsel, 1, threads->nr);
 out_evsel_delete:
@@ -437,6 +440,159 @@ out_thread_map_delete:
        return err;
 }
 
+/*
+ * This test will generate random numbers of calls to some getpid syscalls,
+ * then establish an mmap for a group of events that are created to monitor
+ * the syscalls.
+ *
+ * It will receive the events, using mmap, use its PERF_SAMPLE_ID generated
+ * sample.id field to map back to its respective perf_evsel instance.
+ *
+ * Then it checks if the number of syscalls reported as perf events by
+ * the kernel corresponds to the number of syscalls made.
+ */
+static int test__basic_mmap(void)
+{
+       int err = -1;
+       union perf_event *event;
+       struct thread_map *threads;
+       struct cpu_map *cpus;
+       struct perf_evlist *evlist;
+       struct perf_event_attr attr = {
+               .type           = PERF_TYPE_TRACEPOINT,
+               .read_format    = PERF_FORMAT_ID,
+               .sample_type    = PERF_SAMPLE_ID,
+               .watermark      = 0,
+       };
+       cpu_set_t cpu_set;
+       const char *syscall_names[] = { "getsid", "getppid", "getpgrp",
+                                       "getpgid", };
+       pid_t (*syscalls[])(void) = { (void *)getsid, getppid, getpgrp,
+                                     (void*)getpgid };
+#define nsyscalls ARRAY_SIZE(syscall_names)
+       int ids[nsyscalls];
+       unsigned int nr_events[nsyscalls],
+                    expected_nr_events[nsyscalls], i, j;
+       struct perf_evsel *evsels[nsyscalls], *evsel;
+
+       for (i = 0; i < nsyscalls; ++i) {
+               char name[64];
+
+               snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);
+               ids[i] = trace_event__id(name);
+               if (ids[i] < 0) {
+                       pr_debug("Is debugfs mounted on /sys/kernel/debug?\n");
+                       return -1;
+               }
+               nr_events[i] = 0;
+               expected_nr_events[i] = random() % 257;
+       }
+
+       threads = thread_map__new(-1, getpid());
+       if (threads == NULL) {
+               pr_debug("thread_map__new\n");
+               return -1;
+       }
+
+       cpus = cpu_map__new(NULL);
+       if (cpus == NULL) {
+               pr_debug("cpu_map__new\n");
+               goto out_free_threads;
+       }
+
+       CPU_ZERO(&cpu_set);
+       CPU_SET(cpus->map[0], &cpu_set);
+       sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
+       if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
+               pr_debug("sched_setaffinity() failed on CPU %d: %s ",
+                        cpus->map[0], strerror(errno));
+               goto out_free_cpus;
+       }
+
+       evlist = perf_evlist__new(cpus, threads);
+       if (evlist == NULL) {
+               pr_debug("perf_evlist__new\n");
+               goto out_free_cpus;
+       }
+
+       /* anonymous union fields, can't be initialized above */
+       attr.wakeup_events = 1;
+       attr.sample_period = 1;
+
+       for (i = 0; i < nsyscalls; ++i) {
+               attr.config = ids[i];
+               evsels[i] = perf_evsel__new(&attr, i);
+               if (evsels[i] == NULL) {
+                       pr_debug("perf_evsel__new\n");
+                       goto out_free_evlist;
+               }
+
+               perf_evlist__add(evlist, evsels[i]);
+
+               if (perf_evsel__open(evsels[i], cpus, threads, false, false) < 0) {
+                       pr_debug("failed to open counter: %s, "
+                                "tweak /proc/sys/kernel/perf_event_paranoid?\n",
+                                strerror(errno));
+                       goto out_close_fd;
+               }
+       }
+
+       if (perf_evlist__mmap(evlist, 128, true) < 0) {
+               pr_debug("failed to mmap events: %d (%s)\n", errno,
+                        strerror(errno));
+               goto out_close_fd;
+       }
+
+       for (i = 0; i < nsyscalls; ++i)
+               for (j = 0; j < expected_nr_events[i]; ++j) {
+                       int foo = syscalls[i]();
+                       ++foo;
+               }
+
+       while ((event = perf_evlist__read_on_cpu(evlist, 0)) != NULL) {
+               struct perf_sample sample;
+
+               if (event->header.type != PERF_RECORD_SAMPLE) {
+                       pr_debug("unexpected %s event\n",
+                                perf_event__name(event->header.type));
+                       goto out_munmap;
+               }
+
+               perf_event__parse_sample(event, attr.sample_type, false, &sample);
+               evsel = perf_evlist__id2evsel(evlist, sample.id);
+               if (evsel == NULL) {
+                       pr_debug("event with id %" PRIu64
+                                " doesn't map to an evsel\n", sample.id);
+                       goto out_munmap;
+               }
+               nr_events[evsel->idx]++;
+       }
+
+       list_for_each_entry(evsel, &evlist->entries, node) {
+               if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) {
+                       pr_debug("expected %d %s events, got %d\n",
+                                expected_nr_events[evsel->idx],
+                                event_name(evsel), nr_events[evsel->idx]);
+                       goto out_munmap;
+               }
+       }
+
+       err = 0;
+out_munmap:
+       perf_evlist__munmap(evlist);
+out_close_fd:
+       for (i = 0; i < nsyscalls; ++i)
+               perf_evsel__close_fd(evsels[i], 1, threads->nr);
+out_free_evlist:
+       perf_evlist__delete(evlist);
+out_free_cpus:
+       cpu_map__delete(cpus);
+out_free_threads:
+       thread_map__delete(threads);
+       return err;
+#undef nsyscalls
+}
+
 static struct test {
        const char *desc;
        int (*func)(void);
@@ -453,6 +609,10 @@ static struct test {
                .desc = "detect open syscall event on all cpus",
                .func = test__open_syscall_event_on_all_cpus,
        },
+       {
+               .desc = "read samples using the mmap interface",
+               .func = test__basic_mmap,
+       },
        {
                .func = NULL,
        },
index 746cf03..67c0459 100644 (file)
@@ -264,9 +264,6 @@ pid_put_sample(int pid, int type, unsigned int cpu, u64 start, u64 end)
                c->start_time = start;
        if (p->start_time == 0 || p->start_time > start)
                p->start_time = start;
-
-       if (cpu > numcpus)
-               numcpus = cpu;
 }
 
 #define MAX_CPUS 4096
@@ -276,21 +273,24 @@ static int cpus_cstate_state[MAX_CPUS];
 static u64 cpus_pstate_start_times[MAX_CPUS];
 static u64 cpus_pstate_state[MAX_CPUS];
 
-static int process_comm_event(event_t *event, struct sample_data *sample __used,
+static int process_comm_event(union perf_event *event,
+                             struct perf_sample *sample __used,
                              struct perf_session *session __used)
 {
        pid_set_comm(event->comm.tid, event->comm.comm);
        return 0;
 }
 
-static int process_fork_event(event_t *event, struct sample_data *sample __used,
+static int process_fork_event(union perf_event *event,
+                             struct perf_sample *sample __used,
                              struct perf_session *session __used)
 {
        pid_fork(event->fork.pid, event->fork.ppid, event->fork.time);
        return 0;
 }
 
-static int process_exit_event(event_t *event, struct sample_data *sample __used,
+static int process_exit_event(union perf_event *event,
+                             struct perf_sample *sample __used,
                              struct perf_session *session __used)
 {
        pid_exit(event->fork.pid, event->fork.time);
@@ -486,8 +486,8 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
 }
 
 
-static int process_sample_event(event_t *event __used,
-                               struct sample_data *sample,
+static int process_sample_event(union perf_event *event __used,
+                               struct perf_sample *sample,
                                struct perf_session *session)
 {
        struct trace_entry *te;
@@ -511,6 +511,9 @@ static int process_sample_event(event_t *event __used,
                if (!event_str)
                        return 0;
 
+               if (sample->cpu > numcpus)
+                       numcpus = sample->cpu;
+
                if (strcmp(event_str, "power:cpu_idle") == 0) {
                        struct power_processor_entry *ppe = (void *)te;
                        if (ppe->state == (u32)PWR_EVENT_EXIT)
index b6998e0..80c9e06 100644 (file)
 
 #include "perf.h"
 
+#include "util/annotate.h"
+#include "util/cache.h"
 #include "util/color.h"
+#include "util/evlist.h"
 #include "util/evsel.h"
 #include "util/session.h"
 #include "util/symbol.h"
 #include "util/thread.h"
+#include "util/thread_map.h"
+#include "util/top.h"
 #include "util/util.h"
 #include <linux/rbtree.h>
 #include "util/parse-options.h"
@@ -45,7 +50,6 @@
 #include <errno.h>
 #include <time.h>
 #include <sched.h>
-#include <pthread.h>
 
 #include <sys/syscall.h>
 #include <sys/ioctl.h>
 
 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
 
+static struct perf_top top = {
+       .count_filter           = 5,
+       .delay_secs             = 2,
+       .display_weighted       = -1,
+       .target_pid             = -1,
+       .target_tid             = -1,
+       .active_symbols         = LIST_HEAD_INIT(top.active_symbols),
+       .active_symbols_lock    = PTHREAD_MUTEX_INITIALIZER,
+       .active_symbols_cond    = PTHREAD_COND_INITIALIZER,
+       .freq                   = 1000, /* 1 KHz */
+};
+
 static bool                    system_wide                     =  false;
 
-static int                     default_interval                =      0;
+static bool                    use_tui, use_stdio;
 
-static int                     count_filter                    =      5;
-static int                     print_entries;
+static int                     default_interval                =      0;
 
-static int                     target_pid                      =     -1;
-static int                     target_tid                      =     -1;
-static struct thread_map       *threads;
 static bool                    inherit                         =  false;
-static struct cpu_map          *cpus;
 static int                     realtime_prio                   =      0;
 static bool                    group                           =  false;
 static unsigned int            page_size;
-static unsigned int            mmap_pages                      =     16;
-static int                     freq                            =   1000; /* 1 KHz */
+static unsigned int            mmap_pages                      =    128;
 
-static int                     delay_secs                      =      2;
-static bool                    zero                            =  false;
 static bool                    dump_symtab                     =  false;
 
-static bool                    hide_kernel_symbols             =  false;
-static bool                    hide_user_symbols               =  false;
 static struct winsize          winsize;
 
-/*
- * Source
- */
-
-struct source_line {
-       u64                     eip;
-       unsigned long           count[MAX_COUNTERS];
-       char                    *line;
-       struct source_line      *next;
-};
-
 static const char              *sym_filter                     =   NULL;
-struct sym_entry               *sym_filter_entry               =   NULL;
 struct sym_entry               *sym_filter_entry_sched         =   NULL;
 static int                     sym_pcnt_filter                 =      5;
-static int                     sym_counter                     =      0;
-static struct perf_evsel       *sym_evsel                      =   NULL;
-static int                     display_weighted                =     -1;
-static const char              *cpu_list;
-
-/*
- * Symbols
- */
-
-struct sym_entry_source {
-       struct source_line      *source;
-       struct source_line      *lines;
-       struct source_line      **lines_tail;
-       pthread_mutex_t         lock;
-};
-
-struct sym_entry {
-       struct rb_node          rb_node;
-       struct list_head        node;
-       unsigned long           snap_count;
-       double                  weight;
-       int                     skip;
-       u16                     name_len;
-       u8                      origin;
-       struct map              *map;
-       struct sym_entry_source *src;
-       unsigned long           count[0];
-};
 
 /*
  * Source functions
  */
 
-static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
-{
-       return ((void *)self) + symbol_conf.priv_size;
-}
-
 void get_term_dimensions(struct winsize *ws)
 {
        char *s = getenv("LINES");
@@ -163,10 +124,10 @@ void get_term_dimensions(struct winsize *ws)
 
 static void update_print_entries(struct winsize *ws)
 {
-       print_entries = ws->ws_row;
+       top.print_entries = ws->ws_row;
 
-       if (print_entries > 9)
-               print_entries -= 9;
+       if (top.print_entries > 9)
+               top.print_entries -= 9;
 }
 
 static void sig_winch_handler(int sig __used)
@@ -178,12 +139,9 @@ static void sig_winch_handler(int sig __used)
 static int parse_source(struct sym_entry *syme)
 {
        struct symbol *sym;
-       struct sym_entry_source *source;
+       struct annotation *notes;
        struct map *map;
-       FILE *file;
-       char command[PATH_MAX*2];
-       const char *path;
-       u64 len;
+       int err = -1;
 
        if (!syme)
                return -1;
@@ -194,411 +152,137 @@ static int parse_source(struct sym_entry *syme)
        /*
         * We can't annotate with just /proc/kallsyms
         */
-       if (map->dso->origin == DSO__ORIG_KERNEL)
+       if (map->dso->origin == DSO__ORIG_KERNEL) {
+               pr_err("Can't annotate %s: No vmlinux file was found in the "
+                      "path\n", sym->name);
+               sleep(1);
                return -1;
-
-       if (syme->src == NULL) {
-               syme->src = zalloc(sizeof(*source));
-               if (syme->src == NULL)
-                       return -1;
-               pthread_mutex_init(&syme->src->lock, NULL);
        }
 
-       source = syme->src;
-
-       if (source->lines) {
-               pthread_mutex_lock(&source->lock);
+       notes = symbol__annotation(sym);
+       if (notes->src != NULL) {
+               pthread_mutex_lock(&notes->lock);
                goto out_assign;
        }
-       path = map->dso->long_name;
-
-       len = sym->end - sym->start;
-
-       sprintf(command,
-               "objdump --start-address=%#0*" PRIx64 " --stop-address=%#0*" PRIx64 " -dS %s",
-               BITS_PER_LONG / 4, map__rip_2objdump(map, sym->start),
-               BITS_PER_LONG / 4, map__rip_2objdump(map, sym->end), path);
-
-       file = popen(command, "r");
-       if (!file)
-               return -1;
-
-       pthread_mutex_lock(&source->lock);
-       source->lines_tail = &source->lines;
-       while (!feof(file)) {
-               struct source_line *src;
-               size_t dummy = 0;
-               char *c, *sep;
 
-               src = malloc(sizeof(struct source_line));
-               assert(src != NULL);
-               memset(src, 0, sizeof(struct source_line));
+       pthread_mutex_lock(&notes->lock);
 
-               if (getline(&src->line, &dummy, file) < 0)
-                       break;
-               if (!src->line)
-                       break;
-
-               c = strchr(src->line, '\n');
-               if (c)
-                       *c = 0;
-
-               src->next = NULL;
-               *source->lines_tail = src;
-               source->lines_tail = &src->next;
-
-               src->eip = strtoull(src->line, &sep, 16);
-               if (*sep == ':')
-                       src->eip = map__objdump_2ip(map, src->eip);
-               else /* this line has no ip info (e.g. source line) */
-                       src->eip = 0;
+       if (symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) {
+               pthread_mutex_unlock(&notes->lock);
+               pr_err("Not enough memory for annotating '%s' symbol!\n",
+                      sym->name);
+               sleep(1);
+               return err;
        }
-       pclose(file);
+
+       err = symbol__annotate(sym, syme->map, 0);
+       if (err == 0) {
 out_assign:
-       sym_filter_entry = syme;
-       pthread_mutex_unlock(&source->lock);
-       return 0;
+               top.sym_filter_entry = syme;
+       }
+
+       pthread_mutex_unlock(&notes->lock);
+       return err;
 }
 
 static void __zero_source_counters(struct sym_entry *syme)
 {
-       int i;
-       struct source_line *line;
-
-       line = syme->src->lines;
-       while (line) {
-               for (i = 0; i < nr_counters; i++)
-                       line->count[i] = 0;
-               line = line->next;
-       }
+       struct symbol *sym = sym_entry__symbol(syme);
+       symbol__annotate_zero_histograms(sym);
 }
 
 static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
 {
-       struct source_line *line;
-
-       if (syme != sym_filter_entry)
-               return;
+       struct annotation *notes;
+       struct symbol *sym;
 
-       if (pthread_mutex_trylock(&syme->src->lock))
+       if (syme != top.sym_filter_entry)
                return;
 
-       if (syme->src == NULL || syme->src->source == NULL)
-               goto out_unlock;
-
-       for (line = syme->src->lines; line; line = line->next) {
-               /* skip lines without IP info */
-               if (line->eip == 0)
-                       continue;
-               if (line->eip == ip) {
-                       line->count[counter]++;
-                       break;
-               }
-               if (line->eip > ip)
-                       break;
-       }
-out_unlock:
-       pthread_mutex_unlock(&syme->src->lock);
-}
-
-#define PATTERN_LEN            (BITS_PER_LONG / 4 + 2)
-
-static void lookup_sym_source(struct sym_entry *syme)
-{
-       struct symbol *symbol = sym_entry__symbol(syme);
-       struct source_line *line;
-       char pattern[PATTERN_LEN + 1];
-
-       sprintf(pattern, "%0*" PRIx64 " <", BITS_PER_LONG / 4,
-               map__rip_2objdump(syme->map, symbol->start));
-
-       pthread_mutex_lock(&syme->src->lock);
-       for (line = syme->src->lines; line; line = line->next) {
-               if (memcmp(line->line, pattern, PATTERN_LEN) == 0) {
-                       syme->src->source = line;
-                       break;
-               }
-       }
-       pthread_mutex_unlock(&syme->src->lock);
-}
+       sym = sym_entry__symbol(syme);
+       notes = symbol__annotation(sym);
 
-static void show_lines(struct source_line *queue, int count, int total)
-{
-       int i;
-       struct source_line *line;
+       if (pthread_mutex_trylock(&notes->lock))
+               return;
 
-       line = queue;
-       for (i = 0; i < count; i++) {
-               float pcnt = 100.0*(float)line->count[sym_counter]/(float)total;
+       ip = syme->map->map_ip(syme->map, ip);
+       symbol__inc_addr_samples(sym, syme->map, counter, ip);
 
-               printf("%8li %4.1f%%\t%s\n", line->count[sym_counter], pcnt, line->line);
-               line = line->next;
-       }
+       pthread_mutex_unlock(&notes->lock);
 }
 
-#define TRACE_COUNT     3
-
 static void show_details(struct sym_entry *syme)
 {
+       struct annotation *notes;
        struct symbol *symbol;
-       struct source_line *line;
-       struct source_line *line_queue = NULL;
-       int displayed = 0;
-       int line_queue_count = 0, total = 0, more = 0;
+       int more;
 
        if (!syme)
                return;
 
-       if (!syme->src->source)
-               lookup_sym_source(syme);
-
-       if (!syme->src->source)
-               return;
-
        symbol = sym_entry__symbol(syme);
-       printf("Showing %s for %s\n", event_name(sym_evsel), symbol->name);
-       printf("  Events  Pcnt (>=%d%%)\n", sym_pcnt_filter);
-
-       pthread_mutex_lock(&syme->src->lock);
-       line = syme->src->source;
-       while (line) {
-               total += line->count[sym_counter];
-               line = line->next;
-       }
-
-       line = syme->src->source;
-       while (line) {
-               float pcnt = 0.0;
-
-               if (!line_queue_count)
-                       line_queue = line;
-               line_queue_count++;
-
-               if (line->count[sym_counter])
-                       pcnt = 100.0 * line->count[sym_counter] / (float)total;
-               if (pcnt >= (float)sym_pcnt_filter) {
-                       if (displayed <= print_entries)
-                               show_lines(line_queue, line_queue_count, total);
-                       else more++;
-                       displayed += line_queue_count;
-                       line_queue_count = 0;
-                       line_queue = NULL;
-               } else if (line_queue_count > TRACE_COUNT) {
-                       line_queue = line_queue->next;
-                       line_queue_count--;
-               }
-
-               line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8;
-               line = line->next;
-       }
-       pthread_mutex_unlock(&syme->src->lock);
-       if (more)
-               printf("%d lines not displayed, maybe increase display entries [e]\n", more);
-}
+       notes = symbol__annotation(symbol);
 
-/*
- * Symbols will be added here in event__process_sample and will get out
- * after decayed.
- */
-static LIST_HEAD(active_symbols);
-static pthread_mutex_t active_symbols_lock = PTHREAD_MUTEX_INITIALIZER;
-
-/*
- * Ordering weight: count-1 * count-2 * ... / count-n
- */
-static double sym_weight(const struct sym_entry *sym)
-{
-       double weight = sym->snap_count;
-       int counter;
-
-       if (!display_weighted)
-               return weight;
+       pthread_mutex_lock(&notes->lock);
 
-       for (counter = 1; counter < nr_counters-1; counter++)
-               weight *= sym->count[counter];
+       if (notes->src == NULL)
+               goto out_unlock;
 
-       weight /= (sym->count[counter] + 1);
+       printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name);
+       printf("  Events  Pcnt (>=%d%%)\n", sym_pcnt_filter);
 
-       return weight;
+       more = symbol__annotate_printf(symbol, syme->map, top.sym_evsel->idx,
+                                      0, sym_pcnt_filter, top.print_entries, 4);
+       if (top.zero)
+               symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx);
+       else
+               symbol__annotate_decay_histogram(symbol, top.sym_evsel->idx);
+       if (more != 0)
+               printf("%d lines not displayed, maybe increase display entries [e]\n", more);
+out_unlock:
+       pthread_mutex_unlock(&notes->lock);
 }
 
-static long                    samples;
-static long                    kernel_samples, us_samples;
-static long                    exact_samples;
-static long                    guest_us_samples, guest_kernel_samples;
 static const char              CONSOLE_CLEAR[] = "\e[H\e[2J";
 
 static void __list_insert_active_sym(struct sym_entry *syme)
 {
-       list_add(&syme->node, &active_symbols);
-}
-
-static void list_remove_active_sym(struct sym_entry *syme)
-{
-       pthread_mutex_lock(&active_symbols_lock);
-       list_del_init(&syme->node);
-       pthread_mutex_unlock(&active_symbols_lock);
+       list_add(&syme->node, &top.active_symbols);
 }
 
-static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
+static void print_sym_table(struct perf_session *session)
 {
-       struct rb_node **p = &tree->rb_node;
-       struct rb_node *parent = NULL;
-       struct sym_entry *iter;
-
-       while (*p != NULL) {
-               parent = *p;
-               iter = rb_entry(parent, struct sym_entry, rb_node);
-
-               if (se->weight > iter->weight)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
-       }
-
-       rb_link_node(&se->rb_node, parent, p);
-       rb_insert_color(&se->rb_node, tree);
-}
-
-static void print_sym_table(void)
-{
-       int printed = 0, j;
-       struct perf_evsel *counter;
-       int snap = !display_weighted ? sym_counter : 0;
-       float samples_per_sec = samples/delay_secs;
-       float ksamples_per_sec = kernel_samples/delay_secs;
-       float us_samples_per_sec = (us_samples)/delay_secs;
-       float guest_kernel_samples_per_sec = (guest_kernel_samples)/delay_secs;
-       float guest_us_samples_per_sec = (guest_us_samples)/delay_secs;
-       float esamples_percent = (100.0*exact_samples)/samples;
-       float sum_ksamples = 0.0;
-       struct sym_entry *syme, *n;
-       struct rb_root tmp = RB_ROOT;
+       char bf[160];
+       int printed = 0;
        struct rb_node *nd;
-       int sym_width = 0, dso_width = 0, dso_short_width = 0;
+       struct sym_entry *syme;
+       struct rb_root tmp = RB_ROOT;
        const int win_width = winsize.ws_col - 1;
-
-       samples = us_samples = kernel_samples = exact_samples = 0;
-       guest_kernel_samples = guest_us_samples = 0;
-
-       /* Sort the active symbols */
-       pthread_mutex_lock(&active_symbols_lock);
-       syme = list_entry(active_symbols.next, struct sym_entry, node);
-       pthread_mutex_unlock(&active_symbols_lock);
-
-       list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
-               syme->snap_count = syme->count[snap];
-               if (syme->snap_count != 0) {
-
-                       if ((hide_user_symbols &&
-                            syme->origin == PERF_RECORD_MISC_USER) ||
-                           (hide_kernel_symbols &&
-                            syme->origin == PERF_RECORD_MISC_KERNEL)) {
-                               list_remove_active_sym(syme);
-                               continue;
-                       }
-                       syme->weight = sym_weight(syme);
-                       rb_insert_active_sym(&tmp, syme);
-                       sum_ksamples += syme->snap_count;
-
-                       for (j = 0; j < nr_counters; j++)
-                               syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8;
-               } else
-                       list_remove_active_sym(syme);
-       }
+       int sym_width, dso_width, dso_short_width;
+       float sum_ksamples = perf_top__decay_samples(&top, &tmp);
 
        puts(CONSOLE_CLEAR);
 
-       printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
-       if (!perf_guest) {
-               printf("   PerfTop:%8.0f irqs/sec  kernel:%4.1f%%"
-                       "  exact: %4.1f%% [",
-                       samples_per_sec,
-                       100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) /
-                                        samples_per_sec)),
-                       esamples_percent);
-       } else {
-               printf("   PerfTop:%8.0f irqs/sec  kernel:%4.1f%% us:%4.1f%%"
-                       " guest kernel:%4.1f%% guest us:%4.1f%%"
-                       " exact: %4.1f%% [",
-                       samples_per_sec,
-                       100.0 - (100.0 * ((samples_per_sec-ksamples_per_sec) /
-                                         samples_per_sec)),
-                       100.0 - (100.0 * ((samples_per_sec-us_samples_per_sec) /
-                                         samples_per_sec)),
-                       100.0 - (100.0 * ((samples_per_sec -
-                                               guest_kernel_samples_per_sec) /
-                                         samples_per_sec)),
-                       100.0 - (100.0 * ((samples_per_sec -
-                                          guest_us_samples_per_sec) /
-                                         samples_per_sec)),
-                       esamples_percent);
-       }
-
-       if (nr_counters == 1 || !display_weighted) {
-               struct perf_evsel *first;
-               first = list_entry(evsel_list.next, struct perf_evsel, node);
-               printf("%" PRIu64, (uint64_t)first->attr.sample_period);
-               if (freq)
-                       printf("Hz ");
-               else
-                       printf(" ");
-       }
-
-       if (!display_weighted)
-               printf("%s", event_name(sym_evsel));
-       else list_for_each_entry(counter, &evsel_list, node) {
-               if (counter->idx)
-                       printf("/");
-
-               printf("%s", event_name(counter));
-       }
+       perf_top__header_snprintf(&top, bf, sizeof(bf));
+       printf("%s\n", bf);
 
-       printf( "], ");
-
-       if (target_pid != -1)
-               printf(" (target_pid: %d", target_pid);
-       else if (target_tid != -1)
-               printf(" (target_tid: %d", target_tid);
-       else
-               printf(" (all");
-
-       if (cpu_list)
-               printf(", CPU%s: %s)\n", cpus->nr > 1 ? "s" : "", cpu_list);
-       else {
-               if (target_tid != -1)
-                       printf(")\n");
-               else
-                       printf(", %d CPU%s)\n", cpus->nr, cpus->nr > 1 ? "s" : "");
-       }
+       perf_top__reset_sample_counters(&top);
 
        printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
 
-       if (sym_filter_entry) {
-               show_details(sym_filter_entry);
-               return;
+       if (session->hists.stats.total_lost != 0) {
+               color_fprintf(stdout, PERF_COLOR_RED, "WARNING:");
+               printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n",
+                      session->hists.stats.total_lost);
        }
 
-       /*
-        * Find the longest symbol name that will be displayed
-        */
-       for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
-               syme = rb_entry(nd, struct sym_entry, rb_node);
-               if (++printed > print_entries ||
-                   (int)syme->snap_count < count_filter)
-                       continue;
-
-               if (syme->map->dso->long_name_len > dso_width)
-                       dso_width = syme->map->dso->long_name_len;
-
-               if (syme->map->dso->short_name_len > dso_short_width)
-                       dso_short_width = syme->map->dso->short_name_len;
-
-               if (syme->name_len > sym_width)
-                       sym_width = syme->name_len;
+       if (top.sym_filter_entry) {
+               show_details(top.sym_filter_entry);
+               return;
        }
 
-       printed = 0;
+       perf_top__find_widths(&top, &tmp, &dso_width, &dso_short_width,
+                             &sym_width);
 
        if (sym_width + dso_width > winsize.ws_col - 29) {
                dso_width = dso_short_width;
@@ -606,7 +290,7 @@ static void print_sym_table(void)
                        sym_width = winsize.ws_col - dso_width - 29;
        }
        putchar('\n');
-       if (nr_counters == 1)
+       if (top.evlist->nr_entries == 1)
                printf("             samples  pcnt");
        else
                printf("   weight    samples  pcnt");
@@ -615,7 +299,7 @@ static void print_sym_table(void)
                printf("         RIP       ");
        printf(" %-*.*s DSO\n", sym_width, sym_width, "function");
        printf("   %s    _______ _____",
-              nr_counters == 1 ? "      " : "______");
+              top.evlist->nr_entries == 1 ? "      " : "______");
        if (verbose)
                printf(" ________________");
        printf(" %-*.*s", sym_width, sym_width, graph_line);
@@ -628,13 +312,14 @@ static void print_sym_table(void)
 
                syme = rb_entry(nd, struct sym_entry, rb_node);
                sym = sym_entry__symbol(syme);
-               if (++printed > print_entries || (int)syme->snap_count < count_filter)
+               if (++printed > top.print_entries ||
+                   (int)syme->snap_count < top.count_filter)
                        continue;
 
                pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
                                         sum_ksamples));
 
-               if (nr_counters == 1 || !display_weighted)
+               if (top.evlist->nr_entries == 1 || !top.display_weighted)
                        printf("%20.2f ", syme->weight);
                else
                        printf("%9.1f %10ld ", syme->weight, syme->snap_count);
@@ -693,10 +378,8 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
 
        /* zero counters of active symbol */
        if (syme) {
-               pthread_mutex_lock(&syme->src->lock);
                __zero_source_counters(syme);
                *target = NULL;
-               pthread_mutex_unlock(&syme->src->lock);
        }
 
        fprintf(stdout, "\n%s: ", msg);
@@ -707,11 +390,11 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
        if (p)
                *p = 0;
 
-       pthread_mutex_lock(&active_symbols_lock);
-       syme = list_entry(active_symbols.next, struct sym_entry, node);
-       pthread_mutex_unlock(&active_symbols_lock);
+       pthread_mutex_lock(&top.active_symbols_lock);
+       syme = list_entry(top.active_symbols.next, struct sym_entry, node);
+       pthread_mutex_unlock(&top.active_symbols_lock);
 
-       list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
+       list_for_each_entry_safe_from(syme, n, &top.active_symbols, node) {
                struct symbol *sym = sym_entry__symbol(syme);
 
                if (!strcmp(buf, sym->name)) {
@@ -735,34 +418,34 @@ static void print_mapped_keys(void)
 {
        char *name = NULL;
 
-       if (sym_filter_entry) {
-               struct symbol *sym = sym_entry__symbol(sym_filter_entry);
+       if (top.sym_filter_entry) {
+               struct symbol *sym = sym_entry__symbol(top.sym_filter_entry);
                name = sym->name;
        }
 
        fprintf(stdout, "\nMapped keys:\n");
-       fprintf(stdout, "\t[d]     display refresh delay.             \t(%d)\n", delay_secs);
-       fprintf(stdout, "\t[e]     display entries (lines).           \t(%d)\n", print_entries);
+       fprintf(stdout, "\t[d]     display refresh delay.             \t(%d)\n", top.delay_secs);
+       fprintf(stdout, "\t[e]     display entries (lines).           \t(%d)\n", top.print_entries);
 
-       if (nr_counters > 1)
-               fprintf(stdout, "\t[E]     active event counter.              \t(%s)\n", event_name(sym_evsel));
+       if (top.evlist->nr_entries > 1)
+               fprintf(stdout, "\t[E]     active event counter.              \t(%s)\n", event_name(top.sym_evsel));
 
-       fprintf(stdout, "\t[f]     profile display filter (count).    \t(%d)\n", count_filter);
+       fprintf(stdout, "\t[f]     profile display filter (count).    \t(%d)\n", top.count_filter);
 
        fprintf(stdout, "\t[F]     annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter);
        fprintf(stdout, "\t[s]     annotate symbol.                   \t(%s)\n", name?: "NULL");
        fprintf(stdout, "\t[S]     stop annotation.\n");
 
-       if (nr_counters > 1)
-               fprintf(stdout, "\t[w]     toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0);
+       if (top.evlist->nr_entries > 1)
+               fprintf(stdout, "\t[w]     toggle display weighted/count[E]r. \t(%d)\n", top.display_weighted ? 1 : 0);
 
        fprintf(stdout,
                "\t[K]     hide kernel_symbols symbols.     \t(%s)\n",
-               hide_kernel_symbols ? "yes" : "no");
+               top.hide_kernel_symbols ? "yes" : "no");
        fprintf(stdout,
                "\t[U]     hide user symbols.               \t(%s)\n",
-               hide_user_symbols ? "yes" : "no");
-       fprintf(stdout, "\t[z]     toggle sample zeroing.             \t(%d)\n", zero ? 1 : 0);
+               top.hide_user_symbols ? "yes" : "no");
+       fprintf(stdout, "\t[z]     toggle sample zeroing.             \t(%d)\n", top.zero ? 1 : 0);
        fprintf(stdout, "\t[qQ]    quit.\n");
 }
 
@@ -783,7 +466,7 @@ static int key_mapped(int c)
                        return 1;
                case 'E':
                case 'w':
-                       return nr_counters > 1 ? 1 : 0;
+                       return top.evlist->nr_entries > 1 ? 1 : 0;
                default:
                        break;
        }
@@ -818,47 +501,47 @@ static void handle_keypress(struct perf_session *session, int c)
 
        switch (c) {
                case 'd':
-                       prompt_integer(&delay_secs, "Enter display delay");
-                       if (delay_secs < 1)
-                               delay_secs = 1;
+                       prompt_integer(&top.delay_secs, "Enter display delay");
+                       if (top.delay_secs < 1)
+                               top.delay_secs = 1;
                        break;
                case 'e':
-                       prompt_integer(&print_entries, "Enter display entries (lines)");
-                       if (print_entries == 0) {
+                       prompt_integer(&top.print_entries, "Enter display entries (lines)");
+                       if (top.print_entries == 0) {
                                sig_winch_handler(SIGWINCH);
                                signal(SIGWINCH, sig_winch_handler);
                        } else
                                signal(SIGWINCH, SIG_DFL);
                        break;
                case 'E':
-                       if (nr_counters > 1) {
+                       if (top.evlist->nr_entries > 1) {
                                fprintf(stderr, "\nAvailable events:");
 
-                               list_for_each_entry(sym_evsel, &evsel_list, node)
-                                       fprintf(stderr, "\n\t%d %s", sym_evsel->idx, event_name(sym_evsel));
+                               list_for_each_entry(top.sym_evsel, &top.evlist->entries, node)
+                                       fprintf(stderr, "\n\t%d %s", top.sym_evsel->idx, event_name(top.sym_evsel));
 
-                               prompt_integer(&sym_counter, "Enter details event counter");
+                               prompt_integer(&top.sym_counter, "Enter details event counter");
 
-                               if (sym_counter >= nr_counters) {
-                                       sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node);
-                                       sym_counter = 0;
-                                       fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(sym_evsel));
+                               if (top.sym_counter >= top.evlist->nr_entries) {
+                                       top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
+                                       top.sym_counter = 0;
+                                       fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top.sym_evsel));
                                        sleep(1);
                                        break;
                                }
-                               list_for_each_entry(sym_evsel, &evsel_list, node)
-                                       if (sym_evsel->idx == sym_counter)
+                               list_for_each_entry(top.sym_evsel, &top.evlist->entries, node)
+                                       if (top.sym_evsel->idx == top.sym_counter)
                                                break;
-                       } else sym_counter = 0;
+                       } else top.sym_counter = 0;
                        break;
                case 'f':
-                       prompt_integer(&count_filter, "Enter display event count filter");
+                       prompt_integer(&top.count_filter, "Enter display event count filter");
                        break;
                case 'F':
                        prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)");
                        break;
                case 'K':
-                       hide_kernel_symbols = !hide_kernel_symbols;
+                       top.hide_kernel_symbols = !top.hide_kernel_symbols;
                        break;
                case 'q':
                case 'Q':
@@ -867,34 +550,50 @@ static void handle_keypress(struct perf_session *session, int c)
                                perf_session__fprintf_dsos(session, stderr);
                        exit(0);
                case 's':
-                       prompt_symbol(&sym_filter_entry, "Enter details symbol");
+                       prompt_symbol(&top.sym_filter_entry, "Enter details symbol");
                        break;
                case 'S':
-                       if (!sym_filter_entry)
+                       if (!top.sym_filter_entry)
                                break;
                        else {
-                               struct sym_entry *syme = sym_filter_entry;
+                               struct sym_entry *syme = top.sym_filter_entry;
 
-                               pthread_mutex_lock(&syme->src->lock);
-                               sym_filter_entry = NULL;
+                               top.sym_filter_entry = NULL;
                                __zero_source_counters(syme);
-                               pthread_mutex_unlock(&syme->src->lock);
                        }
                        break;
                case 'U':
-                       hide_user_symbols = !hide_user_symbols;
+                       top.hide_user_symbols = !top.hide_user_symbols;
                        break;
                case 'w':
-                       display_weighted = ~display_weighted;
+                       top.display_weighted = ~top.display_weighted;
                        break;
                case 'z':
-                       zero = !zero;
+                       top.zero = !top.zero;
                        break;
                default:
                        break;
        }
 }
 
+static void *display_thread_tui(void *arg __used)
+{
+       int err = 0;
+       pthread_mutex_lock(&top.active_symbols_lock);
+       while (list_empty(&top.active_symbols)) {
+               err = pthread_cond_wait(&top.active_symbols_cond,
+                                       &top.active_symbols_lock);
+               if (err)
+                       break;
+       }
+       pthread_mutex_unlock(&top.active_symbols_lock);
+       if (!err)
+               perf_top__tui_browser(&top);
+       exit_browser(0);
+       exit(0);
+       return NULL;
+}
+
 static void *display_thread(void *arg __used)
 {
        struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
@@ -909,13 +608,13 @@ static void *display_thread(void *arg __used)
        tc.c_cc[VTIME] = 0;
 
 repeat:
-       delay_msecs = delay_secs * 1000;
+       delay_msecs = top.delay_secs * 1000;
        tcsetattr(0, TCSANOW, &tc);
        /* trash return*/
        getc(stdin);
 
        do {
-               print_sym_table();
+               print_sym_table(session);
        } while (!poll(&stdin_poll, 1, delay_msecs) == 1);
 
        c = getc(stdin);
@@ -930,6 +629,7 @@ repeat:
 /* Tag samples to be skipped. */
 static const char *skip_symbols[] = {
        "default_idle",
+       "native_safe_halt",
        "cpu_idle",
        "enter_idle",
        "exit_idle",
@@ -965,9 +665,9 @@ static int symbol_filter(struct map *map, struct symbol *sym)
 
        syme = symbol__priv(sym);
        syme->map = map;
-       syme->src = NULL;
+       symbol__annotate_init(map, sym);
 
-       if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) {
+       if (!top.sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) {
                /* schedule initial sym_filter_entry setup */
                sym_filter_entry_sched = syme;
                sym_filter = NULL;
@@ -980,44 +680,40 @@ static int symbol_filter(struct map *map, struct symbol *sym)
                }
        }
 
-       if (!syme->skip)
-               syme->name_len = strlen(sym->name);
-
        return 0;
 }
 
-static void event__process_sample(const event_t *self,
-                                 struct sample_data *sample,
-                                 struct perf_session *session,
-                                 struct perf_evsel *evsel)
+static void perf_event__process_sample(const union perf_event *event,
+                                      struct perf_sample *sample,
+                                      struct perf_session *session)
 {
-       u64 ip = self->ip.ip;
+       u64 ip = event->ip.ip;
        struct sym_entry *syme;
        struct addr_location al;
        struct machine *machine;
-       u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
+       u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
 
-       ++samples;
+       ++top.samples;
 
        switch (origin) {
        case PERF_RECORD_MISC_USER:
-               ++us_samples;
-               if (hide_user_symbols)
+               ++top.us_samples;
+               if (top.hide_user_symbols)
                        return;
                machine = perf_session__find_host_machine(session);
                break;
        case PERF_RECORD_MISC_KERNEL:
-               ++kernel_samples;
-               if (hide_kernel_symbols)
+               ++top.kernel_samples;
+               if (top.hide_kernel_symbols)
                        return;
                machine = perf_session__find_host_machine(session);
                break;
        case PERF_RECORD_MISC_GUEST_KERNEL:
-               ++guest_kernel_samples;
-               machine = perf_session__find_machine(session, self->ip.pid);
+               ++top.guest_kernel_samples;
+               machine = perf_session__find_machine(session, event->ip.pid);
                break;
        case PERF_RECORD_MISC_GUEST_USER:
-               ++guest_us_samples;
+               ++top.guest_us_samples;
                /*
                 * TODO: we don't process guest user from host side
                 * except simple counting.
@@ -1029,15 +725,15 @@ static void event__process_sample(const event_t *self,
 
        if (!machine && perf_guest) {
                pr_err("Can't find guest [%d]'s kernel information\n",
-                       self->ip.pid);
+                       event->ip.pid);
                return;
        }
 
-       if (self->header.misc & PERF_RECORD_MISC_EXACT_IP)
-               exact_samples++;
+       if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
+               top.exact_samples++;
 
-       if (event__preprocess_sample(self, session, &al, sample,
-                                    symbol_filter) < 0 ||
+       if (perf_event__preprocess_sample(event, session, &al, sample,
+                                         symbol_filter) < 0 ||
            al.filtered)
                return;
 
@@ -1055,8 +751,9 @@ static void event__process_sample(const event_t *self,
                 */
                if (al.map == machine->vmlinux_maps[MAP__FUNCTION] &&
                    RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
-                       pr_err("The %s file can't be used\n",
-                              symbol_conf.vmlinux_name);
+                       ui__warning("The %s file can't be used\n",
+                                   symbol_conf.vmlinux_name);
+                       exit_browser(0);
                        exit(1);
                }
 
@@ -1065,13 +762,13 @@ static void event__process_sample(const event_t *self,
 
        /* let's see, whether we need to install initial sym_filter_entry */
        if (sym_filter_entry_sched) {
-               sym_filter_entry = sym_filter_entry_sched;
+               top.sym_filter_entry = sym_filter_entry_sched;
                sym_filter_entry_sched = NULL;
-               if (parse_source(sym_filter_entry) < 0) {
-                       struct symbol *sym = sym_entry__symbol(sym_filter_entry);
+               if (parse_source(top.sym_filter_entry) < 0) {
+                       struct symbol *sym = sym_entry__symbol(top.sym_filter_entry);
 
                        pr_err("Can't annotate %s", sym->name);
-                       if (sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) {
+                       if (top.sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) {
                                pr_err(": No vmlinux file was found in the path:\n");
                                machine__fprintf_vmlinux_path(machine, stderr);
                        } else
@@ -1082,166 +779,73 @@ static void event__process_sample(const event_t *self,
 
        syme = symbol__priv(al.sym);
        if (!syme->skip) {
-               syme->count[evsel->idx]++;
+               struct perf_evsel *evsel;
+
                syme->origin = origin;
+               evsel = perf_evlist__id2evsel(top.evlist, sample->id);
+               assert(evsel != NULL);
+               syme->count[evsel->idx]++;
                record_precise_ip(syme, evsel->idx, ip);
-               pthread_mutex_lock(&active_symbols_lock);
-               if (list_empty(&syme->node) || !syme->node.next)
+               pthread_mutex_lock(&top.active_symbols_lock);
+               if (list_empty(&syme->node) || !syme->node.next) {
+                       static bool first = true;
                        __list_insert_active_sym(syme);
-               pthread_mutex_unlock(&active_symbols_lock);
+                       if (first) {
+                               pthread_cond_broadcast(&top.active_symbols_cond);
+                               first = false;
+                       }
+               }
+               pthread_mutex_unlock(&top.active_symbols_lock);
        }
 }
 
-struct mmap_data {
-       void                    *base;
-       int                     mask;
-       unsigned int            prev;
-};
-
-static int perf_evsel__alloc_mmap_per_thread(struct perf_evsel *evsel,
-                                            int ncpus, int nthreads)
-{
-       evsel->priv = xyarray__new(ncpus, nthreads, sizeof(struct mmap_data));
-       return evsel->priv != NULL ? 0 : -ENOMEM;
-}
-
-static void perf_evsel__free_mmap(struct perf_evsel *evsel)
-{
-       xyarray__delete(evsel->priv);
-       evsel->priv = NULL;
-}
-
-static unsigned int mmap_read_head(struct mmap_data *md)
-{
-       struct perf_event_mmap_page *pc = md->base;
-       int head;
-
-       head = pc->data_head;
-       rmb();
-
-       return head;
-}
-
-static void perf_session__mmap_read_counter(struct perf_session *self,
-                                           struct perf_evsel *evsel,
-                                           int cpu, int thread_idx)
+static void perf_session__mmap_read_cpu(struct perf_session *self, int cpu)
 {
-       struct xyarray *mmap_array = evsel->priv;
-       struct mmap_data *md = xyarray__entry(mmap_array, cpu, thread_idx);
-       unsigned int head = mmap_read_head(md);
-       unsigned int old = md->prev;
-       unsigned char *data = md->base + page_size;
-       struct sample_data sample;
-       int diff;
-
-       /*
-        * If we're further behind than half the buffer, there's a chance
-        * the writer will bite our tail and mess up the samples under us.
-        *
-        * If we somehow ended up ahead of the head, we got messed up.
-        *
-        * In either case, truncate and restart at head.
-        */
-       diff = head - old;
-       if (diff > md->mask / 2 || diff < 0) {
-               fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
-
-               /*
-                * head points to a known good entry, start there.
-                */
-               old = head;
-       }
-
-       for (; old != head;) {
-               event_t *event = (event_t *)&data[old & md->mask];
-
-               event_t event_copy;
+       struct perf_sample sample;
+       union perf_event *event;
 
-               size_t size = event->header.size;
+       while ((event = perf_evlist__read_on_cpu(top.evlist, cpu)) != NULL) {
+               perf_session__parse_sample(self, event, &sample);
 
-               /*
-                * Event straddles the mmap boundary -- header should always
-                * be inside due to u64 alignment of output.
-                */
-               if ((old & md->mask) + size != ((old + size) & md->mask)) {
-                       unsigned int offset = old;
-                       unsigned int len = min(sizeof(*event), size), cpy;
-                       void *dst = &event_copy;
-
-                       do {
-                               cpy = min(md->mask + 1 - (offset & md->mask), len);
-                               memcpy(dst, &data[offset & md->mask], cpy);
-                               offset += cpy;
-                               dst += cpy;
-                               len -= cpy;
-                       } while (len);
-
-                       event = &event_copy;
-               }
-
-               event__parse_sample(event, self, &sample);
                if (event->header.type == PERF_RECORD_SAMPLE)
-                       event__process_sample(event, &sample, self, evsel);
+                       perf_event__process_sample(event, &sample, self);
                else
-                       event__process(event, &sample, self);
-               old += size;
+                       perf_event__process(event, &sample, self);
        }
-
-       md->prev = old;
 }
 
-static struct pollfd *event_array;
-
 static void perf_session__mmap_read(struct perf_session *self)
 {
-       struct perf_evsel *counter;
-       int i, thread_index;
-
-       for (i = 0; i < cpus->nr; i++) {
-               list_for_each_entry(counter, &evsel_list, node) {
-                       for (thread_index = 0;
-                               thread_index < threads->nr;
-                               thread_index++) {
-                               perf_session__mmap_read_counter(self,
-                                       counter, i, thread_index);
-                       }
-               }
-       }
-}
+       int i;
 
-int nr_poll;
-int group_fd;
+       for (i = 0; i < top.evlist->cpus->nr; i++)
+               perf_session__mmap_read_cpu(self, i);
+}
 
-static void start_counter(int i, struct perf_evsel *evsel)
+static void start_counters(struct perf_evlist *evlist)
 {
-       struct xyarray *mmap_array = evsel->priv;
-       struct mmap_data *mm;
-       struct perf_event_attr *attr;
-       int cpu = -1;
-       int thread_index;
-
-       if (target_tid == -1)
-               cpu = cpus->map[i];
+       struct perf_evsel *counter;
 
-       attr = &evsel->attr;
+       list_for_each_entry(counter, &evlist->entries, node) {
+               struct perf_event_attr *attr = &counter->attr;
 
-       attr->sample_type       = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
+               attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
 
-       if (freq) {
-               attr->sample_type       |= PERF_SAMPLE_PERIOD;
-               attr->freq              = 1;
-               attr->sample_freq       = freq;
-       }
+               if (top.freq) {
+                       attr->sample_type |= PERF_SAMPLE_PERIOD;
+                       attr->freq        = 1;
+                       attr->sample_freq = top.freq;
+               }
 
-       attr->inherit           = (cpu < 0) && inherit;
-       attr->mmap              = 1;
+               if (evlist->nr_entries > 1) {
+                       attr->sample_type |= PERF_SAMPLE_ID;
+                       attr->read_format |= PERF_FORMAT_ID;
+               }
 
-       for (thread_index = 0; thread_index < threads->nr; thread_index++) {
+               attr->mmap = 1;
 try_again:
-               FD(evsel, i, thread_index) = sys_perf_event_open(attr,
-                               threads->map[thread_index], cpu, group_fd, 0);
-
-               if (FD(evsel, i, thread_index) < 0) {
+               if (perf_evsel__open(counter, top.evlist->cpus,
+                                    top.evlist->threads, group, inherit) < 0) {
                        int err = errno;
 
                        if (err == EPERM || err == EACCES)
@@ -1253,8 +857,8 @@ try_again:
                         * based cpu-clock-tick sw counter, which
                         * is always available even if no PMU support:
                         */
-                       if (attr->type == PERF_TYPE_HARDWARE
-                                       && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
+                       if (attr->type == PERF_TYPE_HARDWARE &&
+                           attr->config == PERF_COUNT_HW_CPU_CYCLES) {
 
                                if (verbose)
                                        warning(" ... trying to fall back to cpu-clock-ticks\n");
@@ -1264,39 +868,22 @@ try_again:
                                goto try_again;
                        }
                        printf("\n");
-                       error("sys_perf_event_open() syscall returned with %d (%s).  /bin/dmesg may provide additional information.\n",
-                                       FD(evsel, i, thread_index), strerror(err));
+                       error("sys_perf_event_open() syscall returned with %d "
+                             "(%s).  /bin/dmesg may provide additional information.\n",
+                             err, strerror(err));
                        die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
                        exit(-1);
                }
-               assert(FD(evsel, i, thread_index) >= 0);
-               fcntl(FD(evsel, i, thread_index), F_SETFL, O_NONBLOCK);
-
-               /*
-                * First counter acts as the group leader:
-                */
-               if (group && group_fd == -1)
-                       group_fd = FD(evsel, i, thread_index);
-
-               event_array[nr_poll].fd = FD(evsel, i, thread_index);
-               event_array[nr_poll].events = POLLIN;
-               nr_poll++;
-
-               mm = xyarray__entry(mmap_array, i, thread_index);
-               mm->prev = 0;
-               mm->mask = mmap_pages*page_size - 1;
-               mm->base = mmap(NULL, (mmap_pages+1)*page_size,
-                               PROT_READ, MAP_SHARED, FD(evsel, i, thread_index), 0);
-               if (mm->base == MAP_FAILED)
-                       die("failed to mmap with %d (%s)\n", errno, strerror(errno));
        }
+
+       if (perf_evlist__mmap(evlist, mmap_pages, false) < 0)
+               die("failed to mmap with %d (%s)\n", errno, strerror(errno));
 }
 
 static int __cmd_top(void)
 {
        pthread_t thread;
-       struct perf_evsel *counter;
-       int i, ret;
+       int ret __used;
        /*
         * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
         * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
@@ -1305,23 +892,23 @@ static int __cmd_top(void)
        if (session == NULL)
                return -ENOMEM;
 
-       if (target_tid != -1)
-               event__synthesize_thread(target_tid, event__process, session);
+       if (top.target_tid != -1)
+               perf_event__synthesize_thread_map(top.evlist->threads,
+                                                 perf_event__process, session);
        else
-               event__synthesize_threads(event__process, session);
+               perf_event__synthesize_threads(perf_event__process, session);
 
-       for (i = 0; i < cpus->nr; i++) {
-               group_fd = -1;
-               list_for_each_entry(counter, &evsel_list, node)
-                       start_counter(i, counter);
-       }
+       start_counters(top.evlist);
+       session->evlist = top.evlist;
+       perf_session__update_sample_type(session);
 
        /* Wait for a minimal set of events before starting the snapshot */
-       poll(&event_array[0], nr_poll, 100);
+       poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
 
        perf_session__mmap_read(session);
 
-       if (pthread_create(&thread, NULL, display_thread, session)) {
+       if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
+                                                            display_thread), session)) {
                printf("Could not create display thread.\n");
                exit(-1);
        }
@@ -1337,12 +924,12 @@ static int __cmd_top(void)
        }
 
        while (1) {
-               int hits = samples;
+               u64 hits = top.samples;
 
                perf_session__mmap_read(session);
 
-               if (hits == samples)
-                       ret = poll(event_array, nr_poll, 100);
+               if (hits == top.samples)
+                       ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
        }
 
        return 0;
@@ -1354,31 +941,31 @@ static const char * const top_usage[] = {
 };
 
 static const struct option options[] = {
-       OPT_CALLBACK('e', "event", NULL, "event",
+       OPT_CALLBACK('e', "event", &top.evlist, "event",
                     "event selector. use 'perf list' to list available events",
                     parse_events),
        OPT_INTEGER('c', "count", &default_interval,
                    "event period to sample"),
-       OPT_INTEGER('p', "pid", &target_pid,
+       OPT_INTEGER('p', "pid", &top.target_pid,
                    "profile events on existing process id"),
-       OPT_INTEGER('t', "tid", &target_tid,
+       OPT_INTEGER('t', "tid", &top.target_tid,
                    "profile events on existing thread id"),
        OPT_BOOLEAN('a', "all-cpus", &system_wide,
                            "system-wide collection from all CPUs"),
-       OPT_STRING('C', "cpu", &cpu_list, "cpu",
+       OPT_STRING('C', "cpu", &top.cpu_list, "cpu",
                    "list of cpus to monitor"),
        OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
                   "file", "vmlinux pathname"),
-       OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols,
+       OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols,
                    "hide kernel symbols"),
        OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"),
        OPT_INTEGER('r', "realtime", &realtime_prio,
                    "collect data with this RT SCHED_FIFO priority"),
-       OPT_INTEGER('d', "delay", &delay_secs,
+       OPT_INTEGER('d', "delay", &top.delay_secs,
                    "number of seconds to delay between refreshes"),
        OPT_BOOLEAN('D', "dump-symtab", &dump_symtab,
                            "dump the symbol table used for profiling"),
-       OPT_INTEGER('f', "count-filter", &count_filter,
+       OPT_INTEGER('f', "count-filter", &top.count_filter,
                    "only display functions with more events than this"),
        OPT_BOOLEAN('g', "group", &group,
                            "put the counters into a counter group"),
@@ -1386,14 +973,16 @@ static const struct option options[] = {
                    "child tasks inherit counters"),
        OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name",
                    "symbol to annotate"),
-       OPT_BOOLEAN('z', "zero", &zero,
+       OPT_BOOLEAN('z', "zero", &top.zero,
                    "zero history across updates"),
-       OPT_INTEGER('F', "freq", &freq,
+       OPT_INTEGER('F', "freq", &top.freq,
                    "profile at this frequency"),
-       OPT_INTEGER('E', "entries", &print_entries,
+       OPT_INTEGER('E', "entries", &top.print_entries,
                    "display this many functions"),
-       OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols,
+       OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols,
                    "hide user symbols"),
+       OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"),
+       OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
        OPT_INCR('v', "verbose", &verbose,
                    "be more verbose (show counter open errors, etc)"),
        OPT_END()
@@ -1404,64 +993,68 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
        struct perf_evsel *pos;
        int status = -ENOMEM;
 
+       top.evlist = perf_evlist__new(NULL, NULL);
+       if (top.evlist == NULL)
+               return -ENOMEM;
+
        page_size = sysconf(_SC_PAGE_SIZE);
 
        argc = parse_options(argc, argv, options, top_usage, 0);
        if (argc)
                usage_with_options(top_usage, options);
 
-       if (target_pid != -1)
-               target_tid = target_pid;
+       /*
+        * XXX For now start disabled, only using TUI if explicitely asked for.
+        * Change that when handle_keys equivalent gets written, live annotation
+        * done, etc.
+        */
+       use_browser = 0;
 
-       threads = thread_map__new(target_pid, target_tid);
-       if (threads == NULL) {
-               pr_err("Problems finding threads of monitor\n");
-               usage_with_options(top_usage, options);
-       }
+       if (use_stdio)
+               use_browser = 0;
+       else if (use_tui)
+               use_browser = 1;
 
-       event_array = malloc((sizeof(struct pollfd) *
-                             MAX_NR_CPUS * MAX_COUNTERS * threads->nr));
-       if (!event_array)
-               return -ENOMEM;
+       setup_browser(false);
 
        /* CPU and PID are mutually exclusive */
-       if (target_tid > 0 && cpu_list) {
+       if (top.target_tid > 0 && top.cpu_list) {
                printf("WARNING: PID switch overriding CPU\n");
                sleep(1);
-               cpu_list = NULL;
+               top.cpu_list = NULL;
        }
 
-       if (!nr_counters && perf_evsel_list__create_default() < 0) {
+       if (top.target_pid != -1)
+               top.target_tid = top.target_pid;
+
+       if (perf_evlist__create_maps(top.evlist, top.target_pid,
+                                    top.target_tid, top.cpu_list) < 0)
+               usage_with_options(top_usage, options);
+
+       if (!top.evlist->nr_entries &&
+           perf_evlist__add_default(top.evlist) < 0) {
                pr_err("Not enough memory for event selector list\n");
                return -ENOMEM;
        }
 
-       if (delay_secs < 1)
-               delay_secs = 1;
+       if (top.delay_secs < 1)
+               top.delay_secs = 1;
 
        /*
         * User specified count overrides default frequency.
         */
        if (default_interval)
-               freq = 0;
-       else if (freq) {
-               default_interval = freq;
+               top.freq = 0;
+       else if (top.freq) {
+               default_interval = top.freq;
        } else {
                fprintf(stderr, "frequency and count are zero, aborting\n");
                exit(EXIT_FAILURE);
        }
 
-       if (target_tid != -1)
-               cpus = cpu_map__dummy_new();
-       else
-               cpus = cpu_map__new(cpu_list);
-
-       if (cpus == NULL)
-               usage_with_options(top_usage, options);
-
-       list_for_each_entry(pos, &evsel_list, node) {
-               if (perf_evsel__alloc_mmap_per_thread(pos, cpus->nr, threads->nr) < 0 ||
-                   perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
+       list_for_each_entry(pos, &top.evlist->entries, node) {
+               if (perf_evsel__alloc_fd(pos, top.evlist->cpus->nr,
+                                        top.evlist->threads->nr) < 0)
                        goto out_free_fd;
                /*
                 * Fill in the ones not specifically initialized via -c:
@@ -1472,26 +1065,28 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
                pos->attr.sample_period = default_interval;
        }
 
-       sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node);
+       if (perf_evlist__alloc_pollfd(top.evlist) < 0 ||
+           perf_evlist__alloc_mmap(top.evlist) < 0)
+               goto out_free_fd;
+
+       top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
 
-       symbol_conf.priv_size = (sizeof(struct sym_entry) +
-                                (nr_counters + 1) * sizeof(unsigned long));
+       symbol_conf.priv_size = (sizeof(struct sym_entry) + sizeof(struct annotation) +
+                                (top.evlist->nr_entries + 1) * sizeof(unsigned long));
 
        symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
        if (symbol__init() < 0)
                return -1;
 
        get_term_dimensions(&winsize);
-       if (print_entries == 0) {
+       if (top.print_entries == 0) {
                update_print_entries(&winsize);
                signal(SIGWINCH, sig_winch_handler);
        }
 
        status = __cmd_top();
 out_free_fd:
-       list_for_each_entry(pos, &evsel_list, node)
-               perf_evsel__free_mmap(pos);
-       perf_evsel_list__delete();
+       perf_evlist__delete(top.evlist);
 
        return status;
 }
index 95aaf56..a5fc660 100644 (file)
@@ -94,6 +94,32 @@ void get_term_dimensions(struct winsize *ws);
 #include "util/types.h"
 #include <stdbool.h>
 
+struct perf_mmap {
+       void                    *base;
+       int                     mask;
+       unsigned int            prev;
+};
+
+static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
+{
+       struct perf_event_mmap_page *pc = mm->base;
+       int head = pc->data_head;
+       rmb();
+       return head;
+}
+
+static inline void perf_mmap__write_tail(struct perf_mmap *md,
+                                        unsigned long tail)
+{
+       struct perf_event_mmap_page *pc = md->base;
+
+       /*
+        * ensure all reads are done before we write the tail out.
+        */
+       /* mb(); */
+       pc->data_tail = tail;
+}
+
 /*
  * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all
  * counters in the current task.
diff --git a/tools/perf/python/twatch.py b/tools/perf/python/twatch.py
new file mode 100755 (executable)
index 0000000..df638c4
--- /dev/null
@@ -0,0 +1,41 @@
+#! /usr/bin/python
+# -*- python -*-
+# -*- coding: utf-8 -*-
+#   twatch - Experimental use of the perf python interface
+#   Copyright (C) 2011 Arnaldo Carvalho de Melo <acme@redhat.com>
+#
+#   This application 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.
+#
+#   This application 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.
+
+import perf
+
+def main():
+       cpus = perf.cpu_map()
+       threads = perf.thread_map()
+       evsel = perf.evsel(task = 1, comm = 1, mmap = 0,
+                          wakeup_events = 1, sample_period = 1,
+                          sample_id_all = 1,
+                          sample_type = perf.SAMPLE_PERIOD | perf.SAMPLE_TID | perf.SAMPLE_CPU | perf.SAMPLE_TID)
+       evsel.open(cpus = cpus, threads = threads);
+       evlist = perf.evlist(cpus, threads)
+       evlist.add(evsel)
+       evlist.mmap()
+       while True:
+               evlist.poll(timeout = -1)
+               for cpu in cpus:
+                       event = evlist.read_on_cpu(cpu)
+                       if not event:
+                               continue
+                       print "cpu: %2d, pid: %4d, tid: %4d" % (event.sample_cpu,
+                                                               event.sample_pid,
+                                                               event.sample_tid),
+                       print event
+
+if __name__ == '__main__':
+    main()
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
new file mode 100644 (file)
index 0000000..0d0830c
--- /dev/null
@@ -0,0 +1,605 @@
+/*
+ * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
+ *
+ * Parts came from builtin-annotate.c, see those files for further
+ * copyright notes.
+ *
+ * Released under the GPL v2. (and only v2, not any later version)
+ */
+
+#include "util.h"
+#include "build-id.h"
+#include "color.h"
+#include "cache.h"
+#include "symbol.h"
+#include "debug.h"
+#include "annotate.h"
+#include <pthread.h>
+
+int symbol__annotate_init(struct map *map __used, struct symbol *sym)
+{
+       struct annotation *notes = symbol__annotation(sym);
+       pthread_mutex_init(&notes->lock, NULL);
+       return 0;
+}
+
+int symbol__alloc_hist(struct symbol *sym, int nevents)
+{
+       struct annotation *notes = symbol__annotation(sym);
+       size_t sizeof_sym_hist = (sizeof(struct sym_hist) +
+                                 (sym->end - sym->start) * sizeof(u64));
+
+       notes->src = zalloc(sizeof(*notes->src) + nevents * sizeof_sym_hist);
+       if (notes->src == NULL)
+               return -1;
+       notes->src->sizeof_sym_hist = sizeof_sym_hist;
+       notes->src->nr_histograms   = nevents;
+       INIT_LIST_HEAD(&notes->src->source);
+       return 0;
+}
+
+void symbol__annotate_zero_histograms(struct symbol *sym)
+{
+       struct annotation *notes = symbol__annotation(sym);
+
+       pthread_mutex_lock(&notes->lock);
+       if (notes->src != NULL)
+               memset(notes->src->histograms, 0,
+                      notes->src->nr_histograms * notes->src->sizeof_sym_hist);
+       pthread_mutex_unlock(&notes->lock);
+}
+
+int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
+                            int evidx, u64 addr)
+{
+       unsigned offset;
+       struct annotation *notes;
+       struct sym_hist *h;
+
+       notes = symbol__annotation(sym);
+       if (notes->src == NULL)
+               return -ENOMEM;
+
+       pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));
+
+       if (addr >= sym->end)
+               return 0;
+
+       offset = addr - sym->start;
+       h = annotation__histogram(notes, evidx);
+       h->sum++;
+       h->addr[offset]++;
+
+       pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64
+                 ", evidx=%d] => %" PRIu64 "\n", sym->start, sym->name,
+                 addr, addr - sym->start, evidx, h->addr[offset]);
+       return 0;
+}
+
+static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize)
+{
+       struct objdump_line *self = malloc(sizeof(*self) + privsize);
+
+       if (self != NULL) {
+               self->offset = offset;
+               self->line = line;
+       }
+
+       return self;
+}
+
+void objdump_line__free(struct objdump_line *self)
+{
+       free(self->line);
+       free(self);
+}
+
+static void objdump__add_line(struct list_head *head, struct objdump_line *line)
+{
+       list_add_tail(&line->node, head);
+}
+
+struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
+                                              struct objdump_line *pos)
+{
+       list_for_each_entry_continue(pos, head, node)
+               if (pos->offset >= 0)
+                       return pos;
+
+       return NULL;
+}
+
+static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
+                              int evidx, u64 len, int min_pcnt,
+                              int printed, int max_lines,
+                              struct objdump_line *queue)
+{
+       static const char *prev_line;
+       static const char *prev_color;
+
+       if (oline->offset != -1) {
+               const char *path = NULL;
+               unsigned int hits = 0;
+               double percent = 0.0;
+               const char *color;
+               struct annotation *notes = symbol__annotation(sym);
+               struct source_line *src_line = notes->src->lines;
+               struct sym_hist *h = annotation__histogram(notes, evidx);
+               s64 offset = oline->offset;
+               struct objdump_line *next;
+
+               next = objdump__get_next_ip_line(&notes->src->source, oline);
+
+               while (offset < (s64)len &&
+                      (next == NULL || offset < next->offset)) {
+                       if (src_line) {
+                               if (path == NULL)
+                                       path = src_line[offset].path;
+                               percent += src_line[offset].percent;
+                       } else
+                               hits += h->addr[offset];
+
+                       ++offset;
+               }
+
+               if (src_line == NULL && h->sum)
+                       percent = 100.0 * hits / h->sum;
+
+               if (percent < min_pcnt)
+                       return -1;
+
+               if (max_lines && printed >= max_lines)
+                       return 1;
+
+               if (queue != NULL) {
+                       list_for_each_entry_from(queue, &notes->src->source, node) {
+                               if (queue == oline)
+                                       break;
+                               objdump_line__print(queue, sym, evidx, len,
+                                                   0, 0, 1, NULL);
+                       }
+               }
+
+               color = get_percent_color(percent);
+
+               /*
+                * Also color the filename and line if needed, with
+                * the same color than the percentage. Don't print it
+                * twice for close colored addr with the same filename:line
+                */
+               if (path) {
+                       if (!prev_line || strcmp(prev_line, path)
+                                      || color != prev_color) {
+                               color_fprintf(stdout, color, " %s", path);
+                               prev_line = path;
+                               prev_color = color;
+                       }
+               }
+
+               color_fprintf(stdout, color, " %7.2f", percent);
+               printf(" :      ");
+               color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", oline->line);
+       } else if (max_lines && printed >= max_lines)
+               return 1;
+       else {
+               if (queue)
+                       return -1;
+
+               if (!*oline->line)
+                       printf("         :\n");
+               else
+                       printf("         :      %s\n", oline->line);
+       }
+
+       return 0;
+}
+
+static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
+                                     FILE *file, size_t privsize)
+{
+       struct annotation *notes = symbol__annotation(sym);
+       struct objdump_line *objdump_line;
+       char *line = NULL, *tmp, *tmp2, *c;
+       size_t line_len;
+       s64 line_ip, offset = -1;
+
+       if (getline(&line, &line_len, file) < 0)
+               return -1;
+
+       if (!line)
+               return -1;
+
+       while (line_len != 0 && isspace(line[line_len - 1]))
+               line[--line_len] = '\0';
+
+       c = strchr(line, '\n');
+       if (c)
+               *c = 0;
+
+       line_ip = -1;
+
+       /*
+        * Strip leading spaces:
+        */
+       tmp = line;
+       while (*tmp) {
+               if (*tmp != ' ')
+                       break;
+               tmp++;
+       }
+
+       if (*tmp) {
+               /*
+                * Parse hexa addresses followed by ':'
+                */
+               line_ip = strtoull(tmp, &tmp2, 16);
+               if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
+                       line_ip = -1;
+       }
+
+       if (line_ip != -1) {
+               u64 start = map__rip_2objdump(map, sym->start),
+                   end = map__rip_2objdump(map, sym->end);
+
+               offset = line_ip - start;
+               if (offset < 0 || (u64)line_ip > end)
+                       offset = -1;
+       }
+
+       objdump_line = objdump_line__new(offset, line, privsize);
+       if (objdump_line == NULL) {
+               free(line);
+               return -1;
+       }
+       objdump__add_line(&notes->src->source, objdump_line);
+
+       return 0;
+}
+
+int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
+{
+       struct dso *dso = map->dso;
+       char *filename = dso__build_id_filename(dso, NULL, 0);
+       bool free_filename = true;
+       char command[PATH_MAX * 2];
+       FILE *file;
+       int err = 0;
+       char symfs_filename[PATH_MAX];
+
+       if (filename) {
+               snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
+                        symbol_conf.symfs, filename);
+       }
+
+       if (filename == NULL) {
+               if (dso->has_build_id) {
+                       pr_err("Can't annotate %s: not enough memory\n",
+                              sym->name);
+                       return -ENOMEM;
+               }
+               goto fallback;
+       } else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
+                  strstr(command, "[kernel.kallsyms]") ||
+                  access(symfs_filename, R_OK)) {
+               free(filename);
+fallback:
+               /*
+                * If we don't have build-ids or the build-id file isn't in the
+                * cache, or is just a kallsyms file, well, lets hope that this
+                * DSO is the same as when 'perf record' ran.
+                */
+               filename = dso->long_name;
+               snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
+                        symbol_conf.symfs, filename);
+               free_filename = false;
+       }
+
+       if (dso->origin == DSO__ORIG_KERNEL) {
+               char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
+               char *build_id_msg = NULL;
+
+               if (dso->annotate_warned)
+                       goto out_free_filename;
+
+               if (dso->has_build_id) {
+                       build_id__sprintf(dso->build_id,
+                                         sizeof(dso->build_id), bf + 15);
+                       build_id_msg = bf;
+               }
+               err = -ENOENT;
+               dso->annotate_warned = 1;
+               pr_err("Can't annotate %s: No vmlinux file%s was found in the "
+                      "path.\nPlease use 'perf buildid-cache -av vmlinux' or "
+                      "--vmlinux vmlinux.\n",
+                      sym->name, build_id_msg ?: "");
+               goto out_free_filename;
+       }
+
+       pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
+                filename, sym->name, map->unmap_ip(map, sym->start),
+                map->unmap_ip(map, sym->end));
+
+       pr_debug("annotating [%p] %30s : [%p] %30s\n",
+                dso, dso->long_name, sym, sym->name);
+
+       snprintf(command, sizeof(command),
+                "objdump --start-address=0x%016" PRIx64
+                " --stop-address=0x%016" PRIx64 " -dS -C %s|grep -v %s|expand",
+                map__rip_2objdump(map, sym->start),
+                map__rip_2objdump(map, sym->end),
+                symfs_filename, filename);
+
+       pr_debug("Executing: %s\n", command);
+
+       file = popen(command, "r");
+       if (!file)
+               goto out_free_filename;
+
+       while (!feof(file))
+               if (symbol__parse_objdump_line(sym, map, file, privsize) < 0)
+                       break;
+
+       pclose(file);
+out_free_filename:
+       if (free_filename)
+               free(filename);
+       return err;
+}
+
+static void insert_source_line(struct rb_root *root, struct source_line *src_line)
+{
+       struct source_line *iter;
+       struct rb_node **p = &root->rb_node;
+       struct rb_node *parent = NULL;
+
+       while (*p != NULL) {
+               parent = *p;
+               iter = rb_entry(parent, struct source_line, node);
+
+               if (src_line->percent > iter->percent)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
+       }
+
+       rb_link_node(&src_line->node, parent, p);
+       rb_insert_color(&src_line->node, root);
+}
+
+static void symbol__free_source_line(struct symbol *sym, int len)
+{
+       struct annotation *notes = symbol__annotation(sym);
+       struct source_line *src_line = notes->src->lines;
+       int i;
+
+       for (i = 0; i < len; i++)
+               free(src_line[i].path);
+
+       free(src_line);
+       notes->src->lines = NULL;
+}
+
+/* Get the filename:line for the colored entries */
+static int symbol__get_source_line(struct symbol *sym, struct map *map,
+                                  int evidx, struct rb_root *root, int len,
+                                  const char *filename)
+{
+       u64 start;
+       int i;
+       char cmd[PATH_MAX * 2];
+       struct source_line *src_line;
+       struct annotation *notes = symbol__annotation(sym);
+       struct sym_hist *h = annotation__histogram(notes, evidx);
+
+       if (!h->sum)
+               return 0;
+
+       src_line = notes->src->lines = calloc(len, sizeof(struct source_line));
+       if (!notes->src->lines)
+               return -1;
+
+       start = map->unmap_ip(map, sym->start);
+
+       for (i = 0; i < len; i++) {
+               char *path = NULL;
+               size_t line_len;
+               u64 offset;
+               FILE *fp;
+
+               src_line[i].percent = 100.0 * h->addr[i] / h->sum;
+               if (src_line[i].percent <= 0.5)
+                       continue;
+
+               offset = start + i;
+               sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);
+               fp = popen(cmd, "r");
+               if (!fp)
+                       continue;
+
+               if (getline(&path, &line_len, fp) < 0 || !line_len)
+                       goto next;
+
+               src_line[i].path = malloc(sizeof(char) * line_len + 1);
+               if (!src_line[i].path)
+                       goto next;
+
+               strcpy(src_line[i].path, path);
+               insert_source_line(root, &src_line[i]);
+
+       next:
+               pclose(fp);
+       }
+
+       return 0;
+}
+
+static void print_summary(struct rb_root *root, const char *filename)
+{
+       struct source_line *src_line;
+       struct rb_node *node;
+
+       printf("\nSorted summary for file %s\n", filename);
+       printf("----------------------------------------------\n\n");
+
+       if (RB_EMPTY_ROOT(root)) {
+               printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
+               return;
+       }
+
+       node = rb_first(root);
+       while (node) {
+               double percent;
+               const char *color;
+               char *path;
+
+               src_line = rb_entry(node, struct source_line, node);
+               percent = src_line->percent;
+               color = get_percent_color(percent);
+               path = src_line->path;
+
+               color_fprintf(stdout, color, " %7.2f %s", percent, path);
+               node = rb_next(node);
+       }
+}
+
+static void symbol__annotate_hits(struct symbol *sym, int evidx)
+{
+       struct annotation *notes = symbol__annotation(sym);
+       struct sym_hist *h = annotation__histogram(notes, evidx);
+       u64 len = sym->end - sym->start, offset;
+
+       for (offset = 0; offset < len; ++offset)
+               if (h->addr[offset] != 0)
+                       printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
+                              sym->start + offset, h->addr[offset]);
+       printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
+}
+
+int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
+                           bool full_paths, int min_pcnt, int max_lines,
+                           int context)
+{
+       struct dso *dso = map->dso;
+       const char *filename = dso->long_name, *d_filename;
+       struct annotation *notes = symbol__annotation(sym);
+       struct objdump_line *pos, *queue = NULL;
+       int printed = 2, queue_len = 0;
+       int more = 0;
+       u64 len;
+
+       if (full_paths)
+               d_filename = filename;
+       else
+               d_filename = basename(filename);
+
+       len = sym->end - sym->start;
+
+       printf(" Percent |      Source code & Disassembly of %s\n", d_filename);
+       printf("------------------------------------------------\n");
+
+       if (verbose)
+               symbol__annotate_hits(sym, evidx);
+
+       list_for_each_entry(pos, &notes->src->source, node) {
+               if (context && queue == NULL) {
+                       queue = pos;
+                       queue_len = 0;
+               }
+
+               switch (objdump_line__print(pos, sym, evidx, len, min_pcnt,
+                                           printed, max_lines, queue)) {
+               case 0:
+                       ++printed;
+                       if (context) {
+                               printed += queue_len;
+                               queue = NULL;
+                               queue_len = 0;
+                       }
+                       break;
+               case 1:
+                       /* filtered by max_lines */
+                       ++more;
+                       break;
+               case -1:
+               default:
+                       /*
+                        * Filtered by min_pcnt or non IP lines when
+                        * context != 0
+                        */
+                       if (!context)
+                               break;
+                       if (queue_len == context)
+                               queue = list_entry(queue->node.next, typeof(*queue), node);
+                       else
+                               ++queue_len;
+                       break;
+               }
+       }
+
+       return more;
+}
+
+void symbol__annotate_zero_histogram(struct symbol *sym, int evidx)
+{
+       struct annotation *notes = symbol__annotation(sym);
+       struct sym_hist *h = annotation__histogram(notes, evidx);
+
+       memset(h, 0, notes->src->sizeof_sym_hist);
+}
+
+void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
+{
+       struct annotation *notes = symbol__annotation(sym);
+       struct sym_hist *h = annotation__histogram(notes, evidx);
+       struct objdump_line *pos;
+       int len = sym->end - sym->start;
+
+       h->sum = 0;
+
+       list_for_each_entry(pos, &notes->src->source, node) {
+               if (pos->offset != -1 && pos->offset < len) {
+                       h->addr[pos->offset] = h->addr[pos->offset] * 7 / 8;
+                       h->sum += h->addr[pos->offset];
+               }
+       }
+}
+
+void objdump_line_list__purge(struct list_head *head)
+{
+       struct objdump_line *pos, *n;
+
+       list_for_each_entry_safe(pos, n, head, node) {
+               list_del(&pos->node);
+               objdump_line__free(pos);
+       }
+}
+
+int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
+                        bool print_lines, bool full_paths, int min_pcnt,
+                        int max_lines)
+{
+       struct dso *dso = map->dso;
+       const char *filename = dso->long_name;
+       struct rb_root source_line = RB_ROOT;
+       u64 len;
+
+       if (symbol__annotate(sym, map, 0) < 0)
+               return -1;
+
+       len = sym->end - sym->start;
+
+       if (print_lines) {
+               symbol__get_source_line(sym, map, evidx, &source_line,
+                                       len, filename);
+               print_summary(&source_line, filename);
+       }
+
+       symbol__annotate_printf(sym, map, evidx, full_paths,
+                               min_pcnt, max_lines, 0);
+       if (print_lines)
+               symbol__free_source_line(sym, len);
+
+       objdump_line_list__purge(&symbol__annotation(sym)->src->source);
+
+       return 0;
+}
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
new file mode 100644 (file)
index 0000000..c2c2868
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef __PERF_ANNOTATE_H
+#define __PERF_ANNOTATE_H
+
+#include <stdbool.h>
+#include "types.h"
+#include "symbol.h"
+#include <linux/list.h>
+#include <linux/rbtree.h>
+
+struct objdump_line {
+       struct list_head node;
+       s64              offset;
+       char             *line;
+};
+
+void objdump_line__free(struct objdump_line *self);
+struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
+                                              struct objdump_line *pos);
+
+struct sym_hist {
+       u64             sum;
+       u64             addr[0];
+};
+
+struct source_line {
+       struct rb_node  node;
+       double          percent;
+       char            *path;
+};
+
+/** struct annotated_source - symbols with hits have this attached as in sannotation
+ *
+ * @histogram: Array of addr hit histograms per event being monitored
+ * @lines: If 'print_lines' is specified, per source code line percentages
+ * @source: source parsed from objdump -dS
+ *
+ * lines is allocated, percentages calculated and all sorted by percentage
+ * when the annotation is about to be presented, so the percentages are for
+ * one of the entries in the histogram array, i.e. for the event/counter being
+ * presented. It is deallocated right after symbol__{tui,tty,etc}_annotate
+ * returns.
+ */
+struct annotated_source {
+       struct list_head   source;
+       struct source_line *lines;
+       int                nr_histograms;
+       int                sizeof_sym_hist;
+       struct sym_hist    histograms[0];
+};
+
+struct annotation {
+       pthread_mutex_t         lock;
+       struct annotated_source *src;
+};
+
+struct sannotation {
+       struct annotation annotation;
+       struct symbol     symbol;
+};
+
+static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx)
+{
+       return (((void *)&notes->src->histograms) +
+               (notes->src->sizeof_sym_hist * idx));
+}
+
+static inline struct annotation *symbol__annotation(struct symbol *sym)
+{
+       struct sannotation *a = container_of(sym, struct sannotation, symbol);
+       return &a->annotation;
+}
+
+int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
+                            int evidx, u64 addr);
+int symbol__alloc_hist(struct symbol *sym, int nevents);
+void symbol__annotate_zero_histograms(struct symbol *sym);
+
+int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize);
+int symbol__annotate_init(struct map *map __used, struct symbol *sym);
+int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
+                           bool full_paths, int min_pcnt, int max_lines,
+                           int context);
+void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
+void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
+void objdump_line_list__purge(struct list_head *head);
+
+int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
+                        bool print_lines, bool full_paths, int min_pcnt,
+                        int max_lines);
+
+#ifdef NO_NEWT_SUPPORT
+static inline int symbol__tui_annotate(struct symbol *sym __used,
+                                      struct map *map __used,
+                                      int evidx __used, int refresh __used)
+{
+       return 0;
+}
+#else
+int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
+                        int refresh);
+#endif
+
+#endif /* __PERF_ANNOTATE_H */
index deffb8c..31f934a 100644 (file)
@@ -14,8 +14,8 @@
 #include <linux/kernel.h>
 #include "debug.h"
 
-static int build_id__mark_dso_hit(event_t *event,
-                                 struct sample_data *sample __used,
+static int build_id__mark_dso_hit(union perf_event *event,
+                                 struct perf_sample *sample __used,
                                  struct perf_session *session)
 {
        struct addr_location al;
@@ -37,13 +37,14 @@ static int build_id__mark_dso_hit(event_t *event,
        return 0;
 }
 
-static int event__exit_del_thread(event_t *self, struct sample_data *sample __used,
-                                 struct perf_session *session)
+static int perf_event__exit_del_thread(union perf_event *event,
+                                      struct perf_sample *sample __used,
+                                      struct perf_session *session)
 {
-       struct thread *thread = perf_session__findnew(session, self->fork.tid);
+       struct thread *thread = perf_session__findnew(session, event->fork.tid);
 
-       dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
-                   self->fork.ppid, self->fork.ptid);
+       dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
+                   event->fork.ppid, event->fork.ptid);
 
        if (thread) {
                rb_erase(&thread->rb_node, &session->threads);
@@ -56,9 +57,9 @@ static int event__exit_del_thread(event_t *self, struct sample_data *sample __us
 
 struct perf_event_ops build_id__mark_dso_hit_ops = {
        .sample = build_id__mark_dso_hit,
-       .mmap   = event__process_mmap,
-       .fork   = event__process_task,
-       .exit   = event__exit_del_thread,
+       .mmap   = perf_event__process_mmap,
+       .fork   = perf_event__process_task,
+       .exit   = perf_event__exit_del_thread,
 };
 
 char *dso__build_id_filename(struct dso *self, char *bf, size_t size)
index a772979..fc5e5a0 100644 (file)
@@ -34,13 +34,14 @@ extern int pager_use_color;
 extern int use_browser;
 
 #ifdef NO_NEWT_SUPPORT
-static inline void setup_browser(void)
+static inline void setup_browser(bool fallback_to_pager)
 {
-       setup_pager();
+       if (fallback_to_pager)
+               setup_pager();
 }
 static inline void exit_browser(bool wait_for_ok __used) {}
 #else
-void setup_browser(void);
+void setup_browser(bool fallback_to_pager);
 void exit_browser(bool wait_for_ok);
 #endif
 
index e12d539..9f7106a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009-2010, Frederic Weisbecker <fweisbec@gmail.com>
+ * Copyright (C) 2009-2011, Frederic Weisbecker <fweisbec@gmail.com>
  *
  * Handle the callchains from the stream in an ad-hoc radix tree and then
  * sort them in an rbtree.
@@ -18,7 +18,8 @@
 #include "util.h"
 #include "callchain.h"
 
-bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event)
+bool ip_callchain__valid(struct ip_callchain *chain,
+                        const union perf_event *event)
 {
        unsigned int chain_size = event->header.size;
        chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
@@ -26,10 +27,10 @@ bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event)
 }
 
 #define chain_for_each_child(child, parent)    \
-       list_for_each_entry(child, &parent->children, brothers)
+       list_for_each_entry(child, &parent->children, siblings)
 
 #define chain_for_each_child_safe(child, next, parent) \
-       list_for_each_entry_safe(child, next, &parent->children, brothers)
+       list_for_each_entry_safe(child, next, &parent->children, siblings)
 
 static void
 rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
@@ -38,14 +39,14 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
        struct rb_node **p = &root->rb_node;
        struct rb_node *parent = NULL;
        struct callchain_node *rnode;
-       u64 chain_cumul = cumul_hits(chain);
+       u64 chain_cumul = callchain_cumul_hits(chain);
 
        while (*p) {
                u64 rnode_cumul;
 
                parent = *p;
                rnode = rb_entry(parent, struct callchain_node, rb_node);
-               rnode_cumul = cumul_hits(rnode);
+               rnode_cumul = callchain_cumul_hits(rnode);
 
                switch (mode) {
                case CHAIN_FLAT:
@@ -104,7 +105,7 @@ static void __sort_chain_graph_abs(struct callchain_node *node,
 
        chain_for_each_child(child, node) {
                __sort_chain_graph_abs(child, min_hit);
-               if (cumul_hits(child) >= min_hit)
+               if (callchain_cumul_hits(child) >= min_hit)
                        rb_insert_callchain(&node->rb_root, child,
                                            CHAIN_GRAPH_ABS);
        }
@@ -129,7 +130,7 @@ static void __sort_chain_graph_rel(struct callchain_node *node,
 
        chain_for_each_child(child, node) {
                __sort_chain_graph_rel(child, min_percent);
-               if (cumul_hits(child) >= min_hit)
+               if (callchain_cumul_hits(child) >= min_hit)
                        rb_insert_callchain(&node->rb_root, child,
                                            CHAIN_GRAPH_REL);
        }
@@ -143,7 +144,7 @@ sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
        rb_root->rb_node = chain_root->node.rb_root.rb_node;
 }
 
-int register_callchain_param(struct callchain_param *param)
+int callchain_register_param(struct callchain_param *param)
 {
        switch (param->mode) {
        case CHAIN_GRAPH_ABS:
@@ -189,32 +190,27 @@ create_child(struct callchain_node *parent, bool inherit_children)
                chain_for_each_child(next, new)
                        next->parent = new;
        }
-       list_add_tail(&new->brothers, &parent->children);
+       list_add_tail(&new->siblings, &parent->children);
 
        return new;
 }
 
 
-struct resolved_ip {
-       u64               ip;
-       struct map_symbol ms;
-};
-
-struct resolved_chain {
-       u64                     nr;
-       struct resolved_ip      ips[0];
-};
-
-
 /*
  * Fill the node with callchain values
  */
 static void
-fill_node(struct callchain_node *node, struct resolved_chain *chain, int start)
+fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
 {
-       unsigned int i;
+       struct callchain_cursor_node *cursor_node;
+
+       node->val_nr = cursor->nr - cursor->pos;
+       if (!node->val_nr)
+               pr_warning("Warning: empty node in callchain tree\n");
 
-       for (i = start; i < chain->nr; i++) {
+       cursor_node = callchain_cursor_current(cursor);
+
+       while (cursor_node) {
                struct callchain_list *call;
 
                call = zalloc(sizeof(*call));
@@ -222,23 +218,25 @@ fill_node(struct callchain_node *node, struct resolved_chain *chain, int start)
                        perror("not enough memory for the code path tree");
                        return;
                }
-               call->ip = chain->ips[i].ip;
-               call->ms = chain->ips[i].ms;
+               call->ip = cursor_node->ip;
+               call->ms.sym = cursor_node->sym;
+               call->ms.map = cursor_node->map;
                list_add_tail(&call->list, &node->val);
+
+               callchain_cursor_advance(cursor);
+               cursor_node = callchain_cursor_current(cursor);
        }
-       node->val_nr = chain->nr - start;
-       if (!node->val_nr)
-               pr_warning("Warning: empty node in callchain tree\n");
 }
 
 static void
-add_child(struct callchain_node *parent, struct resolved_chain *chain,
-         int start, u64 period)
+add_child(struct callchain_node *parent,
+         struct callchain_cursor *cursor,
+         u64 period)
 {
        struct callchain_node *new;
 
        new = create_child(parent, false);
-       fill_node(new, chain, start);
+       fill_node(new, cursor);
 
        new->children_hit = 0;
        new->hit = period;
@@ -250,9 +248,10 @@ add_child(struct callchain_node *parent, struct resolved_chain *chain,
  * Then create another child to host the given callchain of new branch
  */
 static void
-split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
-               struct callchain_list *to_split, int idx_parents, int idx_local,
-               u64 period)
+split_add_child(struct callchain_node *parent,
+               struct callchain_cursor *cursor,
+               struct callchain_list *to_split,
+               u64 idx_parents, u64 idx_local, u64 period)
 {
        struct callchain_node *new;
        struct list_head *old_tail;
@@ -272,14 +271,14 @@ split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
        /* split the hits */
        new->hit = parent->hit;
        new->children_hit = parent->children_hit;
-       parent->children_hit = cumul_hits(new);
+       parent->children_hit = callchain_cumul_hits(new);
        new->val_nr = parent->val_nr - idx_local;
        parent->val_nr = idx_local;
 
        /* create a new child for the new branch if any */
-       if (idx_total < chain->nr) {
+       if (idx_total < cursor->nr) {
                parent->hit = 0;
-               add_child(parent, chain, idx_total, period);
+               add_child(parent, cursor, period);
                parent->children_hit += period;
        } else {
                parent->hit = period;
@@ -287,36 +286,41 @@ split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
 }
 
 static int
-append_chain(struct callchain_node *root, struct resolved_chain *chain,
-            unsigned int start, u64 period);
+append_chain(struct callchain_node *root,
+            struct callchain_cursor *cursor,
+            u64 period);
 
 static void
-append_chain_children(struct callchain_node *root, struct resolved_chain *chain,
-                     unsigned int start, u64 period)
+append_chain_children(struct callchain_node *root,
+                     struct callchain_cursor *cursor,
+                     u64 period)
 {
        struct callchain_node *rnode;
 
        /* lookup in childrens */
        chain_for_each_child(rnode, root) {
-               unsigned int ret = append_chain(rnode, chain, start, period);
+               unsigned int ret = append_chain(rnode, cursor, period);
 
                if (!ret)
                        goto inc_children_hit;
        }
        /* nothing in children, add to the current node */
-       add_child(root, chain, start, period);
+       add_child(root, cursor, period);
 
 inc_children_hit:
        root->children_hit += period;
 }
 
 static int
-append_chain(struct callchain_node *root, struct resolved_chain *chain,
-            unsigned int start, u64 period)
+append_chain(struct callchain_node *root,
+            struct callchain_cursor *cursor,
+            u64 period)
 {
+       struct callchain_cursor_node *curr_snap = cursor->curr;
        struct callchain_list *cnode;
-       unsigned int i = start;
+       u64 start = cursor->pos;
        bool found = false;
+       u64 matches;
 
        /*
         * Lookup in the current node
@@ -324,141 +328,134 @@ append_chain(struct callchain_node *root, struct resolved_chain *chain,
         * anywhere inside a function.
         */
        list_for_each_entry(cnode, &root->val, list) {
+               struct callchain_cursor_node *node;
                struct symbol *sym;
 
-               if (i == chain->nr)
+               node = callchain_cursor_current(cursor);
+               if (!node)
                        break;
 
-               sym = chain->ips[i].ms.sym;
+               sym = node->sym;
 
                if (cnode->ms.sym && sym) {
                        if (cnode->ms.sym->start != sym->start)
                                break;
-               } else if (cnode->ip != chain->ips[i].ip)
+               } else if (cnode->ip != node->ip)
                        break;
 
                if (!found)
                        found = true;
-               i++;
+
+               callchain_cursor_advance(cursor);
        }
 
        /* matches not, relay on the parent */
-       if (!found)
+       if (!found) {
+               cursor->curr = curr_snap;
+               cursor->pos = start;
                return -1;
+       }
+
+       matches = cursor->pos - start;
 
        /* we match only a part of the node. Split it and add the new chain */
-       if (i - start < root->val_nr) {
-               split_add_child(root, chain, cnode, start, i - start, period);
+       if (matches < root->val_nr) {
+               split_add_child(root, cursor, cnode, start, matches, period);
                return 0;
        }
 
        /* we match 100% of the path, increment the hit */
-       if (i - start == root->val_nr && i == chain->nr) {
+       if (matches == root->val_nr && cursor->pos == cursor->nr) {
                root->hit += period;
                return 0;
        }
 
        /* We match the node and still have a part remaining */
-       append_chain_children(root, chain, i, period);
+       append_chain_children(root, cursor, period);
 
        return 0;
 }
 
-static void filter_context(struct ip_callchain *old, struct resolved_chain *new,
-                          struct map_symbol *syms)
-{
-       int i, j = 0;
-
-       for (i = 0; i < (int)old->nr; i++) {
-               if (old->ips[i] >= PERF_CONTEXT_MAX)
-                       continue;
-
-               new->ips[j].ip = old->ips[i];
-               new->ips[j].ms = syms[i];
-               j++;
-       }
-
-       new->nr = j;
-}
-
-
-int callchain_append(struct callchain_root *root, struct ip_callchain *chain,
-                    struct map_symbol *syms, u64 period)
+int callchain_append(struct callchain_root *root,
+                    struct callchain_cursor *cursor,
+                    u64 period)
 {
-       struct resolved_chain *filtered;
-
-       if (!chain->nr)
+       if (!cursor->nr)
                return 0;
 
-       filtered = zalloc(sizeof(*filtered) +
-                         chain->nr * sizeof(struct resolved_ip));
-       if (!filtered)
-               return -ENOMEM;
-
-       filter_context(chain, filtered, syms);
-
-       if (!filtered->nr)
-               goto end;
+       callchain_cursor_commit(cursor);
 
-       append_chain_children(&root->node, filtered, 0, period);
+       append_chain_children(&root->node, cursor, period);
 
-       if (filtered->nr > root->max_depth)
-               root->max_depth = filtered->nr;
-end:
-       free(filtered);
+       if (cursor->nr > root->max_depth)
+               root->max_depth = cursor->nr;
 
        return 0;
 }
 
 static int
-merge_chain_branch(struct callchain_node *dst, struct callchain_node *src,
-                  struct resolved_chain *chain)
+merge_chain_branch(struct callchain_cursor *cursor,
+                  struct callchain_node *dst, struct callchain_node *src)
 {
+       struct callchain_cursor_node **old_last = cursor->last;
        struct callchain_node *child, *next_child;
        struct callchain_list *list, *next_list;
-       int old_pos = chain->nr;
+       int old_pos = cursor->nr;
        int err = 0;
 
        list_for_each_entry_safe(list, next_list, &src->val, list) {
-               chain->ips[chain->nr].ip = list->ip;
-               chain->ips[chain->nr].ms = list->ms;
-               chain->nr++;
+               callchain_cursor_append(cursor, list->ip,
+                                       list->ms.map, list->ms.sym);
                list_del(&list->list);
                free(list);
        }
 
-       if (src->hit)
-               append_chain_children(dst, chain, 0, src->hit);
+       if (src->hit) {
+               callchain_cursor_commit(cursor);
+               append_chain_children(dst, cursor, src->hit);
+       }
 
        chain_for_each_child_safe(child, next_child, src) {
-               err = merge_chain_branch(dst, child, chain);
+               err = merge_chain_branch(cursor, dst, child);
                if (err)
                        break;
 
-               list_del(&child->brothers);
+               list_del(&child->siblings);
                free(child);
        }
 
-       chain->nr = old_pos;
+       cursor->nr = old_pos;
+       cursor->last = old_last;
 
        return err;
 }
 
-int callchain_merge(struct callchain_root *dst, struct callchain_root *src)
+int callchain_merge(struct callchain_cursor *cursor,
+                   struct callchain_root *dst, struct callchain_root *src)
+{
+       return merge_chain_branch(cursor, &dst->node, &src->node);
+}
+
+int callchain_cursor_append(struct callchain_cursor *cursor,
+                           u64 ip, struct map *map, struct symbol *sym)
 {
-       struct resolved_chain *chain;
-       int err;
+       struct callchain_cursor_node *node = *cursor->last;
 
-       chain = malloc(sizeof(*chain) +
-                      src->max_depth * sizeof(struct resolved_ip));
-       if (!chain)
-               return -ENOMEM;
+       if (!node) {
+               node = calloc(sizeof(*node), 1);
+               if (!node)
+                       return -ENOMEM;
 
-       chain->nr = 0;
+               *cursor->last = node;
+       }
 
-       err = merge_chain_branch(&dst->node, &src->node, chain);
+       node->ip = ip;
+       node->map = map;
+       node->sym = sym;
 
-       free(chain);
+       cursor->nr++;
 
-       return err;
+       cursor->last = &node->next;
+
+       return 0;
 }
index c15fb8c..1a79df9 100644 (file)
@@ -16,7 +16,7 @@ enum chain_mode {
 
 struct callchain_node {
        struct callchain_node   *parent;
-       struct list_head        brothers;
+       struct list_head        siblings;
        struct list_head        children;
        struct list_head        val;
        struct rb_node          rb_node; /* to sort nodes in an rbtree */
@@ -49,9 +49,30 @@ struct callchain_list {
        struct list_head        list;
 };
 
+/*
+ * A callchain cursor is a single linked list that
+ * let one feed a callchain progressively.
+ * It keeps persitent allocated entries to minimize
+ * allocations.
+ */
+struct callchain_cursor_node {
+       u64                             ip;
+       struct map                      *map;
+       struct symbol                   *sym;
+       struct callchain_cursor_node    *next;
+};
+
+struct callchain_cursor {
+       u64                             nr;
+       struct callchain_cursor_node    *first;
+       struct callchain_cursor_node    **last;
+       u64                             pos;
+       struct callchain_cursor_node    *curr;
+};
+
 static inline void callchain_init(struct callchain_root *root)
 {
-       INIT_LIST_HEAD(&root->node.brothers);
+       INIT_LIST_HEAD(&root->node.siblings);
        INIT_LIST_HEAD(&root->node.children);
        INIT_LIST_HEAD(&root->node.val);
 
@@ -61,15 +82,54 @@ static inline void callchain_init(struct callchain_root *root)
        root->max_depth = 0;
 }
 
-static inline u64 cumul_hits(struct callchain_node *node)
+static inline u64 callchain_cumul_hits(struct callchain_node *node)
 {
        return node->hit + node->children_hit;
 }
 
-int register_callchain_param(struct callchain_param *param);
-int callchain_append(struct callchain_root *root, struct ip_callchain *chain,
-                    struct map_symbol *syms, u64 period);
-int callchain_merge(struct callchain_root *dst, struct callchain_root *src);
+int callchain_register_param(struct callchain_param *param);
+int callchain_append(struct callchain_root *root,
+                    struct callchain_cursor *cursor,
+                    u64 period);
+
+int callchain_merge(struct callchain_cursor *cursor,
+                   struct callchain_root *dst, struct callchain_root *src);
+
+bool ip_callchain__valid(struct ip_callchain *chain,
+                        const union perf_event *event);
+/*
+ * Initialize a cursor before adding entries inside, but keep
+ * the previously allocated entries as a cache.
+ */
+static inline void callchain_cursor_reset(struct callchain_cursor *cursor)
+{
+       cursor->nr = 0;
+       cursor->last = &cursor->first;
+}
+
+int callchain_cursor_append(struct callchain_cursor *cursor, u64 ip,
+                           struct map *map, struct symbol *sym);
 
-bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event);
+/* Close a cursor writing session. Initialize for the reader */
+static inline void callchain_cursor_commit(struct callchain_cursor *cursor)
+{
+       cursor->curr = cursor->first;
+       cursor->pos = 0;
+}
+
+/* Cursor reading iteration helpers */
+static inline struct callchain_cursor_node *
+callchain_cursor_current(struct callchain_cursor *cursor)
+{
+       if (cursor->pos == cursor->nr)
+               return NULL;
+
+       return cursor->curr;
+}
+
+static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
+{
+       cursor->curr = cursor->curr->next;
+       cursor->pos++;
+}
 #endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
new file mode 100644 (file)
index 0000000..9fea755
--- /dev/null
@@ -0,0 +1,178 @@
+#include "util.h"
+#include "../perf.h"
+#include "parse-options.h"
+#include "evsel.h"
+#include "cgroup.h"
+#include "debugfs.h" /* MAX_PATH, STR() */
+#include "evlist.h"
+
+int nr_cgroups;
+
+static int
+cgroupfs_find_mountpoint(char *buf, size_t maxlen)
+{
+       FILE *fp;
+       char mountpoint[MAX_PATH+1], tokens[MAX_PATH+1], type[MAX_PATH+1];
+       char *token, *saved_ptr;
+       int found = 0;
+
+       fp = fopen("/proc/mounts", "r");
+       if (!fp)
+               return -1;
+
+       /*
+        * in order to handle split hierarchy, we need to scan /proc/mounts
+        * and inspect every cgroupfs mount point to find one that has
+        * perf_event subsystem
+        */
+       while (fscanf(fp, "%*s %"STR(MAX_PATH)"s %"STR(MAX_PATH)"s %"
+                               STR(MAX_PATH)"s %*d %*d\n",
+                               mountpoint, type, tokens) == 3) {
+
+               if (!strcmp(type, "cgroup")) {
+
+                       token = strtok_r(tokens, ",", &saved_ptr);
+
+                       while (token != NULL) {
+                               if (!strcmp(token, "perf_event")) {
+                                       found = 1;
+                                       break;
+                               }
+                               token = strtok_r(NULL, ",", &saved_ptr);
+                       }
+               }
+               if (found)
+                       break;
+       }
+       fclose(fp);
+       if (!found)
+               return -1;
+
+       if (strlen(mountpoint) < maxlen) {
+               strcpy(buf, mountpoint);
+               return 0;
+       }
+       return -1;
+}
+
+static int open_cgroup(char *name)
+{
+       char path[MAX_PATH+1];
+       char mnt[MAX_PATH+1];
+       int fd;
+
+
+       if (cgroupfs_find_mountpoint(mnt, MAX_PATH+1))
+               return -1;
+
+       snprintf(path, MAX_PATH, "%s/%s", mnt, name);
+
+       fd = open(path, O_RDONLY);
+       if (fd == -1)
+               fprintf(stderr, "no access to cgroup %s\n", path);
+
+       return fd;
+}
+
+static int add_cgroup(struct perf_evlist *evlist, char *str)
+{
+       struct perf_evsel *counter;
+       struct cgroup_sel *cgrp = NULL;
+       int n;
+       /*
+        * check if cgrp is already defined, if so we reuse it
+        */
+       list_for_each_entry(counter, &evlist->entries, node) {
+               cgrp = counter->cgrp;
+               if (!cgrp)
+                       continue;
+               if (!strcmp(cgrp->name, str))
+                       break;
+
+               cgrp = NULL;
+       }
+
+       if (!cgrp) {
+               cgrp = zalloc(sizeof(*cgrp));
+               if (!cgrp)
+                       return -1;
+
+               cgrp->name = str;
+
+               cgrp->fd = open_cgroup(str);
+               if (cgrp->fd == -1) {
+                       free(cgrp);
+                       return -1;
+               }
+       }
+
+       /*
+        * find corresponding event
+        * if add cgroup N, then need to find event N
+        */
+       n = 0;
+       list_for_each_entry(counter, &evlist->entries, node) {
+               if (n == nr_cgroups)
+                       goto found;
+               n++;
+       }
+       if (cgrp->refcnt == 0)
+               free(cgrp);
+
+       return -1;
+found:
+       cgrp->refcnt++;
+       counter->cgrp = cgrp;
+       return 0;
+}
+
+void close_cgroup(struct cgroup_sel *cgrp)
+{
+       if (!cgrp)
+               return;
+
+       /* XXX: not reentrant */
+       if (--cgrp->refcnt == 0) {
+               close(cgrp->fd);
+               free(cgrp->name);
+               free(cgrp);
+       }
+}
+
+int parse_cgroups(const struct option *opt __used, const char *str,
+                 int unset __used)
+{
+       struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
+       const char *p, *e, *eos = str + strlen(str);
+       char *s;
+       int ret;
+
+       if (list_empty(&evlist->entries)) {
+               fprintf(stderr, "must define events before cgroups\n");
+               return -1;
+       }
+
+       for (;;) {
+               p = strchr(str, ',');
+               e = p ? p : eos;
+
+               /* allow empty cgroups, i.e., skip */
+               if (e - str) {
+                       /* termination added */
+                       s = strndup(str, e - str);
+                       if (!s)
+                               return -1;
+                       ret = add_cgroup(evlist, s);
+                       if (ret) {
+                               free(s);
+                               return -1;
+                       }
+               }
+               /* nr_cgroups is increased een for empty cgroups */
+               nr_cgroups++;
+               if (!p)
+                       break;
+               str = p+1;
+       }
+       return 0;
+}
diff --git a/tools/perf/util/cgroup.h b/tools/perf/util/cgroup.h
new file mode 100644 (file)
index 0000000..89acd6d
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __CGROUP_H__
+#define __CGROUP_H__
+
+struct option;
+
+struct cgroup_sel {
+       char *name;
+       int fd;
+       int refcnt;
+};
+
+
+extern int nr_cgroups; /* number of explicit cgroups defined */
+extern void close_cgroup(struct cgroup_sel *cgrp);
+extern int parse_cgroups(const struct option *opt, const char *str, int unset);
+
+#endif /* __CGROUP_H__ */
index 3ccaa10..6893eec 100644 (file)
@@ -177,3 +177,8 @@ struct cpu_map *cpu_map__dummy_new(void)
 
        return cpus;
 }
+
+void cpu_map__delete(struct cpu_map *map)
+{
+       free(map);
+}
index f7a4f42..072c0a3 100644 (file)
@@ -8,6 +8,6 @@ struct cpu_map {
 
 struct cpu_map *cpu_map__new(const char *cpu_list);
 struct cpu_map *cpu_map__dummy_new(void);
-void *cpu_map__delete(struct cpu_map *map);
+void cpu_map__delete(struct cpu_map *map);
 
 #endif /* __PERF_CPUMAP_H */
index 01bbe8e..d4536a9 100644 (file)
@@ -57,7 +57,7 @@ void ui__warning(const char *format, ...)
 }
 #endif
 
-void trace_event(event_t *event)
+void trace_event(union perf_event *event)
 {
        unsigned char *raw_event = (void *)event;
        const char *color = PERF_COLOR_BLUE;
index ca35fd6..93516cf 100644 (file)
@@ -9,7 +9,7 @@ extern int verbose;
 extern bool quiet, dump_trace;
 
 int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
-void trace_event(event_t *event);
+void trace_event(union perf_event *event);
 
 struct ui_progress;
 
index 1478ab4..2b15c36 100644 (file)
@@ -6,8 +6,9 @@
 #include "string.h"
 #include "strlist.h"
 #include "thread.h"
+#include "thread_map.h"
 
-static const char *event__name[] = {
+static const char *perf_event__names[] = {
        [0]                      = "TOTAL",
        [PERF_RECORD_MMAP]       = "MMAP",
        [PERF_RECORD_LOST]       = "LOST",
@@ -25,16 +26,16 @@ static const char *event__name[] = {
        [PERF_RECORD_FINISHED_ROUND]     = "FINISHED_ROUND",
 };
 
-const char *event__get_event_name(unsigned int id)
+const char *perf_event__name(unsigned int id)
 {
-       if (id >= ARRAY_SIZE(event__name))
+       if (id >= ARRAY_SIZE(perf_event__names))
                return "INVALID";
-       if (!event__name[id])
+       if (!perf_event__names[id])
                return "UNKNOWN";
-       return event__name[id];
+       return perf_event__names[id];
 }
 
-static struct sample_data synth_sample = {
+static struct perf_sample synth_sample = {
        .pid       = -1,
        .tid       = -1,
        .time      = -1,
@@ -43,9 +44,9 @@ static struct sample_data synth_sample = {
        .period    = 1,
 };
 
-static pid_t event__synthesize_comm(event_t *event, pid_t pid, int full,
-                                   event__handler_t process,
-                                   struct perf_session *session)
+static pid_t perf_event__synthesize_comm(union perf_event *event, pid_t pid,
+                                        int full, perf_event__handler_t process,
+                                        struct perf_session *session)
 {
        char filename[PATH_MAX];
        char bf[BUFSIZ];
@@ -126,9 +127,10 @@ out:
        return tgid;
 }
 
-static int event__synthesize_mmap_events(event_t *event, pid_t pid, pid_t tgid,
-                                        event__handler_t process,
-                                        struct perf_session *session)
+static int perf_event__synthesize_mmap_events(union perf_event *event,
+                                             pid_t pid, pid_t tgid,
+                                             perf_event__handler_t process,
+                                             struct perf_session *session)
 {
        char filename[PATH_MAX];
        FILE *fp;
@@ -199,14 +201,14 @@ static int event__synthesize_mmap_events(event_t *event, pid_t pid, pid_t tgid,
        return 0;
 }
 
-int event__synthesize_modules(event__handler_t process,
-                             struct perf_session *session,
-                             struct machine *machine)
+int perf_event__synthesize_modules(perf_event__handler_t process,
+                                  struct perf_session *session,
+                                  struct machine *machine)
 {
        struct rb_node *nd;
        struct map_groups *kmaps = &machine->kmaps;
-       event_t *event = zalloc(sizeof(event->mmap) + session->id_hdr_size);
-
+       union perf_event *event = zalloc((sizeof(event->mmap) +
+                                         session->id_hdr_size));
        if (event == NULL) {
                pr_debug("Not enough memory synthesizing mmap event "
                         "for kernel modules\n");
@@ -251,23 +253,25 @@ int event__synthesize_modules(event__handler_t process,
        return 0;
 }
 
-static int __event__synthesize_thread(event_t *comm_event, event_t *mmap_event,
-                                     pid_t pid, event__handler_t process,
+static int __event__synthesize_thread(union perf_event *comm_event,
+                                     union perf_event *mmap_event,
+                                     pid_t pid, perf_event__handler_t process,
                                      struct perf_session *session)
 {
-       pid_t tgid = event__synthesize_comm(comm_event, pid, 1, process,
+       pid_t tgid = perf_event__synthesize_comm(comm_event, pid, 1, process,
                                            session);
        if (tgid == -1)
                return -1;
-       return event__synthesize_mmap_events(mmap_event, pid, tgid,
+       return perf_event__synthesize_mmap_events(mmap_event, pid, tgid,
                                             process, session);
 }
 
-int event__synthesize_thread(pid_t pid, event__handler_t process,
-                            struct perf_session *session)
+int perf_event__synthesize_thread_map(struct thread_map *threads,
+                                     perf_event__handler_t process,
+                                     struct perf_session *session)
 {
-       event_t *comm_event, *mmap_event;
-       int err = -1;
+       union perf_event *comm_event, *mmap_event;
+       int err = -1, thread;
 
        comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size);
        if (comm_event == NULL)
@@ -277,8 +281,15 @@ int event__synthesize_thread(pid_t pid, event__handler_t process,
        if (mmap_event == NULL)
                goto out_free_comm;
 
-       err = __event__synthesize_thread(comm_event, mmap_event, pid,
-                                        process, session);
+       err = 0;
+       for (thread = 0; thread < threads->nr; ++thread) {
+               if (__event__synthesize_thread(comm_event, mmap_event,
+                                              threads->map[thread],
+                                              process, session)) {
+                       err = -1;
+                       break;
+               }
+       }
        free(mmap_event);
 out_free_comm:
        free(comm_event);
@@ -286,12 +297,12 @@ out:
        return err;
 }
 
-int event__synthesize_threads(event__handler_t process,
-                             struct perf_session *session)
+int perf_event__synthesize_threads(perf_event__handler_t process,
+                                  struct perf_session *session)
 {
        DIR *proc;
        struct dirent dirent, *next;
-       event_t *comm_event, *mmap_event;
+       union perf_event *comm_event, *mmap_event;
        int err = -1;
 
        comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size);
@@ -349,10 +360,10 @@ static int find_symbol_cb(void *arg, const char *name, char type,
        return 1;
 }
 
-int event__synthesize_kernel_mmap(event__handler_t process,
-                                 struct perf_session *session,
-                                 struct machine *machine,
-                                 const char *symbol_name)
+int perf_event__synthesize_kernel_mmap(perf_event__handler_t process,
+                                      struct perf_session *session,
+                                      struct machine *machine,
+                                      const char *symbol_name)
 {
        size_t size;
        const char *filename, *mmap_name;
@@ -366,8 +377,8 @@ int event__synthesize_kernel_mmap(event__handler_t process,
         * kernels.
         */
        struct process_symbol_args args = { .name = symbol_name, };
-       event_t *event = zalloc(sizeof(event->mmap) + session->id_hdr_size);
-
+       union perf_event *event = zalloc((sizeof(event->mmap) +
+                                         session->id_hdr_size));
        if (event == NULL) {
                pr_debug("Not enough memory synthesizing mmap event "
                         "for kernel modules\n");
@@ -413,42 +424,15 @@ int event__synthesize_kernel_mmap(event__handler_t process,
        return err;
 }
 
-static void thread__comm_adjust(struct thread *self, struct hists *hists)
-{
-       char *comm = self->comm;
-
-       if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
-           (!symbol_conf.comm_list ||
-            strlist__has_entry(symbol_conf.comm_list, comm))) {
-               u16 slen = strlen(comm);
-
-               if (hists__new_col_len(hists, HISTC_COMM, slen))
-                       hists__set_col_len(hists, HISTC_THREAD, slen + 6);
-       }
-}
-
-static int thread__set_comm_adjust(struct thread *self, const char *comm,
-                                  struct hists *hists)
-{
-       int ret = thread__set_comm(self, comm);
-
-       if (ret)
-               return ret;
-
-       thread__comm_adjust(self, hists);
-
-       return 0;
-}
-
-int event__process_comm(event_t *self, struct sample_data *sample __used,
-                       struct perf_session *session)
+int perf_event__process_comm(union perf_event *event,
+                            struct perf_sample *sample __used,
+                            struct perf_session *session)
 {
-       struct thread *thread = perf_session__findnew(session, self->comm.tid);
+       struct thread *thread = perf_session__findnew(session, event->comm.tid);
 
-       dump_printf(": %s:%d\n", self->comm.comm, self->comm.tid);
+       dump_printf(": %s:%d\n", event->comm.comm, event->comm.tid);
 
-       if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm,
-                                                     &session->hists)) {
+       if (thread == NULL || thread__set_comm(thread, event->comm.comm)) {
                dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
                return -1;
        }
@@ -456,19 +440,21 @@ int event__process_comm(event_t *self, struct sample_data *sample __used,
        return 0;
 }
 
-int event__process_lost(event_t *self, struct sample_data *sample __used,
-                       struct perf_session *session)
+int perf_event__process_lost(union perf_event *event,
+                            struct perf_sample *sample __used,
+                            struct perf_session *session)
 {
        dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
-                   self->lost.id, self->lost.lost);
-       session->hists.stats.total_lost += self->lost.lost;
+                   event->lost.id, event->lost.lost);
+       session->hists.stats.total_lost += event->lost.lost;
        return 0;
 }
 
-static void event_set_kernel_mmap_len(struct map **maps, event_t *self)
+static void perf_event__set_kernel_mmap_len(union perf_event *event,
+                                           struct map **maps)
 {
-       maps[MAP__FUNCTION]->start = self->mmap.start;
-       maps[MAP__FUNCTION]->end   = self->mmap.start + self->mmap.len;
+       maps[MAP__FUNCTION]->start = event->mmap.start;
+       maps[MAP__FUNCTION]->end   = event->mmap.start + event->mmap.len;
        /*
         * Be a bit paranoid here, some perf.data file came with
         * a zero sized synthesized MMAP event for the kernel.
@@ -477,8 +463,8 @@ static void event_set_kernel_mmap_len(struct map **maps, event_t *self)
                maps[MAP__FUNCTION]->end = ~0ULL;
 }
 
-static int event__process_kernel_mmap(event_t *self,
-                       struct perf_session *session)
+static int perf_event__process_kernel_mmap(union perf_event *event,
+                                          struct perf_session *session)
 {
        struct map *map;
        char kmmap_prefix[PATH_MAX];
@@ -486,9 +472,9 @@ static int event__process_kernel_mmap(event_t *self,
        enum dso_kernel_type kernel_type;
        bool is_kernel_mmap;
 
-       machine = perf_session__findnew_machine(session, self->mmap.pid);
+       machine = perf_session__findnew_machine(session, event->mmap.pid);
        if (!machine) {
-               pr_err("Can't find id %d's machine\n", self->mmap.pid);
+               pr_err("Can't find id %d's machine\n", event->mmap.pid);
                goto out_problem;
        }
 
@@ -498,17 +484,17 @@ static int event__process_kernel_mmap(event_t *self,
        else
                kernel_type = DSO_TYPE_GUEST_KERNEL;
 
-       is_kernel_mmap = memcmp(self->mmap.filename,
+       is_kernel_mmap = memcmp(event->mmap.filename,
                                kmmap_prefix,
                                strlen(kmmap_prefix)) == 0;
-       if (self->mmap.filename[0] == '/' ||
-           (!is_kernel_mmap && self->mmap.filename[0] == '[')) {
+       if (event->mmap.filename[0] == '/' ||
+           (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
 
                char short_module_name[1024];
                char *name, *dot;
 
-               if (self->mmap.filename[0] == '/') {
-                       name = strrchr(self->mmap.filename, '/');
+               if (event->mmap.filename[0] == '/') {
+                       name = strrchr(event->mmap.filename, '/');
                        if (name == NULL)
                                goto out_problem;
 
@@ -520,10 +506,10 @@ static int event__process_kernel_mmap(event_t *self,
                                        "[%.*s]", (int)(dot - name), name);
                        strxfrchar(short_module_name, '-', '_');
                } else
-                       strcpy(short_module_name, self->mmap.filename);
+                       strcpy(short_module_name, event->mmap.filename);
 
-               map = machine__new_module(machine, self->mmap.start,
-                                         self->mmap.filename);
+               map = machine__new_module(machine, event->mmap.start,
+                                         event->mmap.filename);
                if (map == NULL)
                        goto out_problem;
 
@@ -533,9 +519,9 @@ static int event__process_kernel_mmap(event_t *self,
 
                map->dso->short_name = name;
                map->dso->sname_alloc = 1;
-               map->end = map->start + self->mmap.len;
+               map->end = map->start + event->mmap.len;
        } else if (is_kernel_mmap) {
-               const char *symbol_name = (self->mmap.filename +
+               const char *symbol_name = (event->mmap.filename +
                                strlen(kmmap_prefix));
                /*
                 * Should be there already, from the build-id table in
@@ -550,10 +536,10 @@ static int event__process_kernel_mmap(event_t *self,
                if (__machine__create_kernel_maps(machine, kernel) < 0)
                        goto out_problem;
 
-               event_set_kernel_mmap_len(machine->vmlinux_maps, self);
+               perf_event__set_kernel_mmap_len(event, machine->vmlinux_maps);
                perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
                                                         symbol_name,
-                                                        self->mmap.pgoff);
+                                                        event->mmap.pgoff);
                if (machine__is_default_guest(machine)) {
                        /*
                         * preload dso of guest kernel and modules
@@ -567,22 +553,23 @@ out_problem:
        return -1;
 }
 
-int event__process_mmap(event_t *self, struct sample_data *sample __used,
-                       struct perf_session *session)
+int perf_event__process_mmap(union perf_event *event,
+                            struct perf_sample *sample __used,
+                            struct perf_session *session)
 {
        struct machine *machine;
        struct thread *thread;
        struct map *map;
-       u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
+       u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
        int ret = 0;
 
        dump_printf(" %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n",
-                       self->mmap.pid, self->mmap.tid, self->mmap.start,
-                       self->mmap.len, self->mmap.pgoff, self->mmap.filename);
+                       event->mmap.pid, event->mmap.tid, event->mmap.start,
+                       event->mmap.len, event->mmap.pgoff, event->mmap.filename);
 
        if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
            cpumode == PERF_RECORD_MISC_KERNEL) {
-               ret = event__process_kernel_mmap(self, session);
+               ret = perf_event__process_kernel_mmap(event, session);
                if (ret < 0)
                        goto out_problem;
                return 0;
@@ -591,12 +578,12 @@ int event__process_mmap(event_t *self, struct sample_data *sample __used,
        machine = perf_session__find_host_machine(session);
        if (machine == NULL)
                goto out_problem;
-       thread = perf_session__findnew(session, self->mmap.pid);
+       thread = perf_session__findnew(session, event->mmap.pid);
        if (thread == NULL)
                goto out_problem;
-       map = map__new(&machine->user_dsos, self->mmap.start,
-                       self->mmap.len, self->mmap.pgoff,
-                       self->mmap.pid, self->mmap.filename,
+       map = map__new(&machine->user_dsos, event->mmap.start,
+                       event->mmap.len, event->mmap.pgoff,
+                       event->mmap.pid, event->mmap.filename,
                        MAP__FUNCTION);
        if (map == NULL)
                goto out_problem;
@@ -609,16 +596,17 @@ out_problem:
        return 0;
 }
 
-int event__process_task(event_t *self, struct sample_data *sample __used,
-                       struct perf_session *session)
+int perf_event__process_task(union perf_event *event,
+                            struct perf_sample *sample __used,
+                            struct perf_session *session)
 {
-       struct thread *thread = perf_session__findnew(session, self->fork.tid);
-       struct thread *parent = perf_session__findnew(session, self->fork.ptid);
+       struct thread *thread = perf_session__findnew(session, event->fork.tid);
+       struct thread *parent = perf_session__findnew(session, event->fork.ptid);
 
-       dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
-                   self->fork.ppid, self->fork.ptid);
+       dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
+                   event->fork.ppid, event->fork.ptid);
 
-       if (self->header.type == PERF_RECORD_EXIT) {
+       if (event->header.type == PERF_RECORD_EXIT) {
                perf_session__remove_thread(session, thread);
                return 0;
        }
@@ -632,20 +620,22 @@ int event__process_task(event_t *self, struct sample_data *sample __used,
        return 0;
 }
 
-int event__process(event_t *event, struct sample_data *sample,
-                  struct perf_session *session)
+int perf_event__process(union perf_event *event, struct perf_sample *sample,
+                       struct perf_session *session)
 {
        switch (event->header.type) {
        case PERF_RECORD_COMM:
-               event__process_comm(event, sample, session);
+               perf_event__process_comm(event, sample, session);
                break;
        case PERF_RECORD_MMAP:
-               event__process_mmap(event, sample, session);
+               perf_event__process_mmap(event, sample, session);
                break;
        case PERF_RECORD_FORK:
        case PERF_RECORD_EXIT:
-               event__process_task(event, sample, session);
+               perf_event__process_task(event, sample, session);
                break;
+       case PERF_RECORD_LOST:
+               perf_event__process_lost(event, sample, session);
        default:
                break;
        }
@@ -742,24 +732,14 @@ void thread__find_addr_location(struct thread *self,
                al->sym = NULL;
 }
 
-static void dso__calc_col_width(struct dso *self, struct hists *hists)
-{
-       if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
-           (!symbol_conf.dso_list ||
-            strlist__has_entry(symbol_conf.dso_list, self->name))) {
-               u16 slen = dso__name_len(self);
-               hists__new_col_len(hists, HISTC_DSO, slen);
-       }
-
-       self->slen_calculated = 1;
-}
-
-int event__preprocess_sample(const event_t *self, struct perf_session *session,
-                            struct addr_location *al, struct sample_data *data,
-                            symbol_filter_t filter)
+int perf_event__preprocess_sample(const union perf_event *event,
+                                 struct perf_session *session,
+                                 struct addr_location *al,
+                                 struct perf_sample *sample,
+                                 symbol_filter_t filter)
 {
-       u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
-       struct thread *thread = perf_session__findnew(session, self->ip.pid);
+       u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
+       struct thread *thread = perf_session__findnew(session, event->ip.pid);
 
        if (thread == NULL)
                return -1;
@@ -781,12 +761,12 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
                machine__create_kernel_maps(&session->host_machine);
 
        thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
-                             self->ip.pid, self->ip.ip, al);
+                             event->ip.pid, event->ip.ip, al);
        dump_printf(" ...... dso: %s\n",
                    al->map ? al->map->dso->long_name :
                        al->level == 'H' ? "[hypervisor]" : "<not found>");
        al->sym = NULL;
-       al->cpu = data->cpu;
+       al->cpu = sample->cpu;
 
        if (al->map) {
                if (symbol_conf.dso_list &&
@@ -797,23 +777,8 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
                        strlist__has_entry(symbol_conf.dso_list,
                                           al->map->dso->long_name)))))
                        goto out_filtered;
-               /*
-                * We have to do this here as we may have a dso with no symbol
-                * hit that has a name longer than the ones with symbols
-                * sampled.
-                */
-               if (!sort_dso.elide && !al->map->dso->slen_calculated)
-                       dso__calc_col_width(al->map->dso, &session->hists);
 
                al->sym = map__find_symbol(al->map, al->addr, filter);
-       } else {
-               const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
-
-               if (hists__col_len(&session->hists, HISTC_DSO) < unresolved_col_width &&
-                   !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
-                   !symbol_conf.dso_list)
-                       hists__set_col_len(&session->hists, HISTC_DSO,
-                                          unresolved_col_width);
        }
 
        if (symbol_conf.sym_list && al->sym &&
@@ -826,128 +791,3 @@ out_filtered:
        al->filtered = true;
        return 0;
 }
-
-static int event__parse_id_sample(const event_t *event,
-                                 struct perf_session *session,
-                                 struct sample_data *sample)
-{
-       const u64 *array;
-       u64 type;
-
-       sample->cpu = sample->pid = sample->tid = -1;
-       sample->stream_id = sample->id = sample->time = -1ULL;
-
-       if (!session->sample_id_all)
-               return 0;
-
-       array = event->sample.array;
-       array += ((event->header.size -
-                  sizeof(event->header)) / sizeof(u64)) - 1;
-       type = session->sample_type;
-
-       if (type & PERF_SAMPLE_CPU) {
-               u32 *p = (u32 *)array;
-               sample->cpu = *p;
-               array--;
-       }
-
-       if (type & PERF_SAMPLE_STREAM_ID) {
-               sample->stream_id = *array;
-               array--;
-       }
-
-       if (type & PERF_SAMPLE_ID) {
-               sample->id = *array;
-               array--;
-       }
-
-       if (type & PERF_SAMPLE_TIME) {
-               sample->time = *array;
-               array--;
-       }
-
-       if (type & PERF_SAMPLE_TID) {
-               u32 *p = (u32 *)array;
-               sample->pid = p[0];
-               sample->tid = p[1];
-       }
-
-       return 0;
-}
-
-int event__parse_sample(const event_t *event, struct perf_session *session,
-                       struct sample_data *data)
-{
-       const u64 *array;
-       u64 type;
-
-       if (event->header.type != PERF_RECORD_SAMPLE)
-               return event__parse_id_sample(event, session, data);
-
-       array = event->sample.array;
-       type = session->sample_type;
-
-       if (type & PERF_SAMPLE_IP) {
-               data->ip = event->ip.ip;
-               array++;
-       }
-
-       if (type & PERF_SAMPLE_TID) {
-               u32 *p = (u32 *)array;
-               data->pid = p[0];
-               data->tid = p[1];
-               array++;
-       }
-
-       if (type & PERF_SAMPLE_TIME) {
-               data->time = *array;
-               array++;
-       }
-
-       if (type & PERF_SAMPLE_ADDR) {
-               data->addr = *array;
-               array++;
-       }
-
-       data->id = -1ULL;
-       if (type & PERF_SAMPLE_ID) {
-               data->id = *array;
-               array++;
-       }
-
-       if (type & PERF_SAMPLE_STREAM_ID) {
-               data->stream_id = *array;
-               array++;
-       }
-
-       if (type & PERF_SAMPLE_CPU) {
-               u32 *p = (u32 *)array;
-               data->cpu = *p;
-               array++;
-       } else
-               data->cpu = -1;
-
-       if (type & PERF_SAMPLE_PERIOD) {
-               data->period = *array;
-               array++;
-       }
-
-       if (type & PERF_SAMPLE_READ) {
-               pr_debug("PERF_SAMPLE_READ is unsuported for now\n");
-               return -1;
-       }
-
-       if (type & PERF_SAMPLE_CALLCHAIN) {
-               data->callchain = (struct ip_callchain *)array;
-               array += 1 + data->callchain->nr;
-       }
-
-       if (type & PERF_SAMPLE_RAW) {
-               u32 *p = (u32 *)array;
-               data->raw_size = *p;
-               p++;
-               data->raw_data = p;
-       }
-
-       return 0;
-}
index 2b7e919..9c35170 100644 (file)
@@ -61,7 +61,7 @@ struct sample_event {
        u64 array[];
 };
 
-struct sample_data {
+struct perf_sample {
        u64 ip;
        u32 pid, tid;
        u64 time;
@@ -117,7 +117,7 @@ struct tracing_data_event {
        u32 size;
 };
 
-typedef union event_union {
+union perf_event {
        struct perf_event_header        header;
        struct ip_event                 ip;
        struct mmap_event               mmap;
@@ -130,48 +130,54 @@ typedef union event_union {
        struct event_type_event         event_type;
        struct tracing_data_event       tracing_data;
        struct build_id_event           build_id;
-} event_t;
+};
 
-void event__print_totals(void);
+void perf_event__print_totals(void);
 
 struct perf_session;
+struct thread_map;
 
-typedef int (*event__handler_synth_t)(event_t *event, 
+typedef int (*perf_event__handler_synth_t)(union perf_event *event, 
+                                          struct perf_session *session);
+typedef int (*perf_event__handler_t)(union perf_event *event,
+                                    struct perf_sample *sample,
                                      struct perf_session *session);
-typedef int (*event__handler_t)(event_t *event, struct sample_data *sample,
-                               struct perf_session *session);
 
-int event__synthesize_thread(pid_t pid, event__handler_t process,
+int perf_event__synthesize_thread_map(struct thread_map *threads,
+                                     perf_event__handler_t process,
+                                     struct perf_session *session);
+int perf_event__synthesize_threads(perf_event__handler_t process,
+                                  struct perf_session *session);
+int perf_event__synthesize_kernel_mmap(perf_event__handler_t process,
+                                      struct perf_session *session,
+                                      struct machine *machine,
+                                      const char *symbol_name);
+
+int perf_event__synthesize_modules(perf_event__handler_t process,
+                                  struct perf_session *session,
+                                  struct machine *machine);
+
+int perf_event__process_comm(union perf_event *event, struct perf_sample *sample,
                             struct perf_session *session);
-int event__synthesize_threads(event__handler_t process,
-                             struct perf_session *session);
-int event__synthesize_kernel_mmap(event__handler_t process,
-                               struct perf_session *session,
-                               struct machine *machine,
-                               const char *symbol_name);
-
-int event__synthesize_modules(event__handler_t process,
-                             struct perf_session *session,
-                             struct machine *machine);
-
-int event__process_comm(event_t *self, struct sample_data *sample,
-                       struct perf_session *session);
-int event__process_lost(event_t *self, struct sample_data *sample,
-                       struct perf_session *session);
-int event__process_mmap(event_t *self, struct sample_data *sample,
-                       struct perf_session *session);
-int event__process_task(event_t *self, struct sample_data *sample,
+int perf_event__process_lost(union perf_event *event, struct perf_sample *sample,
+                            struct perf_session *session);
+int perf_event__process_mmap(union perf_event *event, struct perf_sample *sample,
+                            struct perf_session *session);
+int perf_event__process_task(union perf_event *event, struct perf_sample *sample,
+                            struct perf_session *session);
+int perf_event__process(union perf_event *event, struct perf_sample *sample,
                        struct perf_session *session);
-int event__process(event_t *event, struct sample_data *sample,
-                  struct perf_session *session);
 
 struct addr_location;
-int event__preprocess_sample(const event_t *self, struct perf_session *session,
-                            struct addr_location *al, struct sample_data *data,
-                            symbol_filter_t filter);
-int event__parse_sample(const event_t *event, struct perf_session *session,
-                       struct sample_data *sample);
+int perf_event__preprocess_sample(const union perf_event *self,
+                                 struct perf_session *session,
+                                 struct addr_location *al,
+                                 struct perf_sample *sample,
+                                 symbol_filter_t filter);
+
+const char *perf_event__name(unsigned int id);
 
-const char *event__get_event_name(unsigned int id);
+int perf_event__parse_sample(const union perf_event *event, u64 type,
+                            bool sample_id_all, struct perf_sample *sample);
 
 #endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
new file mode 100644 (file)
index 0000000..d852cef
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
+ *
+ * Parts came from builtin-{top,stat,record}.c, see those files for further
+ * copyright notes.
+ *
+ * Released under the GPL v2. (and only v2, not any later version)
+ */
+#include <poll.h>
+#include "cpumap.h"
+#include "thread_map.h"
+#include "evlist.h"
+#include "evsel.h"
+#include "util.h"
+
+#include <sys/mman.h>
+
+#include <linux/bitops.h>
+#include <linux/hash.h>
+
+#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
+#define SID(e, x, y) xyarray__entry(e->sample_id, x, y)
+
+void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
+                      struct thread_map *threads)
+{
+       int i;
+
+       for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i)
+               INIT_HLIST_HEAD(&evlist->heads[i]);
+       INIT_LIST_HEAD(&evlist->entries);
+       perf_evlist__set_maps(evlist, cpus, threads);
+}
+
+struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
+                                    struct thread_map *threads)
+{
+       struct perf_evlist *evlist = zalloc(sizeof(*evlist));
+
+       if (evlist != NULL)
+               perf_evlist__init(evlist, cpus, threads);
+
+       return evlist;
+}
+
+static void perf_evlist__purge(struct perf_evlist *evlist)
+{
+       struct perf_evsel *pos, *n;
+
+       list_for_each_entry_safe(pos, n, &evlist->entries, node) {
+               list_del_init(&pos->node);
+               perf_evsel__delete(pos);
+       }
+
+       evlist->nr_entries = 0;
+}
+
+void perf_evlist__exit(struct perf_evlist *evlist)
+{
+       free(evlist->mmap);
+       free(evlist->pollfd);
+       evlist->mmap = NULL;
+       evlist->pollfd = NULL;
+}
+
+void perf_evlist__delete(struct perf_evlist *evlist)
+{
+       perf_evlist__purge(evlist);
+       perf_evlist__exit(evlist);
+       free(evlist);
+}
+
+void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
+{
+       list_add_tail(&entry->node, &evlist->entries);
+       ++evlist->nr_entries;
+}
+
+int perf_evlist__add_default(struct perf_evlist *evlist)
+{
+       struct perf_event_attr attr = {
+               .type = PERF_TYPE_HARDWARE,
+               .config = PERF_COUNT_HW_CPU_CYCLES,
+       };
+       struct perf_evsel *evsel = perf_evsel__new(&attr, 0);
+
+       if (evsel == NULL)
+               return -ENOMEM;
+
+       perf_evlist__add(evlist, evsel);
+       return 0;
+}
+
+int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
+{
+       int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries;
+       evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
+       return evlist->pollfd != NULL ? 0 : -ENOMEM;
+}
+
+void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd)
+{
+       fcntl(fd, F_SETFL, O_NONBLOCK);
+       evlist->pollfd[evlist->nr_fds].fd = fd;
+       evlist->pollfd[evlist->nr_fds].events = POLLIN;
+       evlist->nr_fds++;
+}
+
+static void perf_evlist__id_hash(struct perf_evlist *evlist,
+                                struct perf_evsel *evsel,
+                                int cpu, int thread, u64 id)
+{
+       int hash;
+       struct perf_sample_id *sid = SID(evsel, cpu, thread);
+
+       sid->id = id;
+       sid->evsel = evsel;
+       hash = hash_64(sid->id, PERF_EVLIST__HLIST_BITS);
+       hlist_add_head(&sid->node, &evlist->heads[hash]);
+}
+
+void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
+                        int cpu, int thread, u64 id)
+{
+       perf_evlist__id_hash(evlist, evsel, cpu, thread, id);
+       evsel->id[evsel->ids++] = id;
+}
+
+static int perf_evlist__id_add_fd(struct perf_evlist *evlist,
+                                 struct perf_evsel *evsel,
+                                 int cpu, int thread, int fd)
+{
+       u64 read_data[4] = { 0, };
+       int id_idx = 1; /* The first entry is the counter value */
+
+       if (!(evsel->attr.read_format & PERF_FORMAT_ID) ||
+           read(fd, &read_data, sizeof(read_data)) == -1)
+               return -1;
+
+       if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
+               ++id_idx;
+       if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
+               ++id_idx;
+
+       perf_evlist__id_add(evlist, evsel, cpu, thread, read_data[id_idx]);
+       return 0;
+}
+
+struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
+{
+       struct hlist_head *head;
+       struct hlist_node *pos;
+       struct perf_sample_id *sid;
+       int hash;
+
+       if (evlist->nr_entries == 1)
+               return list_entry(evlist->entries.next, struct perf_evsel, node);
+
+       hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
+       head = &evlist->heads[hash];
+
+       hlist_for_each_entry(sid, pos, head, node)
+               if (sid->id == id)
+                       return sid->evsel;
+       return NULL;
+}
+
+union perf_event *perf_evlist__read_on_cpu(struct perf_evlist *evlist, int cpu)
+{
+       /* 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];
+       unsigned int head = perf_mmap__read_head(md);
+       unsigned int old = md->prev;
+       unsigned char *data = md->base + page_size;
+       union perf_event *event = NULL;
+
+       if (evlist->overwrite) {
+               /*
+                * If we're further behind than half the buffer, there's a chance
+                * the writer will bite our tail and mess up the samples under us.
+                *
+                * If we somehow ended up ahead of the head, we got messed up.
+                *
+                * In either case, truncate and restart at head.
+                */
+               int diff = head - old;
+               if (diff > md->mask / 2 || diff < 0) {
+                       fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
+
+                       /*
+                        * head points to a known good entry, start there.
+                        */
+                       old = head;
+               }
+       }
+
+       if (old != head) {
+               size_t size;
+
+               event = (union perf_event *)&data[old & md->mask];
+               size = event->header.size;
+
+               /*
+                * Event straddles the mmap boundary -- header should always
+                * be inside due to u64 alignment of output.
+                */
+               if ((old & md->mask) + size != ((old + size) & md->mask)) {
+                       unsigned int offset = old;
+                       unsigned int len = min(sizeof(*event), size), cpy;
+                       void *dst = &evlist->event_copy;
+
+                       do {
+                               cpy = min(md->mask + 1 - (offset & md->mask), len);
+                               memcpy(dst, &data[offset & md->mask], cpy);
+                               offset += cpy;
+                               dst += cpy;
+                               len -= cpy;
+                       } while (len);
+
+                       event = &evlist->event_copy;
+               }
+
+               old += size;
+       }
+
+       md->prev = old;
+
+       if (!evlist->overwrite)
+               perf_mmap__write_tail(md, old);
+
+       return event;
+}
+
+void perf_evlist__munmap(struct perf_evlist *evlist)
+{
+       int cpu;
+
+       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;
+               }
+       }
+}
+
+int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
+{
+       evlist->mmap = zalloc(evlist->cpus->nr * sizeof(struct perf_mmap));
+       return evlist->mmap != NULL ? 0 : -ENOMEM;
+}
+
+static int __perf_evlist__mmap(struct perf_evlist *evlist, int cpu, 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,
+                                     MAP_SHARED, fd, 0);
+       if (evlist->mmap[cpu].base == MAP_FAILED)
+               return -1;
+
+       perf_evlist__add_pollfd(evlist, fd);
+       return 0;
+}
+
+/** perf_evlist__mmap - Create per cpu maps to receive events
+ *
+ * @evlist - list of events
+ * @pages - map length in pages
+ * @overwrite - overwrite older events?
+ *
+ * If overwrite is false the user needs to signal event consuption using:
+ *
+ *     struct perf_mmap *m = &evlist->mmap[cpu];
+ *     unsigned int head = perf_mmap__read_head(m);
+ *
+ *     perf_mmap__write_tail(m, head)
+ *
+ * Using perf_evlist__read_on_cpu does this automatically.
+ */
+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;
+       const struct cpu_map *cpus = evlist->cpus;
+       const struct thread_map *threads = evlist->threads;
+       int thread, prot = PROT_READ | (overwrite ? 0 : PROT_WRITE);
+
+       if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
+               return -ENOMEM;
+
+       if (evlist->pollfd == NULL && perf_evlist__alloc_pollfd(evlist) < 0)
+               return -ENOMEM;
+
+       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, 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;
+
+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;
+}
+
+int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
+                            pid_t target_tid, const char *cpu_list)
+{
+       evlist->threads = thread_map__new(target_pid, target_tid);
+
+       if (evlist->threads == NULL)
+               return -1;
+
+       if (target_tid != -1)
+               evlist->cpus = cpu_map__dummy_new();
+       else
+               evlist->cpus = cpu_map__new(cpu_list);
+
+       if (evlist->cpus == NULL)
+               goto out_delete_threads;
+
+       return 0;
+
+out_delete_threads:
+       thread_map__delete(evlist->threads);
+       return -1;
+}
+
+void perf_evlist__delete_maps(struct perf_evlist *evlist)
+{
+       cpu_map__delete(evlist->cpus);
+       thread_map__delete(evlist->threads);
+       evlist->cpus    = NULL;
+       evlist->threads = NULL;
+}
+
+int perf_evlist__set_filters(struct perf_evlist *evlist)
+{
+       const struct thread_map *threads = evlist->threads;
+       const struct cpu_map *cpus = evlist->cpus;
+       struct perf_evsel *evsel;
+       char *filter;
+       int thread;
+       int cpu;
+       int err;
+       int fd;
+
+       list_for_each_entry(evsel, &evlist->entries, node) {
+               filter = evsel->filter;
+               if (!filter)
+                       continue;
+               for (cpu = 0; cpu < cpus->nr; cpu++) {
+                       for (thread = 0; thread < threads->nr; thread++) {
+                               fd = FD(evsel, cpu, thread);
+                               err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter);
+                               if (err)
+                                       return err;
+                       }
+               }
+       }
+
+       return 0;
+}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
new file mode 100644 (file)
index 0000000..8b1cb7a
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef __PERF_EVLIST_H
+#define __PERF_EVLIST_H 1
+
+#include <linux/list.h>
+#include "../perf.h"
+#include "event.h"
+
+struct pollfd;
+struct thread_map;
+struct cpu_map;
+
+#define PERF_EVLIST__HLIST_BITS 8
+#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS)
+
+struct perf_evlist {
+       struct list_head entries;
+       struct hlist_head heads[PERF_EVLIST__HLIST_SIZE];
+       int              nr_entries;
+       int              nr_fds;
+       int              mmap_len;
+       bool             overwrite;
+       union perf_event event_copy;
+       struct perf_mmap *mmap;
+       struct pollfd    *pollfd;
+       struct thread_map *threads;
+       struct cpu_map    *cpus;
+};
+
+struct perf_evsel;
+
+struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
+                                    struct thread_map *threads);
+void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
+                      struct thread_map *threads);
+void perf_evlist__exit(struct perf_evlist *evlist);
+void perf_evlist__delete(struct perf_evlist *evlist);
+
+void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry);
+int perf_evlist__add_default(struct perf_evlist *evlist);
+
+void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
+                        int cpu, int thread, u64 id);
+
+int perf_evlist__alloc_pollfd(struct perf_evlist *evlist);
+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);
+
+int perf_evlist__alloc_mmap(struct perf_evlist *evlist);
+int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite);
+void perf_evlist__munmap(struct perf_evlist *evlist);
+
+static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
+                                        struct cpu_map *cpus,
+                                        struct thread_map *threads)
+{
+       evlist->cpus    = cpus;
+       evlist->threads = threads;
+}
+
+int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
+                            pid_t target_tid, const char *cpu_list);
+void perf_evlist__delete_maps(struct perf_evlist *evlist);
+int perf_evlist__set_filters(struct perf_evlist *evlist);
+
+#endif /* __PERF_EVLIST_H */
index f5cfed6..662596a 100644 (file)
@@ -1,20 +1,34 @@
+/*
+ * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
+ *
+ * Parts came from builtin-{top,stat,record}.c, see those files for further
+ * copyright notes.
+ *
+ * Released under the GPL v2. (and only v2, not any later version)
+ */
+
 #include "evsel.h"
-#include "../perf.h"
+#include "evlist.h"
 #include "util.h"
 #include "cpumap.h"
-#include "thread.h"
+#include "thread_map.h"
 
 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
 
+void perf_evsel__init(struct perf_evsel *evsel,
+                     struct perf_event_attr *attr, int idx)
+{
+       evsel->idx         = idx;
+       evsel->attr        = *attr;
+       INIT_LIST_HEAD(&evsel->node);
+}
+
 struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
 {
        struct perf_evsel *evsel = zalloc(sizeof(*evsel));
 
-       if (evsel != NULL) {
-               evsel->idx         = idx;
-               evsel->attr        = *attr;
-               INIT_LIST_HEAD(&evsel->node);
-       }
+       if (evsel != NULL)
+               perf_evsel__init(evsel, attr, idx);
 
        return evsel;
 }
@@ -25,6 +39,22 @@ int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
        return evsel->fd != NULL ? 0 : -ENOMEM;
 }
 
+int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
+{
+       evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
+       if (evsel->sample_id == NULL)
+               return -ENOMEM;
+
+       evsel->id = zalloc(ncpus * nthreads * sizeof(u64));
+       if (evsel->id == NULL) {
+               xyarray__delete(evsel->sample_id);
+               evsel->sample_id = NULL;
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
 int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
 {
        evsel->counts = zalloc((sizeof(*evsel->counts) +
@@ -38,6 +68,14 @@ void perf_evsel__free_fd(struct perf_evsel *evsel)
        evsel->fd = NULL;
 }
 
+void perf_evsel__free_id(struct perf_evsel *evsel)
+{
+       xyarray__delete(evsel->sample_id);
+       evsel->sample_id = NULL;
+       free(evsel->id);
+       evsel->id = NULL;
+}
+
 void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
 {
        int cpu, thread;
@@ -49,10 +87,19 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
                }
 }
 
-void perf_evsel__delete(struct perf_evsel *evsel)
+void perf_evsel__exit(struct perf_evsel *evsel)
 {
        assert(list_empty(&evsel->node));
        xyarray__delete(evsel->fd);
+       xyarray__delete(evsel->sample_id);
+       free(evsel->id);
+}
+
+void perf_evsel__delete(struct perf_evsel *evsel)
+{
+       perf_evsel__exit(evsel);
+       close_cgroup(evsel->cgrp);
+       free(evsel->name);
        free(evsel);
 }
 
@@ -90,7 +137,7 @@ int __perf_evsel__read(struct perf_evsel *evsel,
        int cpu, thread;
        struct perf_counts_values *aggr = &evsel->counts->aggr, count;
 
-       aggr->val = 0;
+       aggr->val = aggr->ena = aggr->run = 0;
 
        for (cpu = 0; cpu < ncpus; cpu++) {
                for (thread = 0; thread < nthreads; thread++) {
@@ -128,21 +175,51 @@ int __perf_evsel__read(struct perf_evsel *evsel,
 }
 
 static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
-                             struct thread_map *threads)
+                             struct thread_map *threads, bool group, bool inherit)
 {
        int cpu, thread;
+       unsigned long flags = 0;
+       int pid = -1;
 
        if (evsel->fd == NULL &&
            perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
                return -1;
 
+       if (evsel->cgrp) {
+               flags = PERF_FLAG_PID_CGROUP;
+               pid = evsel->cgrp->fd;
+       }
+
        for (cpu = 0; cpu < cpus->nr; cpu++) {
+               int group_fd = -1;
+               /*
+                * Don't allow mmap() of inherited per-task counters. This
+                * would create a performance issue due to all children writing
+                * to the same buffer.
+                *
+                * FIXME:
+                * Proper fix is not to pass 'inherit' to perf_evsel__open*,
+                * but a 'flags' parameter, with 'group' folded there as well,
+                * then introduce a PERF_O_{MMAP,GROUP,INHERIT} enum, and if
+                * O_MMAP is set, emit a warning if cpu < 0 and O_INHERIT is
+                * set. Lets go for the minimal fix first tho.
+                */
+               evsel->attr.inherit = (cpus->map[cpu] >= 0) && inherit;
+
                for (thread = 0; thread < threads->nr; thread++) {
+
+                       if (!evsel->cgrp)
+                               pid = threads->map[thread];
+
                        FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
-                                                                    threads->map[thread],
-                                                                    cpus->map[cpu], -1, 0);
+                                                                    pid,
+                                                                    cpus->map[cpu],
+                                                                    group_fd, flags);
                        if (FD(evsel, cpu, thread) < 0)
                                goto out_close;
+
+                       if (group && group_fd == -1)
+                               group_fd = FD(evsel, cpu, thread);
                }
        }
 
@@ -175,10 +252,9 @@ static struct {
        .threads = { -1, },
 };
 
-int perf_evsel__open(struct perf_evsel *evsel,
-                    struct cpu_map *cpus, struct thread_map *threads)
+int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
+                    struct thread_map *threads, bool group, bool inherit)
 {
-
        if (cpus == NULL) {
                /* Work around old compiler warnings about strict aliasing */
                cpus = &empty_cpu_map.map;
@@ -187,15 +263,135 @@ int perf_evsel__open(struct perf_evsel *evsel,
        if (threads == NULL)
                threads = &empty_thread_map.map;
 
-       return __perf_evsel__open(evsel, cpus, threads);
+       return __perf_evsel__open(evsel, cpus, threads, group, inherit);
 }
 
-int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus)
+int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
+                            struct cpu_map *cpus, bool group, bool inherit)
 {
-       return __perf_evsel__open(evsel, cpus, &empty_thread_map.map);
+       return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group, inherit);
+}
+
+int perf_evsel__open_per_thread(struct perf_evsel *evsel,
+                               struct thread_map *threads, bool group, bool inherit)
+{
+       return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, inherit);
+}
+
+static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
+                                      struct perf_sample *sample)
+{
+       const u64 *array = event->sample.array;
+
+       array += ((event->header.size -
+                  sizeof(event->header)) / sizeof(u64)) - 1;
+
+       if (type & PERF_SAMPLE_CPU) {
+               u32 *p = (u32 *)array;
+               sample->cpu = *p;
+               array--;
+       }
+
+       if (type & PERF_SAMPLE_STREAM_ID) {
+               sample->stream_id = *array;
+               array--;
+       }
+
+       if (type & PERF_SAMPLE_ID) {
+               sample->id = *array;
+               array--;
+       }
+
+       if (type & PERF_SAMPLE_TIME) {
+               sample->time = *array;
+               array--;
+       }
+
+       if (type & PERF_SAMPLE_TID) {
+               u32 *p = (u32 *)array;
+               sample->pid = p[0];
+               sample->tid = p[1];
+       }
+
+       return 0;
 }
 
-int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads)
+int perf_event__parse_sample(const union perf_event *event, u64 type,
+                            bool sample_id_all, struct perf_sample *data)
 {
-       return __perf_evsel__open(evsel, &empty_cpu_map.map, threads);
+       const u64 *array;
+
+       data->cpu = data->pid = data->tid = -1;
+       data->stream_id = data->id = data->time = -1ULL;
+
+       if (event->header.type != PERF_RECORD_SAMPLE) {
+               if (!sample_id_all)
+                       return 0;
+               return perf_event__parse_id_sample(event, type, data);
+       }
+
+       array = event->sample.array;
+
+       if (type & PERF_SAMPLE_IP) {
+               data->ip = event->ip.ip;
+               array++;
+       }
+
+       if (type & PERF_SAMPLE_TID) {
+               u32 *p = (u32 *)array;
+               data->pid = p[0];
+               data->tid = p[1];
+               array++;
+       }
+
+       if (type & PERF_SAMPLE_TIME) {
+               data->time = *array;
+               array++;
+       }
+
+       if (type & PERF_SAMPLE_ADDR) {
+               data->addr = *array;
+               array++;
+       }
+
+       data->id = -1ULL;
+       if (type & PERF_SAMPLE_ID) {
+               data->id = *array;
+               array++;
+       }
+
+       if (type & PERF_SAMPLE_STREAM_ID) {
+               data->stream_id = *array;
+               array++;
+       }
+
+       if (type & PERF_SAMPLE_CPU) {
+               u32 *p = (u32 *)array;
+               data->cpu = *p;
+               array++;
+       }
+
+       if (type & PERF_SAMPLE_PERIOD) {
+               data->period = *array;
+               array++;
+       }
+
+       if (type & PERF_SAMPLE_READ) {
+               fprintf(stderr, "PERF_SAMPLE_READ is unsuported for now\n");
+               return -1;
+       }
+
+       if (type & PERF_SAMPLE_CALLCHAIN) {
+               data->callchain = (struct ip_callchain *)array;
+               array += 1 + data->callchain->nr;
+       }
+
+       if (type & PERF_SAMPLE_RAW) {
+               u32 *p = (u32 *)array;
+               data->raw_size = *p;
+               p++;
+               data->raw_data = p;
+       }
+
+       return 0;
 }
index b2d755f..6710ab5 100644 (file)
@@ -6,6 +6,8 @@
 #include "../../../include/linux/perf_event.h"
 #include "types.h"
 #include "xyarray.h"
+#include "cgroup.h"
+#include "hist.h"
  
 struct perf_counts_values {
        union {
@@ -24,31 +26,66 @@ struct perf_counts {
        struct perf_counts_values cpu[];
 };
 
+struct perf_evsel;
+
+/*
+ * Per fd, to map back from PERF_SAMPLE_ID to evsel, only used when there are
+ * more than one entry in the evlist.
+ */
+struct perf_sample_id {
+       struct hlist_node       node;
+       u64                     id;
+       struct perf_evsel       *evsel;
+};
+
+/** struct perf_evsel - event selector
+ *
+ * @name - Can be set to retain the original event name passed by the user,
+ *         so that when showing results in tools such as 'perf stat', we
+ *         show the name used, not some alias.
+ */
 struct perf_evsel {
        struct list_head        node;
        struct perf_event_attr  attr;
        char                    *filter;
        struct xyarray          *fd;
+       struct xyarray          *sample_id;
+       u64                     *id;
        struct perf_counts      *counts;
        int                     idx;
-       void                    *priv;
+       int                     ids;
+       struct hists            hists;
+       char                    *name;
+       union {
+               void            *priv;
+               off_t           id_offset;
+       };
+       struct cgroup_sel       *cgrp;
 };
 
 struct cpu_map;
 struct thread_map;
+struct perf_evlist;
 
 struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx);
+void perf_evsel__init(struct perf_evsel *evsel,
+                     struct perf_event_attr *attr, int idx);
+void perf_evsel__exit(struct perf_evsel *evsel);
 void perf_evsel__delete(struct perf_evsel *evsel);
 
 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
+int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
 int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
 void perf_evsel__free_fd(struct perf_evsel *evsel);
+void perf_evsel__free_id(struct perf_evsel *evsel);
 void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
 
-int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus);
-int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads);
-int perf_evsel__open(struct perf_evsel *evsel, 
-                    struct cpu_map *cpus, struct thread_map *threads);
+int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
+                            struct cpu_map *cpus, bool group, bool inherit);
+int perf_evsel__open_per_thread(struct perf_evsel *evsel,
+                               struct thread_map *threads, bool group, bool inherit);
+int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
+                    struct thread_map *threads, bool group, bool inherit);
 
 #define perf_evsel__match(evsel, t, c)         \
        (evsel->attr.type == PERF_TYPE_##t &&   \
index 67eeff5..7adf4ad 100644 (file)
@@ -11,31 +11,12 @@ static const char *argv0_path;
 
 const char *system_path(const char *path)
 {
-#ifdef RUNTIME_PREFIX
-       static const char *prefix;
-#else
        static const char *prefix = PREFIX;
-#endif
        struct strbuf d = STRBUF_INIT;
 
        if (is_absolute_path(path))
                return path;
 
-#ifdef RUNTIME_PREFIX
-       assert(argv0_path);
-       assert(is_absolute_path(argv0_path));
-
-       if (!prefix &&
-           !(prefix = strip_path_suffix(argv0_path, PERF_EXEC_PATH)) &&
-           !(prefix = strip_path_suffix(argv0_path, BINDIR)) &&
-           !(prefix = strip_path_suffix(argv0_path, "perf"))) {
-               prefix = PREFIX;
-               fprintf(stderr, "RUNTIME_PREFIX requested, "
-                               "but prefix computation failed.  "
-                               "Using static fallback '%s'.\n", prefix);
-       }
-#endif
-
        strbuf_addf(&d, "%s/%s", prefix, path);
        path = strbuf_detach(&d, NULL);
        return path;
index f6a929e..e5230c0 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/list.h>
 #include <linux/kernel.h>
 
+#include "evlist.h"
+#include "evsel.h"
 #include "util.h"
 #include "header.h"
 #include "../perf.h"
 
 static bool no_buildid_cache = false;
 
-/*
- * Create new perf.data header attribute:
- */
-struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr)
-{
-       struct perf_header_attr *self = malloc(sizeof(*self));
-
-       if (self != NULL) {
-               self->attr = *attr;
-               self->ids  = 0;
-               self->size = 1;
-               self->id   = malloc(sizeof(u64));
-               if (self->id == NULL) {
-                       free(self);
-                       self = NULL;
-               }
-       }
-
-       return self;
-}
-
-void perf_header_attr__delete(struct perf_header_attr *self)
-{
-       free(self->id);
-       free(self);
-}
-
-int perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
-{
-       int pos = self->ids;
-
-       self->ids++;
-       if (self->ids > self->size) {
-               int nsize = self->size * 2;
-               u64 *nid = realloc(self->id, nsize * sizeof(u64));
-
-               if (nid == NULL)
-                       return -1;
-
-               self->size = nsize;
-               self->id = nid;
-       }
-       self->id[pos] = id;
-       return 0;
-}
-
-int perf_header__init(struct perf_header *self)
-{
-       self->size = 1;
-       self->attr = malloc(sizeof(void *));
-       return self->attr == NULL ? -ENOMEM : 0;
-}
-
-void perf_header__exit(struct perf_header *self)
-{
-       int i;
-       for (i = 0; i < self->attrs; ++i)
-                perf_header_attr__delete(self->attr[i]);
-       free(self->attr);
-}
-
-int perf_header__add_attr(struct perf_header *self,
-                         struct perf_header_attr *attr)
-{
-       if (self->frozen)
-               return -1;
-
-       if (self->attrs == self->size) {
-               int nsize = self->size * 2;
-               struct perf_header_attr **nattr;
-
-               nattr = realloc(self->attr, nsize * sizeof(void *));
-               if (nattr == NULL)
-                       return -1;
-
-               self->size = nsize;
-               self->attr = nattr;
-       }
-
-       self->attr[self->attrs++] = attr;
-       return 0;
-}
-
 static int event_count;
 static struct perf_trace_event_type *events;
 
@@ -147,19 +66,19 @@ struct perf_file_attr {
        struct perf_file_section        ids;
 };
 
-void perf_header__set_feat(struct perf_header *self, int feat)
+void perf_header__set_feat(struct perf_header *header, int feat)
 {
-       set_bit(feat, self->adds_features);
+       set_bit(feat, header->adds_features);
 }
 
-void perf_header__clear_feat(struct perf_header *self, int feat)
+void perf_header__clear_feat(struct perf_header *header, int feat)
 {
-       clear_bit(feat, self->adds_features);
+       clear_bit(feat, header->adds_features);
 }
 
-bool perf_header__has_feat(const struct perf_header *self, int feat)
+bool perf_header__has_feat(const struct perf_header *header, int feat)
 {
-       return test_bit(feat, self->adds_features);
+       return test_bit(feat, header->adds_features);
 }
 
 static int do_write(int fd, const void *buf, size_t size)
@@ -228,22 +147,22 @@ static int __dsos__write_buildid_table(struct list_head *head, pid_t pid,
        return 0;
 }
 
-static int machine__write_buildid_table(struct machine *self, int fd)
+static int machine__write_buildid_table(struct machine *machine, int fd)
 {
        int err;
        u16 kmisc = PERF_RECORD_MISC_KERNEL,
            umisc = PERF_RECORD_MISC_USER;
 
-       if (!machine__is_host(self)) {
+       if (!machine__is_host(machine)) {
                kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
                umisc = PERF_RECORD_MISC_GUEST_USER;
        }
 
-       err = __dsos__write_buildid_table(&self->kernel_dsos, self->pid,
+       err = __dsos__write_buildid_table(&machine->kernel_dsos, machine->pid,
                                          kmisc, fd);
        if (err == 0)
-               err = __dsos__write_buildid_table(&self->user_dsos,
-                                                 self->pid, umisc, fd);
+               err = __dsos__write_buildid_table(&machine->user_dsos,
+                                                 machine->pid, umisc, fd);
        return err;
 }
 
@@ -270,11 +189,15 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
                          const char *name, bool is_kallsyms)
 {
        const size_t size = PATH_MAX;
-       char *realname = realpath(name, NULL),
-            *filename = malloc(size),
+       char *realname, *filename = malloc(size),
             *linkname = malloc(size), *targetname;
        int len, err = -1;
 
+       if (is_kallsyms)
+               realname = (char *)name;
+       else
+               realname = realpath(name, NULL);
+
        if (realname == NULL || filename == NULL || linkname == NULL)
                goto out_free;
 
@@ -306,7 +229,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
        if (symlink(targetname, linkname) == 0)
                err = 0;
 out_free:
-       free(realname);
+       if (!is_kallsyms)
+               free(realname);
        free(filename);
        free(linkname);
        return err;
@@ -361,12 +285,12 @@ out_free:
        return err;
 }
 
-static int dso__cache_build_id(struct dso *self, const char *debugdir)
+static int dso__cache_build_id(struct dso *dso, const char *debugdir)
 {
-       bool is_kallsyms = self->kernel && self->long_name[0] != '/';
+       bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
 
-       return build_id_cache__add_b(self->build_id, sizeof(self->build_id),
-                                    self->long_name, debugdir, is_kallsyms);
+       return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id),
+                                    dso->long_name, debugdir, is_kallsyms);
 }
 
 static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
@@ -381,14 +305,14 @@ static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
        return err;
 }
 
-static int machine__cache_build_ids(struct machine *self, const char *debugdir)
+static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
 {
-       int ret = __dsos__cache_build_ids(&self->kernel_dsos, debugdir);
-       ret |= __dsos__cache_build_ids(&self->user_dsos, debugdir);
+       int ret = __dsos__cache_build_ids(&machine->kernel_dsos, debugdir);
+       ret |= __dsos__cache_build_ids(&machine->user_dsos, debugdir);
        return ret;
 }
 
-static int perf_session__cache_build_ids(struct perf_session *self)
+static int perf_session__cache_build_ids(struct perf_session *session)
 {
        struct rb_node *nd;
        int ret;
@@ -399,28 +323,28 @@ static int perf_session__cache_build_ids(struct perf_session *self)
        if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
                return -1;
 
-       ret = machine__cache_build_ids(&self->host_machine, debugdir);
+       ret = machine__cache_build_ids(&session->host_machine, debugdir);
 
-       for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) {
+       for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
                struct machine *pos = rb_entry(nd, struct machine, rb_node);
                ret |= machine__cache_build_ids(pos, debugdir);
        }
        return ret ? -1 : 0;
 }
 
-static bool machine__read_build_ids(struct machine *self, bool with_hits)
+static bool machine__read_build_ids(struct machine *machine, bool with_hits)
 {
-       bool ret = __dsos__read_build_ids(&self->kernel_dsos, with_hits);
-       ret |= __dsos__read_build_ids(&self->user_dsos, with_hits);
+       bool ret = __dsos__read_build_ids(&machine->kernel_dsos, with_hits);
+       ret |= __dsos__read_build_ids(&machine->user_dsos, with_hits);
        return ret;
 }
 
-static bool perf_session__read_build_ids(struct perf_session *self, bool with_hits)
+static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
 {
        struct rb_node *nd;
-       bool ret = machine__read_build_ids(&self->host_machine, with_hits);
+       bool ret = machine__read_build_ids(&session->host_machine, with_hits);
 
-       for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) {
+       for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
                struct machine *pos = rb_entry(nd, struct machine, rb_node);
                ret |= machine__read_build_ids(pos, with_hits);
        }
@@ -428,7 +352,8 @@ static bool perf_session__read_build_ids(struct perf_session *self, bool with_hi
        return ret;
 }
 
-static int perf_header__adds_write(struct perf_header *self, int fd)
+static int perf_header__adds_write(struct perf_header *header,
+                                  struct perf_evlist *evlist, int fd)
 {
        int nr_sections;
        struct perf_session *session;
@@ -437,13 +362,13 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
        u64 sec_start;
        int idx = 0, err;
 
-       session = container_of(self, struct perf_session, header);
+       session = container_of(header, struct perf_session, header);
 
-       if (perf_header__has_feat(self, HEADER_BUILD_ID &&
+       if (perf_header__has_feat(header, HEADER_BUILD_ID &&
            !perf_session__read_build_ids(session, true)))
-               perf_header__clear_feat(self, HEADER_BUILD_ID);
+               perf_header__clear_feat(header, HEADER_BUILD_ID);
 
-       nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
+       nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS);
        if (!nr_sections)
                return 0;
 
@@ -453,28 +378,28 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
 
        sec_size = sizeof(*feat_sec) * nr_sections;
 
-       sec_start = self->data_offset + self->data_size;
+       sec_start = header->data_offset + header->data_size;
        lseek(fd, sec_start + sec_size, SEEK_SET);
 
-       if (perf_header__has_feat(self, HEADER_TRACE_INFO)) {
+       if (perf_header__has_feat(header, HEADER_TRACE_INFO)) {
                struct perf_file_section *trace_sec;
 
                trace_sec = &feat_sec[idx++];
 
                /* Write trace info */
                trace_sec->offset = lseek(fd, 0, SEEK_CUR);
-               read_tracing_data(fd, &evsel_list);
+               read_tracing_data(fd, &evlist->entries);
                trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
        }
 
-       if (perf_header__has_feat(self, HEADER_BUILD_ID)) {
+       if (perf_header__has_feat(header, HEADER_BUILD_ID)) {
                struct perf_file_section *buildid_sec;
 
                buildid_sec = &feat_sec[idx++];
 
                /* Write build-ids */
                buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
-               err = dsos__write_buildid_table(self, fd);
+               err = dsos__write_buildid_table(header, fd);
                if (err < 0) {
                        pr_debug("failed to write buildid table\n");
                        goto out_free;
@@ -513,32 +438,41 @@ int perf_header__write_pipe(int fd)
        return 0;
 }
 
-int perf_header__write(struct perf_header *self, int fd, bool at_exit)
+int perf_session__write_header(struct perf_session *session,
+                              struct perf_evlist *evlist,
+                              int fd, bool at_exit)
 {
        struct perf_file_header f_header;
        struct perf_file_attr   f_attr;
-       struct perf_header_attr *attr;
-       int i, err;
+       struct perf_header *header = &session->header;
+       struct perf_evsel *attr, *pair = NULL;
+       int err;
 
        lseek(fd, sizeof(f_header), SEEK_SET);
 
-       for (i = 0; i < self->attrs; i++) {
-               attr = self->attr[i];
+       if (session->evlist != evlist)
+               pair = list_entry(session->evlist->entries.next, struct perf_evsel, node);
 
+       list_for_each_entry(attr, &evlist->entries, node) {
                attr->id_offset = lseek(fd, 0, SEEK_CUR);
                err = do_write(fd, attr->id, attr->ids * sizeof(u64));
                if (err < 0) {
+out_err_write:
                        pr_debug("failed to write perf header\n");
                        return err;
                }
+               if (session->evlist != evlist) {
+                       err = do_write(fd, pair->id, pair->ids * sizeof(u64));
+                       if (err < 0)
+                               goto out_err_write;
+                       attr->ids += pair->ids;
+                       pair = list_entry(pair->node.next, struct perf_evsel, node);
+               }
        }
 
+       header->attr_offset = lseek(fd, 0, SEEK_CUR);
 
-       self->attr_offset = lseek(fd, 0, SEEK_CUR);
-
-       for (i = 0; i < self->attrs; i++) {
-               attr = self->attr[i];
-
+       list_for_each_entry(attr, &evlist->entries, node) {
                f_attr = (struct perf_file_attr){
                        .attr = attr->attr,
                        .ids  = {
@@ -553,20 +487,20 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
                }
        }
 
-       self->event_offset = lseek(fd, 0, SEEK_CUR);
-       self->event_size = event_count * sizeof(struct perf_trace_event_type);
+       header->event_offset = lseek(fd, 0, SEEK_CUR);
+       header->event_size = event_count * sizeof(struct perf_trace_event_type);
        if (events) {
-               err = do_write(fd, events, self->event_size);
+               err = do_write(fd, events, header->event_size);
                if (err < 0) {
                        pr_debug("failed to write perf header events\n");
                        return err;
                }
        }
 
-       self->data_offset = lseek(fd, 0, SEEK_CUR);
+       header->data_offset = lseek(fd, 0, SEEK_CUR);
 
        if (at_exit) {
-               err = perf_header__adds_write(self, fd);
+               err = perf_header__adds_write(header, evlist, fd);
                if (err < 0)
                        return err;
        }
@@ -576,20 +510,20 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
                .size      = sizeof(f_header),
                .attr_size = sizeof(f_attr),
                .attrs = {
-                       .offset = self->attr_offset,
-                       .size   = self->attrs * sizeof(f_attr),
+                       .offset = header->attr_offset,
+                       .size   = evlist->nr_entries * sizeof(f_attr),
                },
                .data = {
-                       .offset = self->data_offset,
-                       .size   = self->data_size,
+                       .offset = header->data_offset,
+                       .size   = header->data_size,
                },
                .event_types = {
-                       .offset = self->event_offset,
-                       .size   = self->event_size,
+                       .offset = header->event_offset,
+                       .size   = header->event_size,
                },
        };
 
-       memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features));
+       memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features));
 
        lseek(fd, 0, SEEK_SET);
        err = do_write(fd, &f_header, sizeof(f_header));
@@ -597,26 +531,26 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
                pr_debug("failed to write perf header\n");
                return err;
        }
-       lseek(fd, self->data_offset + self->data_size, SEEK_SET);
+       lseek(fd, header->data_offset + header->data_size, SEEK_SET);
 
-       self->frozen = 1;
+       header->frozen = 1;
        return 0;
 }
 
-static int perf_header__getbuffer64(struct perf_header *self,
+static int perf_header__getbuffer64(struct perf_header *header,
                                    int fd, void *buf, size_t size)
 {
        if (readn(fd, buf, size) <= 0)
                return -1;
 
-       if (self->needs_swap)
+       if (header->needs_swap)
                mem_bswap_64(buf, size);
 
        return 0;
 }
 
-int perf_header__process_sections(struct perf_header *self, int fd,
-                                 int (*process)(struct perf_file_section *self,
+int perf_header__process_sections(struct perf_header *header, int fd,
+                                 int (*process)(struct perf_file_section *section,
                                                 struct perf_header *ph,
                                                 int feat, int fd))
 {
@@ -626,7 +560,7 @@ int perf_header__process_sections(struct perf_header *self, int fd,
        int idx = 0;
        int err = -1, feat = 1;
 
-       nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
+       nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS);
        if (!nr_sections)
                return 0;
 
@@ -636,17 +570,17 @@ int perf_header__process_sections(struct perf_header *self, int fd,
 
        sec_size = sizeof(*feat_sec) * nr_sections;
 
-       lseek(fd, self->data_offset + self->data_size, SEEK_SET);
+       lseek(fd, header->data_offset + header->data_size, SEEK_SET);
 
-       if (perf_header__getbuffer64(self, fd, feat_sec, sec_size))
+       if (perf_header__getbuffer64(header, fd, feat_sec, sec_size))
                goto out_free;
 
        err = 0;
        while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
-               if (perf_header__has_feat(self, feat)) {
+               if (perf_header__has_feat(header, feat)) {
                        struct perf_file_section *sec = &feat_sec[idx++];
 
-                       err = process(sec, self, feat, fd);
+                       err = process(sec, header, feat, fd);
                        if (err < 0)
                                break;
                }
@@ -657,35 +591,35 @@ out_free:
        return err;
 }
 
-int perf_file_header__read(struct perf_file_header *self,
+int perf_file_header__read(struct perf_file_header *header,
                           struct perf_header *ph, int fd)
 {
        lseek(fd, 0, SEEK_SET);
 
-       if (readn(fd, self, sizeof(*self)) <= 0 ||
-           memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
+       if (readn(fd, header, sizeof(*header)) <= 0 ||
+           memcmp(&header->magic, __perf_magic, sizeof(header->magic)))
                return -1;
 
-       if (self->attr_size != sizeof(struct perf_file_attr)) {
-               u64 attr_size = bswap_64(self->attr_size);
+       if (header->attr_size != sizeof(struct perf_file_attr)) {
+               u64 attr_size = bswap_64(header->attr_size);
 
                if (attr_size != sizeof(struct perf_file_attr))
                        return -1;
 
-               mem_bswap_64(self, offsetof(struct perf_file_header,
+               mem_bswap_64(header, offsetof(struct perf_file_header,
                                            adds_features));
                ph->needs_swap = true;
        }
 
-       if (self->size != sizeof(*self)) {
+       if (header->size != sizeof(*header)) {
                /* Support the previous format */
-               if (self->size == offsetof(typeof(*self), adds_features))
-                       bitmap_zero(self->adds_features, HEADER_FEAT_BITS);
+               if (header->size == offsetof(typeof(*header), adds_features))
+                       bitmap_zero(header->adds_features, HEADER_FEAT_BITS);
                else
                        return -1;
        }
 
-       memcpy(&ph->adds_features, &self->adds_features,
+       memcpy(&ph->adds_features, &header->adds_features,
               sizeof(ph->adds_features));
        /*
         * FIXME: hack that assumes that if we need swap the perf.data file
@@ -699,10 +633,10 @@ int perf_file_header__read(struct perf_file_header *self,
                perf_header__set_feat(ph, HEADER_BUILD_ID);
        }
 
-       ph->event_offset = self->event_types.offset;
-       ph->event_size   = self->event_types.size;
-       ph->data_offset  = self->data.offset;
-       ph->data_size    = self->data.size;
+       ph->event_offset = header->event_types.offset;
+       ph->event_size   = header->event_types.size;
+       ph->data_offset  = header->data.offset;
+       ph->data_size    = header->data.size;
        return 0;
 }
 
@@ -761,11 +695,10 @@ out:
        return err;
 }
 
-static int perf_header__read_build_ids(struct perf_header *self,
-                       int input, u64 offset, u64 size)
+static int perf_header__read_build_ids(struct perf_header *header,
+                                      int input, u64 offset, u64 size)
 {
-       struct perf_session *session = container_of(self,
-                       struct perf_session, header);
+       struct perf_session *session = container_of(header, struct perf_session, header);
        struct build_id_event bev;
        char filename[PATH_MAX];
        u64 limit = offset + size;
@@ -777,7 +710,7 @@ static int perf_header__read_build_ids(struct perf_header *self,
                if (read(input, &bev, sizeof(bev)) != sizeof(bev))
                        goto out;
 
-               if (self->needs_swap)
+               if (header->needs_swap)
                        perf_event_header__bswap(&bev.header);
 
                len = bev.header.size - sizeof(bev);
@@ -793,13 +726,13 @@ out:
        return err;
 }
 
-static int perf_file_section__process(struct perf_file_section *self,
+static int perf_file_section__process(struct perf_file_section *section,
                                      struct perf_header *ph,
                                      int feat, int fd)
 {
-       if (lseek(fd, self->offset, SEEK_SET) == (off_t)-1) {
+       if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
                pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
-                         "%d, continuing...\n", self->offset, feat);
+                         "%d, continuing...\n", section->offset, feat);
                return 0;
        }
 
@@ -809,7 +742,7 @@ static int perf_file_section__process(struct perf_file_section *self,
                break;
 
        case HEADER_BUILD_ID:
-               if (perf_header__read_build_ids(ph, fd, self->offset, self->size))
+               if (perf_header__read_build_ids(ph, fd, section->offset, section->size))
                        pr_debug("Failed to read buildids, continuing...\n");
                break;
        default:
@@ -819,21 +752,21 @@ static int perf_file_section__process(struct perf_file_section *self,
        return 0;
 }
 
-static int perf_file_header__read_pipe(struct perf_pipe_file_header *self,
+static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
                                       struct perf_header *ph, int fd,
                                       bool repipe)
 {
-       if (readn(fd, self, sizeof(*self)) <= 0 ||
-           memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
+       if (readn(fd, header, sizeof(*header)) <= 0 ||
+           memcmp(&header->magic, __perf_magic, sizeof(header->magic)))
                return -1;
 
-       if (repipe && do_write(STDOUT_FILENO, self, sizeof(*self)) < 0)
+       if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0)
                return -1;
 
-       if (self->size != sizeof(*self)) {
-               u64 size = bswap_64(self->size);
+       if (header->size != sizeof(*header)) {
+               u64 size = bswap_64(header->size);
 
-               if (size != sizeof(*self))
+               if (size != sizeof(*header))
                        return -1;
 
                ph->needs_swap = true;
@@ -844,10 +777,10 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *self,
 
 static int perf_header__read_pipe(struct perf_session *session, int fd)
 {
-       struct perf_header *self = &session->header;
+       struct perf_header *header = &session->header;
        struct perf_pipe_file_header f_header;
 
-       if (perf_file_header__read_pipe(&f_header, self, fd,
+       if (perf_file_header__read_pipe(&f_header, header, fd,
                                        session->repipe) < 0) {
                pr_debug("incompatible file format\n");
                return -EINVAL;
@@ -858,18 +791,22 @@ static int perf_header__read_pipe(struct perf_session *session, int fd)
        return 0;
 }
 
-int perf_header__read(struct perf_session *session, int fd)
+int perf_session__read_header(struct perf_session *session, int fd)
 {
-       struct perf_header *self = &session->header;
+       struct perf_header *header = &session->header;
        struct perf_file_header f_header;
        struct perf_file_attr   f_attr;
        u64                     f_id;
        int nr_attrs, nr_ids, i, j;
 
+       session->evlist = perf_evlist__new(NULL, NULL);
+       if (session->evlist == NULL)
+               return -ENOMEM;
+
        if (session->fd_pipe)
                return perf_header__read_pipe(session, fd);
 
-       if (perf_file_header__read(&f_header, self, fd) < 0) {
+       if (perf_file_header__read(&f_header, header, fd) < 0) {
                pr_debug("incompatible file format\n");
                return -EINVAL;
        }
@@ -878,33 +815,39 @@ int perf_header__read(struct perf_session *session, int fd)
        lseek(fd, f_header.attrs.offset, SEEK_SET);
 
        for (i = 0; i < nr_attrs; i++) {
-               struct perf_header_attr *attr;
+               struct perf_evsel *evsel;
                off_t tmp;
 
-               if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr)))
+               if (perf_header__getbuffer64(header, fd, &f_attr, sizeof(f_attr)))
                        goto out_errno;
 
                tmp = lseek(fd, 0, SEEK_CUR);
+               evsel = perf_evsel__new(&f_attr.attr, i);
 
-               attr = perf_header_attr__new(&f_attr.attr);
-               if (attr == NULL)
-                        return -ENOMEM;
+               if (evsel == NULL)
+                       goto out_delete_evlist;
+               /*
+                * Do it before so that if perf_evsel__alloc_id fails, this
+                * entry gets purged too at perf_evlist__delete().
+                */
+               perf_evlist__add(session->evlist, evsel);
 
                nr_ids = f_attr.ids.size / sizeof(u64);
+               /*
+                * We don't have the cpu and thread maps on the header, so
+                * for allocating the perf_sample_id table we fake 1 cpu and
+                * hattr->ids threads.
+                */
+               if (perf_evsel__alloc_id(evsel, 1, nr_ids))
+                       goto out_delete_evlist;
+
                lseek(fd, f_attr.ids.offset, SEEK_SET);
 
                for (j = 0; j < nr_ids; j++) {
-                       if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id)))
+                       if (perf_header__getbuffer64(header, fd, &f_id, sizeof(f_id)))
                                goto out_errno;
 
-                       if (perf_header_attr__add_id(attr, f_id) < 0) {
-                               perf_header_attr__delete(attr);
-                               return -ENOMEM;
-                       }
-               }
-               if (perf_header__add_attr(self, attr) < 0) {
-                       perf_header_attr__delete(attr);
-                       return -ENOMEM;
+                       perf_evlist__id_add(session->evlist, evsel, 0, j, f_id);
                }
 
                lseek(fd, tmp, SEEK_SET);
@@ -915,93 +858,63 @@ int perf_header__read(struct perf_session *session, int fd)
                events = malloc(f_header.event_types.size);
                if (events == NULL)
                        return -ENOMEM;
-               if (perf_header__getbuffer64(self, fd, events,
+               if (perf_header__getbuffer64(header, fd, events,
                                             f_header.event_types.size))
                        goto out_errno;
                event_count =  f_header.event_types.size / sizeof(struct perf_trace_event_type);
        }
 
-       perf_header__process_sections(self, fd, perf_file_section__process);
+       perf_header__process_sections(header, fd, perf_file_section__process);
 
-       lseek(fd, self->data_offset, SEEK_SET);
+       lseek(fd, header->data_offset, SEEK_SET);
 
-       self->frozen = 1;
+       header->frozen = 1;
        return 0;
 out_errno:
        return -errno;
+
+out_delete_evlist:
+       perf_evlist__delete(session->evlist);
+       session->evlist = NULL;
+       return -ENOMEM;
 }
 
-u64 perf_header__sample_type(struct perf_header *header)
+u64 perf_evlist__sample_type(struct perf_evlist *evlist)
 {
+       struct perf_evsel *pos;
        u64 type = 0;
-       int i;
-
-       for (i = 0; i < header->attrs; i++) {
-               struct perf_header_attr *attr = header->attr[i];
 
+       list_for_each_entry(pos, &evlist->entries, node) {
                if (!type)
-                       type = attr->attr.sample_type;
-               else if (type != attr->attr.sample_type)
+                       type = pos->attr.sample_type;
+               else if (type != pos->attr.sample_type)
                        die("non matching sample_type");
        }
 
        return type;
 }
 
-bool perf_header__sample_id_all(const struct perf_header *header)
+bool perf_evlist__sample_id_all(const struct perf_evlist *evlist)
 {
        bool value = false, first = true;
-       int i;
-
-       for (i = 0; i < header->attrs; i++) {
-               struct perf_header_attr *attr = header->attr[i];
+       struct perf_evsel *pos;
 
+       list_for_each_entry(pos, &evlist->entries, node) {
                if (first) {
-                       value = attr->attr.sample_id_all;
+                       value = pos->attr.sample_id_all;
                        first = false;
-               } else if (value != attr->attr.sample_id_all)
+               } else if (value != pos->attr.sample_id_all)
                        die("non matching sample_id_all");
        }
 
        return value;
 }
 
-struct perf_event_attr *
-perf_header__find_attr(u64 id, struct perf_header *header)
-{
-       int i;
-
-       /*
-        * We set id to -1 if the data file doesn't contain sample
-        * ids. This can happen when the data file contains one type
-        * of event and in that case, the header can still store the
-        * event attribute information. Check for this and avoid
-        * walking through the entire list of ids which may be large.
-        */
-       if (id == -1ULL) {
-               if (header->attrs > 0)
-                       return &header->attr[0]->attr;
-               return NULL;
-       }
-
-       for (i = 0; i < header->attrs; i++) {
-               struct perf_header_attr *attr = header->attr[i];
-               int j;
-
-               for (j = 0; j < attr->ids; j++) {
-                       if (attr->id[j] == id)
-                               return &attr->attr;
-               }
-       }
-
-       return NULL;
-}
-
-int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
-                          event__handler_t process,
-                          struct perf_session *session)
+int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
+                               perf_event__handler_t process,
+                               struct perf_session *session)
 {
-       event_t *ev;
+       union perf_event *ev;
        size_t size;
        int err;
 
@@ -1028,17 +941,15 @@ int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
        return err;
 }
 
-int event__synthesize_attrs(struct perf_header *self, event__handler_t process,
-                           struct perf_session *session)
+int perf_session__synthesize_attrs(struct perf_session *session,
+                                  perf_event__handler_t process)
 {
-       struct perf_header_attr *attr;
-       int i, err = 0;
-
-       for (i = 0; i < self->attrs; i++) {
-               attr = self->attr[i];
+       struct perf_evsel *attr;
+       int err = 0;
 
-               err = event__synthesize_attr(&attr->attr, attr->ids, attr->id,
-                                            process, session);
+       list_for_each_entry(attr, &session->evlist->entries, node) {
+               err = perf_event__synthesize_attr(&attr->attr, attr->ids,
+                                                 attr->id, process, session);
                if (err) {
                        pr_debug("failed to create perf header attribute\n");
                        return err;
@@ -1048,29 +959,39 @@ int event__synthesize_attrs(struct perf_header *self, event__handler_t process,
        return err;
 }
 
-int event__process_attr(event_t *self, struct perf_session *session)
+int perf_event__process_attr(union perf_event *event,
+                            struct perf_session *session)
 {
-       struct perf_header_attr *attr;
        unsigned int i, ids, n_ids;
+       struct perf_evsel *evsel;
+
+       if (session->evlist == NULL) {
+               session->evlist = perf_evlist__new(NULL, NULL);
+               if (session->evlist == NULL)
+                       return -ENOMEM;
+       }
 
-       attr = perf_header_attr__new(&self->attr.attr);
-       if (attr == NULL)
+       evsel = perf_evsel__new(&event->attr.attr,
+                               session->evlist->nr_entries);
+       if (evsel == NULL)
                return -ENOMEM;
 
-       ids = self->header.size;
-       ids -= (void *)&self->attr.id - (void *)self;
+       perf_evlist__add(session->evlist, evsel);
+
+       ids = event->header.size;
+       ids -= (void *)&event->attr.id - (void *)event;
        n_ids = ids / sizeof(u64);
+       /*
+        * We don't have the cpu and thread maps on the header, so
+        * for allocating the perf_sample_id table we fake 1 cpu and
+        * hattr->ids threads.
+        */
+       if (perf_evsel__alloc_id(evsel, 1, n_ids))
+               return -ENOMEM;
 
        for (i = 0; i < n_ids; i++) {
-               if (perf_header_attr__add_id(attr, self->attr.id[i]) < 0) {
-                       perf_header_attr__delete(attr);
-                       return -ENOMEM;
-               }
-       }
-
-       if (perf_header__add_attr(&session->header, attr) < 0) {
-               perf_header_attr__delete(attr);
-               return -ENOMEM;
+               perf_evlist__id_add(session->evlist, evsel, 0, i,
+                                   event->attr.id[i]);
        }
 
        perf_session__update_sample_type(session);
@@ -1078,11 +999,11 @@ int event__process_attr(event_t *self, struct perf_session *session)
        return 0;
 }
 
-int event__synthesize_event_type(u64 event_id, char *name,
-                                event__handler_t process,
-                                struct perf_session *session)
+int perf_event__synthesize_event_type(u64 event_id, char *name,
+                                     perf_event__handler_t process,
+                                     struct perf_session *session)
 {
-       event_t ev;
+       union perf_event ev;
        size_t size = 0;
        int err = 0;
 
@@ -1103,8 +1024,8 @@ int event__synthesize_event_type(u64 event_id, char *name,
        return err;
 }
 
-int event__synthesize_event_types(event__handler_t process,
-                                 struct perf_session *session)
+int perf_event__synthesize_event_types(perf_event__handler_t process,
+                                      struct perf_session *session)
 {
        struct perf_trace_event_type *type;
        int i, err = 0;
@@ -1112,8 +1033,9 @@ int event__synthesize_event_types(event__handler_t process,
        for (i = 0; i < event_count; i++) {
                type = &events[i];
 
-               err = event__synthesize_event_type(type->event_id, type->name,
-                                                  process, session);
+               err = perf_event__synthesize_event_type(type->event_id,
+                                                       type->name, process,
+                                                       session);
                if (err) {
                        pr_debug("failed to create perf header event type\n");
                        return err;
@@ -1123,28 +1045,28 @@ int event__synthesize_event_types(event__handler_t process,
        return err;
 }
 
-int event__process_event_type(event_t *self,
-                             struct perf_session *session __unused)
+int perf_event__process_event_type(union perf_event *event,
+                                  struct perf_session *session __unused)
 {
-       if (perf_header__push_event(self->event_type.event_type.event_id,
-                                   self->event_type.event_type.name) < 0)
+       if (perf_header__push_event(event->event_type.event_type.event_id,
+                                   event->event_type.event_type.name) < 0)
                return -ENOMEM;
 
        return 0;
 }
 
-int event__synthesize_tracing_data(int fd, struct list_head *pattrs,
-                                  event__handler_t process,
+int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
+                                        perf_event__handler_t process,
                                   struct perf_session *session __unused)
 {
-       event_t ev;
+       union perf_event ev;
        ssize_t size = 0, aligned_size = 0, padding;
-       int err = 0;
+       int err __used = 0;
 
        memset(&ev, 0, sizeof(ev));
 
        ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA;
-       size = read_tracing_data_size(fd, pattrs);
+       size = read_tracing_data_size(fd, &evlist->entries);
        if (size <= 0)
                return size;
        aligned_size = ALIGN(size, sizeof(u64));
@@ -1154,16 +1076,16 @@ int event__synthesize_tracing_data(int fd, struct list_head *pattrs,
 
        process(&ev, NULL, session);
 
-       err = read_tracing_data(fd, pattrs);
+       err = read_tracing_data(fd, &evlist->entries);
        write_padded(fd, NULL, 0, padding);
 
        return aligned_size;
 }
 
-int event__process_tracing_data(event_t *self,
-                               struct perf_session *session)
+int perf_event__process_tracing_data(union perf_event *event,
+                                    struct perf_session *session)
 {
-       ssize_t size_read, padding, size = self->tracing_data.size;
+       ssize_t size_read, padding, size = event->tracing_data.size;
        off_t offset = lseek(session->fd, 0, SEEK_CUR);
        char buf[BUFSIZ];
 
@@ -1189,12 +1111,12 @@ int event__process_tracing_data(event_t *self,
        return size_read + padding;
 }
 
-int event__synthesize_build_id(struct dso *pos, u16 misc,
-                              event__handler_t process,
-                              struct machine *machine,
-                              struct perf_session *session)
+int perf_event__synthesize_build_id(struct dso *pos, u16 misc,
+                                   perf_event__handler_t process,
+                                   struct machine *machine,
+                                   struct perf_session *session)
 {
-       event_t ev;
+       union perf_event ev;
        size_t len;
        int err = 0;
 
@@ -1217,11 +1139,11 @@ int event__synthesize_build_id(struct dso *pos, u16 misc,
        return err;
 }
 
-int event__process_build_id(event_t *self,
-                           struct perf_session *session)
+int perf_event__process_build_id(union perf_event *event,
+                                struct perf_session *session)
 {
-       __event_process_build_id(&self->build_id,
-                                self->build_id.filename,
+       __event_process_build_id(&event->build_id,
+                                event->build_id.filename,
                                 session);
        return 0;
 }
index 33f16be..456661d 100644 (file)
@@ -9,13 +9,6 @@
 
 #include <linux/bitmap.h>
 
-struct perf_header_attr {
-       struct perf_event_attr attr;
-       int ids, size;
-       u64 *id;
-       off_t id_offset;
-};
-
 enum {
        HEADER_TRACE_INFO = 1,
        HEADER_BUILD_ID,
@@ -46,14 +39,12 @@ struct perf_pipe_file_header {
 
 struct perf_header;
 
-int perf_file_header__read(struct perf_file_header *self,
+int perf_file_header__read(struct perf_file_header *header,
                           struct perf_header *ph, int fd);
 
 struct perf_header {
        int                     frozen;
-       int                     attrs, size;
        bool                    needs_swap;
-       struct perf_header_attr **attr;
        s64                     attr_offset;
        u64                     data_offset;
        u64                     data_size;
@@ -62,34 +53,25 @@ struct perf_header {
        DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
 };
 
-int perf_header__init(struct perf_header *self);
-void perf_header__exit(struct perf_header *self);
+struct perf_evlist;
 
-int perf_header__read(struct perf_session *session, int fd);
-int perf_header__write(struct perf_header *self, int fd, bool at_exit);
+int perf_session__read_header(struct perf_session *session, int fd);
+int perf_session__write_header(struct perf_session *session,
+                              struct perf_evlist *evlist,
+                              int fd, bool at_exit);
 int perf_header__write_pipe(int fd);
 
-int perf_header__add_attr(struct perf_header *self,
-                         struct perf_header_attr *attr);
-
 int perf_header__push_event(u64 id, const char *name);
 char *perf_header__find_event(u64 id);
 
-struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr);
-void perf_header_attr__delete(struct perf_header_attr *self);
+u64 perf_evlist__sample_type(struct perf_evlist *evlist);
+bool perf_evlist__sample_id_all(const struct perf_evlist *evlist);
+void perf_header__set_feat(struct perf_header *header, int feat);
+void perf_header__clear_feat(struct perf_header *header, int feat);
+bool perf_header__has_feat(const struct perf_header *header, int feat);
 
-int perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
-
-u64 perf_header__sample_type(struct perf_header *header);
-bool perf_header__sample_id_all(const struct perf_header *header);
-struct perf_event_attr *
-perf_header__find_attr(u64 id, struct perf_header *header);
-void perf_header__set_feat(struct perf_header *self, int feat);
-void perf_header__clear_feat(struct perf_header *self, int feat);
-bool perf_header__has_feat(const struct perf_header *self, int feat);
-
-int perf_header__process_sections(struct perf_header *self, int fd,
-                                 int (*process)(struct perf_file_section *self,
+int perf_header__process_sections(struct perf_header *header, int fd,
+                                 int (*process)(struct perf_file_section *section,
                                                 struct perf_header *ph,
                                                 int feat, int fd));
 
@@ -97,32 +79,31 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
                          const char *name, bool is_kallsyms);
 int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
 
-int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
-                          event__handler_t process,
-                          struct perf_session *session);
-int event__synthesize_attrs(struct perf_header *self,
-                           event__handler_t process,
-                           struct perf_session *session);
-int event__process_attr(event_t *self, struct perf_session *session);
-
-int event__synthesize_event_type(u64 event_id, char *name,
-                                event__handler_t process,
-                                struct perf_session *session);
-int event__synthesize_event_types(event__handler_t process,
-                                 struct perf_session *session);
-int event__process_event_type(event_t *self,
-                             struct perf_session *session);
-
-int event__synthesize_tracing_data(int fd, struct list_head *pattrs,
-                                  event__handler_t process,
-                                  struct perf_session *session);
-int event__process_tracing_data(event_t *self,
+int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
+                               perf_event__handler_t process,
                                struct perf_session *session);
+int perf_session__synthesize_attrs(struct perf_session *session,
+                                  perf_event__handler_t process);
+int perf_event__process_attr(union perf_event *event, struct perf_session *session);
+
+int perf_event__synthesize_event_type(u64 event_id, char *name,
+                                     perf_event__handler_t process,
+                                     struct perf_session *session);
+int perf_event__synthesize_event_types(perf_event__handler_t process,
+                                      struct perf_session *session);
+int perf_event__process_event_type(union perf_event *event,
+                                  struct perf_session *session);
 
-int event__synthesize_build_id(struct dso *pos, u16 misc,
-                              event__handler_t process,
-                              struct machine *machine,
-                              struct perf_session *session);
-int event__process_build_id(event_t *self, struct perf_session *session);
-
+int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
+                                       perf_event__handler_t process,
+                                       struct perf_session *session);
+int perf_event__process_tracing_data(union perf_event *event,
+                                    struct perf_session *session);
+
+int perf_event__synthesize_build_id(struct dso *pos, u16 misc,
+                                   perf_event__handler_t process,
+                                   struct machine *machine,
+                                   struct perf_session *session);
+int perf_event__process_build_id(union perf_event *event,
+                                struct perf_session *session);
 #endif /* __PERF_HEADER_H */
index 32f4f1f..627a02e 100644 (file)
@@ -1,3 +1,4 @@
+#include "annotate.h"
 #include "util.h"
 #include "build-id.h"
 #include "hist.h"
@@ -49,6 +50,15 @@ static void hists__calc_col_len(struct hists *self, struct hist_entry *h)
 
        if (h->ms.sym)
                hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen);
+       else {
+               const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
+
+               if (hists__col_len(self, HISTC_DSO) < unresolved_col_width &&
+                   !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
+                   !symbol_conf.dso_list)
+                       hists__set_col_len(self, HISTC_DSO,
+                                          unresolved_col_width);
+       }
 
        len = thread__comm_len(h->thread);
        if (hists__new_col_len(self, HISTC_COMM, len))
@@ -211,7 +221,9 @@ void hist_entry__free(struct hist_entry *he)
  * collapse the histogram
  */
 
-static bool collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
+static bool hists__collapse_insert_entry(struct hists *self,
+                                        struct rb_root *root,
+                                        struct hist_entry *he)
 {
        struct rb_node **p = &root->rb_node;
        struct rb_node *parent = NULL;
@@ -226,8 +238,11 @@ static bool collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
 
                if (!cmp) {
                        iter->period += he->period;
-                       if (symbol_conf.use_callchain)
-                               callchain_merge(iter->callchain, he->callchain);
+                       if (symbol_conf.use_callchain) {
+                               callchain_cursor_reset(&self->callchain_cursor);
+                               callchain_merge(&self->callchain_cursor, iter->callchain,
+                                               he->callchain);
+                       }
                        hist_entry__free(he);
                        return false;
                }
@@ -262,7 +277,7 @@ void hists__collapse_resort(struct hists *self)
                next = rb_next(&n->rb_node);
 
                rb_erase(&n->rb_node, &self->entries);
-               if (collapse__insert_entry(&tmp, n))
+               if (hists__collapse_insert_entry(self, &tmp, n))
                        hists__inc_nr_entries(self, n);
        }
 
@@ -425,7 +440,7 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
                u64 cumul;
 
                child = rb_entry(node, struct callchain_node, rb_node);
-               cumul = cumul_hits(child);
+               cumul = callchain_cumul_hits(child);
                remaining -= cumul;
 
                /*
@@ -585,6 +600,7 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
 {
        struct sort_entry *se;
        u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
+       u64 nr_events;
        const char *sep = symbol_conf.field_sep;
        int ret;
 
@@ -593,6 +609,7 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
 
        if (pair_hists) {
                period = self->pair ? self->pair->period : 0;
+               nr_events = self->pair ? self->pair->nr_events : 0;
                total = pair_hists->stats.total_period;
                period_sys = self->pair ? self->pair->period_sys : 0;
                period_us = self->pair ? self->pair->period_us : 0;
@@ -600,6 +617,7 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
                period_guest_us = self->pair ? self->pair->period_guest_us : 0;
        } else {
                period = self->period;
+               nr_events = self->nr_events;
                total = session_total;
                period_sys = self->period_sys;
                period_us = self->period_us;
@@ -640,9 +658,9 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
 
        if (symbol_conf.show_nr_samples) {
                if (sep)
-                       ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
+                       ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
                else
-                       ret += snprintf(s + ret, size - ret, "%11" PRIu64, period);
+                       ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
        }
 
        if (pair_hists) {
@@ -944,225 +962,14 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread)
        }
 }
 
-static int symbol__alloc_hist(struct symbol *self)
-{
-       struct sym_priv *priv = symbol__priv(self);
-       const int size = (sizeof(*priv->hist) +
-                         (self->end - self->start) * sizeof(u64));
-
-       priv->hist = zalloc(size);
-       return priv->hist == NULL ? -1 : 0;
-}
-
-int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip)
-{
-       unsigned int sym_size, offset;
-       struct symbol *sym = self->ms.sym;
-       struct sym_priv *priv;
-       struct sym_hist *h;
-
-       if (!sym || !self->ms.map)
-               return 0;
-
-       priv = symbol__priv(sym);
-       if (priv->hist == NULL && symbol__alloc_hist(sym) < 0)
-               return -ENOMEM;
-
-       sym_size = sym->end - sym->start;
-       offset = ip - sym->start;
-
-       pr_debug3("%s: ip=%#" PRIx64 "\n", __func__, self->ms.map->unmap_ip(self->ms.map, ip));
-
-       if (offset >= sym_size)
-               return 0;
-
-       h = priv->hist;
-       h->sum++;
-       h->ip[offset]++;
-
-       pr_debug3("%#" PRIx64 " %s: period++ [ip: %#" PRIx64 ", %#" PRIx64
-                 "] => %" PRIu64 "\n", self->ms.sym->start, self->ms.sym->name,
-                 ip, ip - self->ms.sym->start, h->ip[offset]);
-       return 0;
-}
-
-static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize)
-{
-       struct objdump_line *self = malloc(sizeof(*self) + privsize);
-
-       if (self != NULL) {
-               self->offset = offset;
-               self->line = line;
-       }
-
-       return self;
-}
-
-void objdump_line__free(struct objdump_line *self)
-{
-       free(self->line);
-       free(self);
-}
-
-static void objdump__add_line(struct list_head *head, struct objdump_line *line)
-{
-       list_add_tail(&line->node, head);
-}
-
-struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
-                                              struct objdump_line *pos)
-{
-       list_for_each_entry_continue(pos, head, node)
-               if (pos->offset >= 0)
-                       return pos;
-
-       return NULL;
-}
-
-static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file,
-                                         struct list_head *head, size_t privsize)
+int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
 {
-       struct symbol *sym = self->ms.sym;
-       struct objdump_line *objdump_line;
-       char *line = NULL, *tmp, *tmp2, *c;
-       size_t line_len;
-       s64 line_ip, offset = -1;
-
-       if (getline(&line, &line_len, file) < 0)
-               return -1;
-
-       if (!line)
-               return -1;
-
-       while (line_len != 0 && isspace(line[line_len - 1]))
-               line[--line_len] = '\0';
-
-       c = strchr(line, '\n');
-       if (c)
-               *c = 0;
-
-       line_ip = -1;
-
-       /*
-        * Strip leading spaces:
-        */
-       tmp = line;
-       while (*tmp) {
-               if (*tmp != ' ')
-                       break;
-               tmp++;
-       }
-
-       if (*tmp) {
-               /*
-                * Parse hexa addresses followed by ':'
-                */
-               line_ip = strtoull(tmp, &tmp2, 16);
-               if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
-                       line_ip = -1;
-       }
-
-       if (line_ip != -1) {
-               u64 start = map__rip_2objdump(self->ms.map, sym->start),
-                   end = map__rip_2objdump(self->ms.map, sym->end);
-
-               offset = line_ip - start;
-               if (offset < 0 || (u64)line_ip > end)
-                       offset = -1;
-       }
-
-       objdump_line = objdump_line__new(offset, line, privsize);
-       if (objdump_line == NULL) {
-               free(line);
-               return -1;
-       }
-       objdump__add_line(head, objdump_line);
-
-       return 0;
+       return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
 }
 
-int hist_entry__annotate(struct hist_entry *self, struct list_head *head,
-                        size_t privsize)
+int hist_entry__annotate(struct hist_entry *he, size_t privsize)
 {
-       struct symbol *sym = self->ms.sym;
-       struct map *map = self->ms.map;
-       struct dso *dso = map->dso;
-       char *filename = dso__build_id_filename(dso, NULL, 0);
-       bool free_filename = true;
-       char command[PATH_MAX * 2];
-       FILE *file;
-       int err = 0;
-       u64 len;
-       char symfs_filename[PATH_MAX];
-
-       if (filename) {
-               snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
-                        symbol_conf.symfs, filename);
-       }
-
-       if (filename == NULL) {
-               if (dso->has_build_id) {
-                       pr_err("Can't annotate %s: not enough memory\n",
-                              sym->name);
-                       return -ENOMEM;
-               }
-               goto fallback;
-       } else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
-                  strstr(command, "[kernel.kallsyms]") ||
-                  access(symfs_filename, R_OK)) {
-               free(filename);
-fallback:
-               /*
-                * If we don't have build-ids or the build-id file isn't in the
-                * cache, or is just a kallsyms file, well, lets hope that this
-                * DSO is the same as when 'perf record' ran.
-                */
-               filename = dso->long_name;
-               snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
-                        symbol_conf.symfs, filename);
-               free_filename = false;
-       }
-
-       if (dso->origin == DSO__ORIG_KERNEL) {
-               if (dso->annotate_warned)
-                       goto out_free_filename;
-               err = -ENOENT;
-               dso->annotate_warned = 1;
-               pr_err("Can't annotate %s: No vmlinux file was found in the "
-                      "path\n", sym->name);
-               goto out_free_filename;
-       }
-
-       pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
-                filename, sym->name, map->unmap_ip(map, sym->start),
-                map->unmap_ip(map, sym->end));
-
-       len = sym->end - sym->start;
-
-       pr_debug("annotating [%p] %30s : [%p] %30s\n",
-                dso, dso->long_name, sym, sym->name);
-
-       snprintf(command, sizeof(command),
-                "objdump --start-address=0x%016" PRIx64 " --stop-address=0x%016" PRIx64 " -dS -C %s|grep -v %s|expand",
-                map__rip_2objdump(map, sym->start),
-                map__rip_2objdump(map, sym->end),
-                symfs_filename, filename);
-
-       pr_debug("Executing: %s\n", command);
-
-       file = popen(command, "r");
-       if (!file)
-               goto out_free_filename;
-
-       while (!feof(file))
-               if (hist_entry__parse_objdump_line(self, file, head, privsize) < 0)
-                       break;
-
-       pclose(file);
-out_free_filename:
-       if (free_filename)
-               free(filename);
-       return err;
+       return symbol__annotate(he->ms.sym, he->ms.map, privsize);
 }
 
 void hists__inc_nr_events(struct hists *self, u32 type)
@@ -1177,8 +984,12 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
        size_t ret = 0;
 
        for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
-               const char *name = event__get_event_name(i);
+               const char *name;
+
+               if (self->stats.nr_events[i] == 0)
+                       continue;
 
+               name = perf_event__name(i);
                if (!strcmp(name, "UNKNOWN"))
                        continue;
 
index ee78985..cb6858a 100644 (file)
@@ -9,33 +9,6 @@ extern struct callchain_param callchain_param;
 struct hist_entry;
 struct addr_location;
 struct symbol;
-struct rb_root;
-
-struct objdump_line {
-       struct list_head node;
-       s64              offset;
-       char             *line;
-};
-
-void objdump_line__free(struct objdump_line *self);
-struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
-                                              struct objdump_line *pos);
-
-struct sym_hist {
-       u64             sum;
-       u64             ip[0];
-};
-
-struct sym_ext {
-       struct rb_node  node;
-       double          percent;
-       char            *path;
-};
-
-struct sym_priv {
-       struct sym_hist *hist;
-       struct sym_ext  *ext;
-};
 
 /*
  * The kernel collects the number of events it couldn't send in a stretch and
@@ -69,14 +42,13 @@ enum hist_column {
 };
 
 struct hists {
-       struct rb_node          rb_node;
        struct rb_root          entries;
        u64                     nr_entries;
        struct events_stats     stats;
-       u64                     config;
        u64                     event_stream;
-       u32                     type;
        u16                     col_len[HISTC_NR_COLS];
+       /* Best would be to reuse the session callchain cursor */
+       struct callchain_cursor callchain_cursor;
 };
 
 struct hist_entry *__hists__add_entry(struct hists *self,
@@ -102,9 +74,8 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp);
 size_t hists__fprintf(struct hists *self, struct hists *pair,
                      bool show_displacement, FILE *fp);
 
-int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip);
-int hist_entry__annotate(struct hist_entry *self, struct list_head *head,
-                        size_t privsize);
+int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr);
+int hist_entry__annotate(struct hist_entry *self, size_t privsize);
 
 void hists__filter_by_dso(struct hists *self, const struct dso *dso);
 void hists__filter_by_thread(struct hists *self, const struct thread *thread);
@@ -113,21 +84,18 @@ u16 hists__col_len(struct hists *self, enum hist_column col);
 void hists__set_col_len(struct hists *self, enum hist_column col, u16 len);
 bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len);
 
-#ifdef NO_NEWT_SUPPORT
-static inline int hists__browse(struct hists *self __used,
-                               const char *helpline __used,
-                               const char *ev_name __used)
-{
-       return 0;
-}
+struct perf_evlist;
 
-static inline int hists__tui_browse_tree(struct rb_root *self __used,
-                                        const char *help __used)
+#ifdef NO_NEWT_SUPPORT
+static inline
+int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used,
+                                 const char *help __used)
 {
        return 0;
 }
 
-static inline int hist_entry__tui_annotate(struct hist_entry *self __used)
+static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
+                                          int evidx __used)
 {
        return 0;
 }
@@ -135,14 +103,12 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used)
 #define KEY_RIGHT -2
 #else
 #include <newt.h>
-int hists__browse(struct hists *self, const char *helpline,
-                 const char *ev_name);
-int hist_entry__tui_annotate(struct hist_entry *self);
+int hist_entry__tui_annotate(struct hist_entry *self, int evidx);
 
 #define KEY_LEFT NEWT_KEY_LEFT
 #define KEY_RIGHT NEWT_KEY_RIGHT
 
-int hists__tui_browse_tree(struct rb_root *self, const char *help);
+int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help);
 #endif
 
 unsigned int hists__sort_list_width(struct hists *self);
index f5ca26e..356c7e4 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/kernel.h>
 #include "../../../../include/linux/list.h"
 
 #ifndef PERF_LIST_H
index 135f69b..54a7e26 100644 (file)
@@ -1,6 +1,7 @@
 #include "../../../include/linux/hw_breakpoint.h"
 #include "util.h"
 #include "../perf.h"
+#include "evlist.h"
 #include "evsel.h"
 #include "parse-options.h"
 #include "parse-events.h"
 #include "header.h"
 #include "debugfs.h"
 
-int                            nr_counters;
-
-LIST_HEAD(evsel_list);
-
 struct event_symbol {
        u8              type;
        u64             config;
@@ -271,6 +268,9 @@ const char *event_name(struct perf_evsel *evsel)
        u64 config = evsel->attr.config;
        int type = evsel->attr.type;
 
+       if (evsel->name)
+               return evsel->name;
+
        return __event_name(type, config);
 }
 
@@ -449,8 +449,8 @@ parse_single_tracepoint_event(char *sys_name,
 /* sys + ':' + event + ':' + flags*/
 #define MAX_EVOPT_LEN  (MAX_EVENT_LENGTH * 2 + 2 + 128)
 static enum event_result
-parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp,
-                               char *flags)
+parse_multiple_tracepoint_event(const struct option *opt, char *sys_name,
+                               const char *evt_exp, char *flags)
 {
        char evt_path[MAXPATHLEN];
        struct dirent *evt_ent;
@@ -483,15 +483,16 @@ parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp,
                if (len < 0)
                        return EVT_FAILED;
 
-               if (parse_events(NULL, event_opt, 0))
+               if (parse_events(opt, event_opt, 0))
                        return EVT_FAILED;
        }
 
        return EVT_HANDLED_ALL;
 }
 
-static enum event_result parse_tracepoint_event(const char **strp,
-                                   struct perf_event_attr *attr)
+static enum event_result
+parse_tracepoint_event(const struct option *opt, const char **strp,
+                      struct perf_event_attr *attr)
 {
        const char *evt_name;
        char *flags = NULL, *comma_loc;
@@ -530,7 +531,7 @@ static enum event_result parse_tracepoint_event(const char **strp,
                return EVT_FAILED;
        if (strpbrk(evt_name, "*?")) {
                *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */
-               return parse_multiple_tracepoint_event(sys_name, evt_name,
+               return parse_multiple_tracepoint_event(opt, sys_name, evt_name,
                                                       flags);
        } else {
                return parse_single_tracepoint_event(sys_name, evt_name,
@@ -740,11 +741,12 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
  * Symbolic names are (almost) exactly matched.
  */
 static enum event_result
-parse_event_symbols(const char **str, struct perf_event_attr *attr)
+parse_event_symbols(const struct option *opt, const char **str,
+                   struct perf_event_attr *attr)
 {
        enum event_result ret;
 
-       ret = parse_tracepoint_event(str, attr);
+       ret = parse_tracepoint_event(opt, str, attr);
        if (ret != EVT_FAILED)
                goto modifier;
 
@@ -778,14 +780,17 @@ modifier:
        return ret;
 }
 
-int parse_events(const struct option *opt __used, const char *str, int unset __used)
+int parse_events(const struct option *opt, const char *str, int unset __used)
 {
+       struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
        struct perf_event_attr attr;
        enum event_result ret;
+       const char *ostr;
 
        for (;;) {
+               ostr = str;
                memset(&attr, 0, sizeof(attr));
-               ret = parse_event_symbols(&str, &attr);
+               ret = parse_event_symbols(opt, &str, &attr);
                if (ret == EVT_FAILED)
                        return -1;
 
@@ -794,12 +799,15 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
 
                if (ret != EVT_HANDLED_ALL) {
                        struct perf_evsel *evsel;
-                       evsel = perf_evsel__new(&attr,
-                                               nr_counters);
+                       evsel = perf_evsel__new(&attr, evlist->nr_entries);
                        if (evsel == NULL)
                                return -1;
-                       list_add_tail(&evsel->node, &evsel_list);
-                       ++nr_counters;
+                       perf_evlist__add(evlist, evsel);
+
+                       evsel->name = calloc(str - ostr + 1, 1);
+                       if (!evsel->name)
+                               return -1;
+                       strncpy(evsel->name, ostr, str - ostr);
                }
 
                if (*str == 0)
@@ -813,13 +821,14 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
        return 0;
 }
 
-int parse_filter(const struct option *opt __used, const char *str,
+int parse_filter(const struct option *opt, const char *str,
                 int unset __used)
 {
+       struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
        struct perf_evsel *last = NULL;
 
-       if (!list_empty(&evsel_list))
-               last = list_entry(evsel_list.prev, struct perf_evsel, node);
+       if (evlist->nr_entries > 0)
+               last = list_entry(evlist->entries.prev, struct perf_evsel, node);
 
        if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) {
                fprintf(stderr,
@@ -849,7 +858,7 @@ static const char * const event_type_descriptors[] = {
  * Print the events from <debugfs_mount_point>/tracing/events
  */
 
-static void print_tracepoint_events(void)
+void print_tracepoint_events(const char *subsys_glob, const char *event_glob)
 {
        DIR *sys_dir, *evt_dir;
        struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
@@ -864,6 +873,9 @@ static void print_tracepoint_events(void)
                return;
 
        for_each_subsystem(sys_dir, sys_dirent, sys_next) {
+               if (subsys_glob != NULL && 
+                   !strglobmatch(sys_dirent.d_name, subsys_glob))
+                       continue;
 
                snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path,
                         sys_dirent.d_name);
@@ -872,6 +884,10 @@ static void print_tracepoint_events(void)
                        continue;
 
                for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
+                       if (event_glob != NULL && 
+                           !strglobmatch(evt_dirent.d_name, event_glob))
+                               continue;
+
                        snprintf(evt_path, MAXPATHLEN, "%s:%s",
                                 sys_dirent.d_name, evt_dirent.d_name);
                        printf("  %-42s [%s]\n", evt_path,
@@ -923,13 +939,61 @@ int is_valid_tracepoint(const char *event_string)
        return 0;
 }
 
+void print_events_type(u8 type)
+{
+       struct event_symbol *syms = event_symbols;
+       unsigned int i;
+       char name[64];
+
+       for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
+               if (type != syms->type)
+                       continue;
+
+               if (strlen(syms->alias))
+                       snprintf(name, sizeof(name),  "%s OR %s",
+                                syms->symbol, syms->alias);
+               else
+                       snprintf(name, sizeof(name), "%s", syms->symbol);
+
+               printf("  %-42s [%s]\n", name,
+                       event_type_descriptors[type]);
+       }
+}
+
+int print_hwcache_events(const char *event_glob)
+{
+       unsigned int type, op, i, printed = 0;
+
+       for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
+               for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
+                       /* skip invalid cache type */
+                       if (!is_cache_op_valid(type, op))
+                               continue;
+
+                       for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
+                               char *name = event_cache_name(type, op, i);
+
+                               if (event_glob != NULL && 
+                                   !strglobmatch(name, event_glob))
+                                       continue;
+
+                               printf("  %-42s [%s]\n", name,
+                                       event_type_descriptors[PERF_TYPE_HW_CACHE]);
+                               ++printed;
+                       }
+               }
+       }
+
+       return printed;
+}
+
 /*
  * Print the help text for the event symbols:
  */
-void print_events(void)
+void print_events(const char *event_glob)
 {
        struct event_symbol *syms = event_symbols;
-       unsigned int i, type, op, prev_type = -1;
+       unsigned int i, type, prev_type = -1, printed = 0, ntypes_printed = 0;
        char name[40];
 
        printf("\n");
@@ -938,8 +1002,16 @@ void print_events(void)
        for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
                type = syms->type;
 
-               if (type != prev_type)
+               if (type != prev_type && printed) {
                        printf("\n");
+                       printed = 0;
+                       ntypes_printed++;
+               }
+
+               if (event_glob != NULL && 
+                   !(strglobmatch(syms->symbol, event_glob) ||
+                     (syms->alias && strglobmatch(syms->alias, event_glob))))
+                       continue;
 
                if (strlen(syms->alias))
                        sprintf(name, "%s OR %s", syms->symbol, syms->alias);
@@ -949,22 +1021,17 @@ void print_events(void)
                        event_type_descriptors[type]);
 
                prev_type = type;
+               ++printed;
        }
 
-       printf("\n");
-       for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
-               for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
-                       /* skip invalid cache type */
-                       if (!is_cache_op_valid(type, op))
-                               continue;
-
-                       for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
-                               printf("  %-42s [%s]\n",
-                                       event_cache_name(type, op, i),
-                                       event_type_descriptors[PERF_TYPE_HW_CACHE]);
-                       }
-               }
+       if (ntypes_printed) {
+               printed = 0;
+               printf("\n");
        }
+       print_hwcache_events(event_glob);
+
+       if (event_glob != NULL)
+               return;
 
        printf("\n");
        printf("  %-42s [%s]\n",
@@ -977,37 +1044,7 @@ void print_events(void)
                        event_type_descriptors[PERF_TYPE_BREAKPOINT]);
        printf("\n");
 
-       print_tracepoint_events();
+       print_tracepoint_events(NULL, NULL);
 
        exit(129);
 }
-
-int perf_evsel_list__create_default(void)
-{
-       struct perf_evsel *evsel;
-       struct perf_event_attr attr;
-
-       memset(&attr, 0, sizeof(attr));
-       attr.type = PERF_TYPE_HARDWARE;
-       attr.config = PERF_COUNT_HW_CPU_CYCLES;
-
-       evsel = perf_evsel__new(&attr, 0);
-
-       if (evsel == NULL)
-               return -ENOMEM;
-
-       list_add(&evsel->node, &evsel_list);
-       ++nr_counters;
-       return 0;
-}
-
-void perf_evsel_list__delete(void)
-{
-       struct perf_evsel *pos, *n;
-
-       list_for_each_entry_safe(pos, n, &evsel_list, node) {
-               list_del_init(&pos->node);
-               perf_evsel__delete(pos);
-       }
-       nr_counters = 0;
-}
index 458e3ec..212f88e 100644 (file)
@@ -9,11 +9,6 @@
 struct list_head;
 struct perf_evsel;
 
-extern struct list_head evsel_list;
-
-int perf_evsel_list__create_default(void);
-void perf_evsel_list__delete(void);
-
 struct option;
 
 struct tracepoint_path {
@@ -25,8 +20,6 @@ struct tracepoint_path {
 extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
 extern bool have_tracepoints(struct list_head *evlist);
 
-extern int                     nr_counters;
-
 const char *event_name(struct perf_evsel *event);
 extern const char *__event_name(int type, u64 config);
 
@@ -35,7 +28,10 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
 
 #define EVENTS_HELP_MAX (128*1024)
 
-extern void print_events(void);
+void print_events(const char *event_glob);
+void print_events_type(u8 type);
+void print_tracepoint_events(const char *subsys_glob, const char *event_glob);
+int print_hwcache_events(const char *event_glob);
 extern int is_valid_tracepoint(const char *event_string);
 
 extern char debugfs_path[];
index 6e29d9c..5ddee66 100644 (file)
@@ -31,6 +31,7 @@
 #include <string.h>
 #include <stdarg.h>
 #include <limits.h>
+#include <elf.h>
 
 #undef _GNU_SOURCE
 #include "util.h"
@@ -111,7 +112,25 @@ static struct symbol *__find_kernel_function_by_name(const char *name,
                                                     NULL);
 }
 
-const char *kernel_get_module_path(const char *module)
+static struct map *kernel_get_module_map(const char *module)
+{
+       struct rb_node *nd;
+       struct map_groups *grp = &machine.kmaps;
+
+       if (!module)
+               module = "kernel";
+
+       for (nd = rb_first(&grp->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) {
+               struct map *pos = rb_entry(nd, struct map, rb_node);
+               if (strncmp(pos->dso->short_name + 1, module,
+                           pos->dso->short_name_len - 2) == 0) {
+                       return pos;
+               }
+       }
+       return NULL;
+}
+
+static struct dso *kernel_get_module_dso(const char *module)
 {
        struct dso *dso;
        struct map *map;
@@ -141,7 +160,13 @@ const char *kernel_get_module_path(const char *module)
                }
        }
 found:
-       return dso->long_name;
+       return dso;
+}
+
+const char *kernel_get_module_path(const char *module)
+{
+       struct dso *dso = kernel_get_module_dso(module);
+       return (dso) ? dso->long_name : NULL;
 }
 
 #ifdef DWARF_SUPPORT
@@ -384,7 +409,7 @@ int show_line_range(struct line_range *lr, const char *module)
        setup_pager();
 
        if (lr->function)
-               fprintf(stdout, "<%s:%d>\n", lr->function,
+               fprintf(stdout, "<%s@%s:%d>\n", lr->function, lr->path,
                        lr->start - lr->offset);
        else
                fprintf(stdout, "<%s:%d>\n", lr->path, lr->start);
@@ -426,12 +451,14 @@ end:
 }
 
 static int show_available_vars_at(int fd, struct perf_probe_event *pev,
-                                 int max_vls, bool externs)
+                                 int max_vls, struct strfilter *_filter,
+                                 bool externs)
 {
        char *buf;
-       int ret, i;
+       int ret, i, nvars;
        struct str_node *node;
        struct variable_list *vls = NULL, *vl;
+       const char *var;
 
        buf = synthesize_perf_probe_point(&pev->point);
        if (!buf)
@@ -439,36 +466,45 @@ static int show_available_vars_at(int fd, struct perf_probe_event *pev,
        pr_debug("Searching variables at %s\n", buf);
 
        ret = find_available_vars_at(fd, pev, &vls, max_vls, externs);
-       if (ret > 0) {
-               /* Some variables were found */
-               fprintf(stdout, "Available variables at %s\n", buf);
-               for (i = 0; i < ret; i++) {
-                       vl = &vls[i];
-                       /*
-                        * A probe point might be converted to
-                        * several trace points.
-                        */
-                       fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
-                               vl->point.offset);
-                       free(vl->point.symbol);
-                       if (vl->vars) {
-                               strlist__for_each(node, vl->vars)
+       if (ret <= 0) {
+               pr_err("Failed to find variables at %s (%d)\n", buf, ret);
+               goto end;
+       }
+       /* Some variables are found */
+       fprintf(stdout, "Available variables at %s\n", buf);
+       for (i = 0; i < ret; i++) {
+               vl = &vls[i];
+               /*
+                * A probe point might be converted to
+                * several trace points.
+                */
+               fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
+                       vl->point.offset);
+               free(vl->point.symbol);
+               nvars = 0;
+               if (vl->vars) {
+                       strlist__for_each(node, vl->vars) {
+                               var = strchr(node->s, '\t') + 1;
+                               if (strfilter__compare(_filter, var)) {
                                        fprintf(stdout, "\t\t%s\n", node->s);
-                               strlist__delete(vl->vars);
-                       } else
-                               fprintf(stdout, "(No variables)\n");
+                                       nvars++;
+                               }
+                       }
+                       strlist__delete(vl->vars);
                }
-               free(vls);
-       } else
-               pr_err("Failed to find variables at %s (%d)\n", buf, ret);
-
+               if (nvars == 0)
+                       fprintf(stdout, "\t\t(No matched variables)\n");
+       }
+       free(vls);
+end:
        free(buf);
        return ret;
 }
 
 /* Show available variables on given probe point */
 int show_available_vars(struct perf_probe_event *pevs, int npevs,
-                       int max_vls, const char *module, bool externs)
+                       int max_vls, const char *module,
+                       struct strfilter *_filter, bool externs)
 {
        int i, fd, ret = 0;
 
@@ -485,7 +521,8 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
        setup_pager();
 
        for (i = 0; i < npevs && ret >= 0; i++)
-               ret = show_available_vars_at(fd, &pevs[i], max_vls, externs);
+               ret = show_available_vars_at(fd, &pevs[i], max_vls, _filter,
+                                            externs);
 
        close(fd);
        return ret;
@@ -531,7 +568,9 @@ int show_line_range(struct line_range *lr __unused, const char *module __unused)
 
 int show_available_vars(struct perf_probe_event *pevs __unused,
                        int npevs __unused, int max_vls __unused,
-                       const char *module __unused, bool externs __unused)
+                       const char *module __unused,
+                       struct strfilter *filter __unused,
+                       bool externs __unused)
 {
        pr_warning("Debuginfo-analysis is not supported.\n");
        return -ENOSYS;
@@ -556,11 +595,11 @@ static int parse_line_num(char **ptr, int *val, const char *what)
  * The line range syntax is described by:
  *
  *         SRC[:SLN[+NUM|-ELN]]
- *         FNC[:SLN[+NUM|-ELN]]
+ *         FNC[@SRC][:SLN[+NUM|-ELN]]
  */
 int parse_line_range_desc(const char *arg, struct line_range *lr)
 {
-       char *range, *name = strdup(arg);
+       char *range, *file, *name = strdup(arg);
        int err;
 
        if (!name)
@@ -610,7 +649,16 @@ int parse_line_range_desc(const char *arg, struct line_range *lr)
                }
        }
 
-       if (strchr(name, '.'))
+       file = strchr(name, '@');
+       if (file) {
+               *file = '\0';
+               lr->file = strdup(++file);
+               if (lr->file == NULL) {
+                       err = -ENOMEM;
+                       goto err;
+               }
+               lr->function = name;
+       } else if (strchr(name, '.'))
                lr->file = name;
        else
                lr->function = name;
@@ -1784,9 +1832,12 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
        }
 
        /* Loop 2: add all events */
-       for (i = 0; i < npevs && ret >= 0; i++)
+       for (i = 0; i < npevs; i++) {
                ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs,
                                                pkgs[i].ntevs, force_add);
+               if (ret < 0)
+                       break;
+       }
 end:
        /* Loop 3: cleanup and free trace events  */
        for (i = 0; i < npevs; i++) {
@@ -1912,4 +1963,46 @@ int del_perf_probe_events(struct strlist *dellist)
 
        return ret;
 }
+/* TODO: don't use a global variable for filter ... */
+static struct strfilter *available_func_filter;
+
+/*
+ * If a symbol corresponds to a function with global binding and
+ * matches filter return 0. For all others return 1.
+ */
+static int filter_available_functions(struct map *map __unused,
+                                     struct symbol *sym)
+{
+       if (sym->binding == STB_GLOBAL &&
+           strfilter__compare(available_func_filter, sym->name))
+               return 0;
+       return 1;
+}
+
+int show_available_funcs(const char *module, struct strfilter *_filter)
+{
+       struct map *map;
+       int ret;
+
+       setup_pager();
+
+       ret = init_vmlinux();
+       if (ret < 0)
+               return ret;
 
+       map = kernel_get_module_map(module);
+       if (!map) {
+               pr_err("Failed to find %s map.\n", (module) ? : "kernel");
+               return -EINVAL;
+       }
+       available_func_filter = _filter;
+       if (map__load(map, filter_available_functions)) {
+               pr_err("Failed to load map.\n");
+               return -EINVAL;
+       }
+       if (!dso__sorted_by_name(map->dso, map->type))
+               dso__sort_by_name(map->dso, map->type);
+
+       dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
+       return 0;
+}
index 5accbed..3434fc9 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <stdbool.h>
 #include "strlist.h"
+#include "strfilter.h"
 
 extern bool probe_event_dry_run;
 
@@ -126,7 +127,8 @@ extern int show_perf_probe_events(void);
 extern int show_line_range(struct line_range *lr, const char *module);
 extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
                               int max_probe_points, const char *module,
-                              bool externs);
+                              struct strfilter *filter, bool externs);
+extern int show_available_funcs(const char *module, struct strfilter *filter);
 
 
 /* Maximum index number of event-name postfix */
index ab83b6a..194f9e2 100644 (file)
@@ -33,6 +33,7 @@
 #include <ctype.h>
 #include <dwarf-regs.h>
 
+#include <linux/bitops.h>
 #include "event.h"
 #include "debug.h"
 #include "util.h"
@@ -280,6 +281,19 @@ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
        return name ? (strcmp(tname, name) == 0) : false;
 }
 
+/* Get callsite line number of inline-function instance */
+static int die_get_call_lineno(Dwarf_Die *in_die)
+{
+       Dwarf_Attribute attr;
+       Dwarf_Word ret;
+
+       if (!dwarf_attr(in_die, DW_AT_call_line, &attr))
+               return -ENOENT;
+
+       dwarf_formudata(&attr, &ret);
+       return (int)ret;
+}
+
 /* Get type die */
 static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
 {
@@ -320,13 +334,23 @@ static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
        return vr_die;
 }
 
-static bool die_is_signed_type(Dwarf_Die *tp_die)
+static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name,
+                             Dwarf_Word *result)
 {
        Dwarf_Attribute attr;
+
+       if (dwarf_attr(tp_die, attr_name, &attr) == NULL ||
+           dwarf_formudata(&attr, result) != 0)
+               return -ENOENT;
+
+       return 0;
+}
+
+static bool die_is_signed_type(Dwarf_Die *tp_die)
+{
        Dwarf_Word ret;
 
-       if (dwarf_attr(tp_die, DW_AT_encoding, &attr) == NULL ||
-           dwarf_formudata(&attr, &ret) != 0)
+       if (die_get_attr_udata(tp_die, DW_AT_encoding, &ret))
                return false;
 
        return (ret == DW_ATE_signed_char || ret == DW_ATE_signed ||
@@ -335,11 +359,29 @@ static bool die_is_signed_type(Dwarf_Die *tp_die)
 
 static int die_get_byte_size(Dwarf_Die *tp_die)
 {
-       Dwarf_Attribute attr;
        Dwarf_Word ret;
 
-       if (dwarf_attr(tp_die, DW_AT_byte_size, &attr) == NULL ||
-           dwarf_formudata(&attr, &ret) != 0)
+       if (die_get_attr_udata(tp_die, DW_AT_byte_size, &ret))
+               return 0;
+
+       return (int)ret;
+}
+
+static int die_get_bit_size(Dwarf_Die *tp_die)
+{
+       Dwarf_Word ret;
+
+       if (die_get_attr_udata(tp_die, DW_AT_bit_size, &ret))
+               return 0;
+
+       return (int)ret;
+}
+
+static int die_get_bit_offset(Dwarf_Die *tp_die)
+{
+       Dwarf_Word ret;
+
+       if (die_get_attr_udata(tp_die, DW_AT_bit_offset, &ret))
                return 0;
 
        return (int)ret;
@@ -458,6 +500,151 @@ static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
        return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
 }
 
+/* Walker on lines (Note: line number will not be sorted) */
+typedef int (* line_walk_handler_t) (const char *fname, int lineno,
+                                    Dwarf_Addr addr, void *data);
+
+struct __line_walk_param {
+       const char *fname;
+       line_walk_handler_t handler;
+       void *data;
+       int retval;
+};
+
+static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data)
+{
+       struct __line_walk_param *lw = data;
+       Dwarf_Addr addr;
+       int lineno;
+
+       if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) {
+               lineno = die_get_call_lineno(in_die);
+               if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
+                       lw->retval = lw->handler(lw->fname, lineno, addr,
+                                                lw->data);
+                       if (lw->retval != 0)
+                               return DIE_FIND_CB_FOUND;
+               }
+       }
+       return DIE_FIND_CB_SIBLING;
+}
+
+/* Walk on lines of blocks included in given DIE */
+static int __die_walk_funclines(Dwarf_Die *sp_die,
+                               line_walk_handler_t handler, void *data)
+{
+       struct __line_walk_param lw = {
+               .handler = handler,
+               .data = data,
+               .retval = 0,
+       };
+       Dwarf_Die die_mem;
+       Dwarf_Addr addr;
+       int lineno;
+
+       /* Handle function declaration line */
+       lw.fname = dwarf_decl_file(sp_die);
+       if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
+           dwarf_entrypc(sp_die, &addr) == 0) {
+               lw.retval = handler(lw.fname, lineno, addr, data);
+               if (lw.retval != 0)
+                       goto done;
+       }
+       die_find_child(sp_die, __die_walk_funclines_cb, &lw, &die_mem);
+done:
+       return lw.retval;
+}
+
+static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
+{
+       struct __line_walk_param *lw = data;
+
+       lw->retval = __die_walk_funclines(sp_die, lw->handler, lw->data);
+       if (lw->retval != 0)
+               return DWARF_CB_ABORT;
+
+       return DWARF_CB_OK;
+}
+
+/*
+ * Walk on lines inside given PDIE. If the PDIE is subprogram, walk only on
+ * the lines inside the subprogram, otherwise PDIE must be a CU DIE.
+ */
+static int die_walk_lines(Dwarf_Die *pdie, line_walk_handler_t handler,
+                         void *data)
+{
+       Dwarf_Lines *lines;
+       Dwarf_Line *line;
+       Dwarf_Addr addr;
+       const char *fname;
+       int lineno, ret = 0;
+       Dwarf_Die die_mem, *cu_die;
+       size_t nlines, i;
+
+       /* Get the CU die */
+       if (dwarf_tag(pdie) == DW_TAG_subprogram)
+               cu_die = dwarf_diecu(pdie, &die_mem, NULL, NULL);
+       else
+               cu_die = pdie;
+       if (!cu_die) {
+               pr_debug2("Failed to get CU from subprogram\n");
+               return -EINVAL;
+       }
+
+       /* Get lines list in the CU */
+       if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) {
+               pr_debug2("Failed to get source lines on this CU.\n");
+               return -ENOENT;
+       }
+       pr_debug2("Get %zd lines from this CU\n", nlines);
+
+       /* Walk on the lines on lines list */
+       for (i = 0; i < nlines; i++) {
+               line = dwarf_onesrcline(lines, i);
+               if (line == NULL ||
+                   dwarf_lineno(line, &lineno) != 0 ||
+                   dwarf_lineaddr(line, &addr) != 0) {
+                       pr_debug2("Failed to get line info. "
+                                 "Possible error in debuginfo.\n");
+                       continue;
+               }
+               /* Filter lines based on address */
+               if (pdie != cu_die)
+                       /*
+                        * Address filtering
+                        * The line is included in given function, and
+                        * no inline block includes it.
+                        */
+                       if (!dwarf_haspc(pdie, addr) ||
+                           die_find_inlinefunc(pdie, addr, &die_mem))
+                               continue;
+               /* Get source line */
+               fname = dwarf_linesrc(line, NULL, NULL);
+
+               ret = handler(fname, lineno, addr, data);
+               if (ret != 0)
+                       return ret;
+       }
+
+       /*
+        * Dwarf lines doesn't include function declarations and inlined
+        * subroutines. We have to check functions list or given function.
+        */
+       if (pdie != cu_die)
+               ret = __die_walk_funclines(pdie, handler, data);
+       else {
+               struct __line_walk_param param = {
+                       .handler = handler,
+                       .data = data,
+                       .retval = 0,
+               };
+               dwarf_getfuncs(cu_die, __die_walk_culines_cb, &param, 0);
+               ret = param.retval;
+       }
+
+       return ret;
+}
+
 struct __find_variable_param {
        const char *name;
        Dwarf_Addr addr;
@@ -669,6 +856,8 @@ static_var:
        return 0;
 }
 
+#define BYTES_TO_BITS(nb)      ((nb) * BITS_PER_LONG / sizeof(long))
+
 static int convert_variable_type(Dwarf_Die *vr_die,
                                 struct probe_trace_arg *tvar,
                                 const char *cast)
@@ -685,6 +874,14 @@ static int convert_variable_type(Dwarf_Die *vr_die,
                return (tvar->type == NULL) ? -ENOMEM : 0;
        }
 
+       if (die_get_bit_size(vr_die) != 0) {
+               /* This is a bitfield */
+               ret = snprintf(buf, 16, "b%d@%d/%zd", die_get_bit_size(vr_die),
+                               die_get_bit_offset(vr_die),
+                               BYTES_TO_BITS(die_get_byte_size(vr_die)));
+               goto formatted;
+       }
+
        if (die_get_real_type(vr_die, &type) == NULL) {
                pr_warning("Failed to get a type information of %s.\n",
                           dwarf_diename(vr_die));
@@ -729,29 +926,31 @@ static int convert_variable_type(Dwarf_Die *vr_die,
                return (tvar->type == NULL) ? -ENOMEM : 0;
        }
 
-       ret = die_get_byte_size(&type) * 8;
-       if (ret) {
-               /* Check the bitwidth */
-               if (ret > MAX_BASIC_TYPE_BITS) {
-                       pr_info("%s exceeds max-bitwidth."
-                               " Cut down to %d bits.\n",
-                               dwarf_diename(&type), MAX_BASIC_TYPE_BITS);
-                       ret = MAX_BASIC_TYPE_BITS;
-               }
+       ret = BYTES_TO_BITS(die_get_byte_size(&type));
+       if (!ret)
+               /* No size ... try to use default type */
+               return 0;
 
-               ret = snprintf(buf, 16, "%c%d",
-                              die_is_signed_type(&type) ? 's' : 'u', ret);
-               if (ret < 0 || ret >= 16) {
-                       if (ret >= 16)
-                               ret = -E2BIG;
-                       pr_warning("Failed to convert variable type: %s\n",
-                                  strerror(-ret));
-                       return ret;
-               }
-               tvar->type = strdup(buf);
-               if (tvar->type == NULL)
-                       return -ENOMEM;
+       /* Check the bitwidth */
+       if (ret > MAX_BASIC_TYPE_BITS) {
+               pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n",
+                       dwarf_diename(&type), MAX_BASIC_TYPE_BITS);
+               ret = MAX_BASIC_TYPE_BITS;
+       }
+       ret = snprintf(buf, 16, "%c%d",
+                      die_is_signed_type(&type) ? 's' : 'u', ret);
+
+formatted:
+       if (ret < 0 || ret >= 16) {
+               if (ret >= 16)
+                       ret = -E2BIG;
+               pr_warning("Failed to convert variable type: %s\n",
+                          strerror(-ret));
+               return ret;
        }
+       tvar->type = strdup(buf);
+       if (tvar->type == NULL)
+               return -ENOMEM;
        return 0;
 }
 
@@ -1050,157 +1249,102 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
        return ret;
 }
 
-/* Find probe point from its line number */
-static int find_probe_point_by_line(struct probe_finder *pf)
+static int probe_point_line_walker(const char *fname, int lineno,
+                                  Dwarf_Addr addr, void *data)
 {
-       Dwarf_Lines *lines;
-       Dwarf_Line *line;
-       size_t nlines, i;
-       Dwarf_Addr addr;
-       int lineno;
-       int ret = 0;
-
-       if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
-               pr_warning("No source lines found.\n");
-               return -ENOENT;
-       }
+       struct probe_finder *pf = data;
+       int ret;
 
-       for (i = 0; i < nlines && ret == 0; i++) {
-               line = dwarf_onesrcline(lines, i);
-               if (dwarf_lineno(line, &lineno) != 0 ||
-                   lineno != pf->lno)
-                       continue;
+       if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0)
+               return 0;
 
-               /* TODO: Get fileno from line, but how? */
-               if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
-                       continue;
+       pf->addr = addr;
+       ret = call_probe_finder(NULL, pf);
 
-               if (dwarf_lineaddr(line, &addr) != 0) {
-                       pr_warning("Failed to get the address of the line.\n");
-                       return -ENOENT;
-               }
-               pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
-                        (int)i, lineno, (uintmax_t)addr);
-               pf->addr = addr;
+       /* Continue if no error, because the line will be in inline function */
+       return ret < 0 ? ret : 0;
+}
 
-               ret = call_probe_finder(NULL, pf);
-               /* Continuing, because target line might be inlined. */
-       }
-       return ret;
+/* Find probe point from its line number */
+static int find_probe_point_by_line(struct probe_finder *pf)
+{
+       return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf);
 }
 
 /* Find lines which match lazy pattern */
 static int find_lazy_match_lines(struct list_head *head,
                                 const char *fname, const char *pat)
 {
-       char *fbuf, *p1, *p2;
-       int fd, line, nlines = -1;
-       struct stat st;
-
-       fd = open(fname, O_RDONLY);
-       if (fd < 0) {
-               pr_warning("Failed to open %s: %s\n", fname, strerror(-fd));
+       FILE *fp;
+       char *line = NULL;
+       size_t line_len;
+       ssize_t len;
+       int count = 0, linenum = 1;
+
+       fp = fopen(fname, "r");
+       if (!fp) {
+               pr_warning("Failed to open %s: %s\n", fname, strerror(errno));
                return -errno;
        }
 
-       if (fstat(fd, &st) < 0) {
-               pr_warning("Failed to get the size of %s: %s\n",
-                          fname, strerror(errno));
-               nlines = -errno;
-               goto out_close;
-       }
-
-       nlines = -ENOMEM;
-       fbuf = malloc(st.st_size + 2);
-       if (fbuf == NULL)
-               goto out_close;
-       if (read(fd, fbuf, st.st_size) < 0) {
-               pr_warning("Failed to read %s: %s\n", fname, strerror(errno));
-               nlines = -errno;
-               goto out_free_fbuf;
-       }
-       fbuf[st.st_size] = '\n';        /* Dummy line */
-       fbuf[st.st_size + 1] = '\0';
-       p1 = fbuf;
-       line = 1;
-       nlines = 0;
-       while ((p2 = strchr(p1, '\n')) != NULL) {
-               *p2 = '\0';
-               if (strlazymatch(p1, pat)) {
-                       line_list__add_line(head, line);
-                       nlines++;
+       while ((len = getline(&line, &line_len, fp)) > 0) {
+
+               if (line[len - 1] == '\n')
+                       line[len - 1] = '\0';
+
+               if (strlazymatch(line, pat)) {
+                       line_list__add_line(head, linenum);
+                       count++;
                }
-               line++;
-               p1 = p2 + 1;
+               linenum++;
        }
-out_free_fbuf:
-       free(fbuf);
-out_close:
-       close(fd);
-       return nlines;
+
+       if (ferror(fp))
+               count = -errno;
+       free(line);
+       fclose(fp);
+
+       if (count == 0)
+               pr_debug("No matched lines found in %s.\n", fname);
+       return count;
+}
+
+static int probe_point_lazy_walker(const char *fname, int lineno,
+                                  Dwarf_Addr addr, void *data)
+{
+       struct probe_finder *pf = data;
+       int ret;
+
+       if (!line_list__has_line(&pf->lcache, lineno) ||
+           strtailcmp(fname, pf->fname) != 0)
+               return 0;
+
+       pr_debug("Probe line found: line:%d addr:0x%llx\n",
+                lineno, (unsigned long long)addr);
+       pf->addr = addr;
+       ret = call_probe_finder(NULL, pf);
+
+       /*
+        * Continue if no error, because the lazy pattern will match
+        * to other lines
+        */
+       return ret < 0 ? ret : 0;
 }
 
 /* Find probe points from lazy pattern  */
 static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
 {
-       Dwarf_Lines *lines;
-       Dwarf_Line *line;
-       size_t nlines, i;
-       Dwarf_Addr addr;
-       Dwarf_Die die_mem;
-       int lineno;
        int ret = 0;
 
        if (list_empty(&pf->lcache)) {
                /* Matching lazy line pattern */
                ret = find_lazy_match_lines(&pf->lcache, pf->fname,
                                            pf->pev->point.lazy_line);
-               if (ret == 0) {
-                       pr_debug("No matched lines found in %s.\n", pf->fname);
-                       return 0;
-               } else if (ret < 0)
+               if (ret <= 0)
                        return ret;
        }
 
-       if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
-               pr_warning("No source lines found.\n");
-               return -ENOENT;
-       }
-
-       for (i = 0; i < nlines && ret >= 0; i++) {
-               line = dwarf_onesrcline(lines, i);
-
-               if (dwarf_lineno(line, &lineno) != 0 ||
-                   !line_list__has_line(&pf->lcache, lineno))
-                       continue;
-
-               /* TODO: Get fileno from line, but how? */
-               if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
-                       continue;
-
-               if (dwarf_lineaddr(line, &addr) != 0) {
-                       pr_debug("Failed to get the address of line %d.\n",
-                                lineno);
-                       continue;
-               }
-               if (sp_die) {
-                       /* Address filtering 1: does sp_die include addr? */
-                       if (!dwarf_haspc(sp_die, addr))
-                               continue;
-                       /* Address filtering 2: No child include addr? */
-                       if (die_find_inlinefunc(sp_die, addr, &die_mem))
-                               continue;
-               }
-
-               pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
-                        (int)i, lineno, (unsigned long long)addr);
-               pf->addr = addr;
-
-               ret = call_probe_finder(sp_die, pf);
-               /* Continuing, because target line might be inlined. */
-       }
-       /* TODO: deallocate lines, but how? */
-       return ret;
+       return die_walk_lines(sp_die, probe_point_lazy_walker, pf);
 }
 
 /* Callback parameter with return value */
@@ -1318,8 +1462,7 @@ static int find_probes(int fd, struct probe_finder *pf)
        off = 0;
        line_list__init(&pf->lcache);
        /* Loop on CUs (Compilation Unit) */
-       while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) &&
-              ret >= 0) {
+       while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
                /* Get the DIE(Debugging Information Entry) of this CU */
                diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die);
                if (!diep)
@@ -1340,6 +1483,8 @@ static int find_probes(int fd, struct probe_finder *pf)
                                pf->lno = pp->line;
                                ret = find_probe_point_by_line(pf);
                        }
+                       if (ret < 0)
+                               break;
                }
                off = noff;
        }
@@ -1644,91 +1789,28 @@ static int line_range_add_line(const char *src, unsigned int lineno,
        return line_list__add_line(&lr->line_list, lineno);
 }
 
-/* Search function declaration lines */
-static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data)
+static int line_range_walk_cb(const char *fname, int lineno,
+                             Dwarf_Addr addr __used,
+                             void *data)
 {
-       struct dwarf_callback_param *param = data;
-       struct line_finder *lf = param->data;
-       const char *src;
-       int lineno;
+       struct line_finder *lf = data;
 
-       src = dwarf_decl_file(sp_die);
-       if (src && strtailcmp(src, lf->fname) != 0)
-               return DWARF_CB_OK;
-
-       if (dwarf_decl_line(sp_die, &lineno) != 0 ||
+       if ((strtailcmp(fname, lf->fname) != 0) ||
            (lf->lno_s > lineno || lf->lno_e < lineno))
-               return DWARF_CB_OK;
+               return 0;
 
-       param->retval = line_range_add_line(src, lineno, lf->lr);
-       if (param->retval < 0)
-               return DWARF_CB_ABORT;
-       return DWARF_CB_OK;
-}
+       if (line_range_add_line(fname, lineno, lf->lr) < 0)
+               return -EINVAL;
 
-static int find_line_range_func_decl_lines(struct line_finder *lf)
-{
-       struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
-       dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, &param, 0);
-       return param.retval;
+       return 0;
 }
 
 /* Find line range from its line number */
 static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
 {
-       Dwarf_Lines *lines;
-       Dwarf_Line *line;
-       size_t nlines, i;
-       Dwarf_Addr addr;
-       int lineno, ret = 0;
-       const char *src;
-       Dwarf_Die die_mem;
-
-       line_list__init(&lf->lr->line_list);
-       if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) {
-               pr_warning("No source lines found.\n");
-               return -ENOENT;
-       }
-
-       /* Search probable lines on lines list */
-       for (i = 0; i < nlines; i++) {
-               line = dwarf_onesrcline(lines, i);
-               if (dwarf_lineno(line, &lineno) != 0 ||
-                   (lf->lno_s > lineno || lf->lno_e < lineno))
-                       continue;
-
-               if (sp_die) {
-                       /* Address filtering 1: does sp_die include addr? */
-                       if (dwarf_lineaddr(line, &addr) != 0 ||
-                           !dwarf_haspc(sp_die, addr))
-                               continue;
-
-                       /* Address filtering 2: No child include addr? */
-                       if (die_find_inlinefunc(sp_die, addr, &die_mem))
-                               continue;
-               }
-
-               /* TODO: Get fileno from line, but how? */
-               src = dwarf_linesrc(line, NULL, NULL);
-               if (strtailcmp(src, lf->fname) != 0)
-                       continue;
-
-               ret = line_range_add_line(src, lineno, lf->lr);
-               if (ret < 0)
-                       return ret;
-       }
+       int ret;
 
-       /*
-        * Dwarf lines doesn't include function declarations. We have to
-        * check functions list or given function.
-        */
-       if (sp_die) {
-               src = dwarf_decl_file(sp_die);
-               if (src && dwarf_decl_line(sp_die, &lineno) == 0 &&
-                   (lf->lno_s <= lineno && lf->lno_e >= lineno))
-                       ret = line_range_add_line(src, lineno, lf->lr);
-       } else
-               ret = find_line_range_func_decl_lines(lf);
+       ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf);
 
        /* Update status */
        if (ret >= 0)
@@ -1758,9 +1840,6 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
        struct line_finder *lf = param->data;
        struct line_range *lr = lf->lr;
 
-       pr_debug("find (%llx) %s\n",
-                (unsigned long long)dwarf_dieoffset(sp_die),
-                dwarf_diename(sp_die));
        if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
            die_compare_name(sp_die, lr->function)) {
                lf->fname = dwarf_decl_file(sp_die);
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
new file mode 100644 (file)
index 0000000..a9f2d7e
--- /dev/null
@@ -0,0 +1,896 @@
+#include <Python.h>
+#include <structmember.h>
+#include <inttypes.h>
+#include <poll.h>
+#include "evlist.h"
+#include "evsel.h"
+#include "event.h"
+#include "cpumap.h"
+#include "thread_map.h"
+
+/* Define PyVarObject_HEAD_INIT for python 2.5 */
+#ifndef PyVarObject_HEAD_INIT
+# define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
+#endif
+
+struct throttle_event {
+       struct perf_event_header header;
+       u64                      time;
+       u64                      id;
+       u64                      stream_id;
+};
+
+PyMODINIT_FUNC initperf(void);
+
+#define member_def(type, member, ptype, help) \
+       { #member, ptype, \
+         offsetof(struct pyrf_event, event) + offsetof(struct type, member), \
+         0, help }
+
+#define sample_member_def(name, member, ptype, help) \
+       { #name, ptype, \
+         offsetof(struct pyrf_event, sample) + offsetof(struct perf_sample, member), \
+         0, help }
+
+struct pyrf_event {
+       PyObject_HEAD
+       struct perf_sample sample;
+       union perf_event   event;
+};
+
+#define sample_members \
+       sample_member_def(sample_ip, ip, T_ULONGLONG, "event type"),                     \
+       sample_member_def(sample_pid, pid, T_INT, "event pid"),                  \
+       sample_member_def(sample_tid, tid, T_INT, "event tid"),                  \
+       sample_member_def(sample_time, time, T_ULONGLONG, "event timestamp"),            \
+       sample_member_def(sample_addr, addr, T_ULONGLONG, "event addr"),                 \
+       sample_member_def(sample_id, id, T_ULONGLONG, "event id"),                       \
+       sample_member_def(sample_stream_id, stream_id, T_ULONGLONG, "event stream id"), \
+       sample_member_def(sample_period, period, T_ULONGLONG, "event period"),           \
+       sample_member_def(sample_cpu, cpu, T_UINT, "event cpu"),
+
+static char pyrf_mmap_event__doc[] = PyDoc_STR("perf mmap event object.");
+
+static PyMemberDef pyrf_mmap_event__members[] = {
+       sample_members
+       member_def(perf_event_header, type, T_UINT, "event type"),
+       member_def(mmap_event, pid, T_UINT, "event pid"),
+       member_def(mmap_event, tid, T_UINT, "event tid"),
+       member_def(mmap_event, start, T_ULONGLONG, "start of the map"),
+       member_def(mmap_event, len, T_ULONGLONG, "map length"),
+       member_def(mmap_event, pgoff, T_ULONGLONG, "page offset"),
+       member_def(mmap_event, filename, T_STRING_INPLACE, "backing store"),
+       { .name = NULL, },
+};
+
+static PyObject *pyrf_mmap_event__repr(struct pyrf_event *pevent)
+{
+       PyObject *ret;
+       char *s;
+
+       if (asprintf(&s, "{ type: mmap, pid: %u, tid: %u, start: %#" PRIx64 ", "
+                        "length: %#" PRIx64 ", offset: %#" PRIx64 ", "
+                        "filename: %s }",
+                    pevent->event.mmap.pid, pevent->event.mmap.tid,
+                    pevent->event.mmap.start, pevent->event.mmap.len,
+                    pevent->event.mmap.pgoff, pevent->event.mmap.filename) < 0) {
+               ret = PyErr_NoMemory();
+       } else {
+               ret = PyString_FromString(s);
+               free(s);
+       }
+       return ret;
+}
+
+static PyTypeObject pyrf_mmap_event__type = {
+       PyVarObject_HEAD_INIT(NULL, 0)
+       .tp_name        = "perf.mmap_event",
+       .tp_basicsize   = sizeof(struct pyrf_event),
+       .tp_flags       = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+       .tp_doc         = pyrf_mmap_event__doc,
+       .tp_members     = pyrf_mmap_event__members,
+       .tp_repr        = (reprfunc)pyrf_mmap_event__repr,
+};
+
+static char pyrf_task_event__doc[] = PyDoc_STR("perf task (fork/exit) event object.");
+
+static PyMemberDef pyrf_task_event__members[] = {
+       sample_members
+       member_def(perf_event_header, type, T_UINT, "event type"),
+       member_def(fork_event, pid, T_UINT, "event pid"),
+       member_def(fork_event, ppid, T_UINT, "event ppid"),
+       member_def(fork_event, tid, T_UINT, "event tid"),
+       member_def(fork_event, ptid, T_UINT, "event ptid"),
+       member_def(fork_event, time, T_ULONGLONG, "timestamp"),
+       { .name = NULL, },
+};
+
+static PyObject *pyrf_task_event__repr(struct pyrf_event *pevent)
+{
+       return PyString_FromFormat("{ type: %s, pid: %u, ppid: %u, tid: %u, "
+                                  "ptid: %u, time: %" PRIu64 "}",
+                                  pevent->event.header.type == PERF_RECORD_FORK ? "fork" : "exit",
+                                  pevent->event.fork.pid,
+                                  pevent->event.fork.ppid,
+                                  pevent->event.fork.tid,
+                                  pevent->event.fork.ptid,
+                                  pevent->event.fork.time);
+}
+
+static PyTypeObject pyrf_task_event__type = {
+       PyVarObject_HEAD_INIT(NULL, 0)
+       .tp_name        = "perf.task_event",
+       .tp_basicsize   = sizeof(struct pyrf_event),
+       .tp_flags       = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+       .tp_doc         = pyrf_task_event__doc,
+       .tp_members     = pyrf_task_event__members,
+       .tp_repr        = (reprfunc)pyrf_task_event__repr,
+};
+
+static char pyrf_comm_event__doc[] = PyDoc_STR("perf comm event object.");
+
+static PyMemberDef pyrf_comm_event__members[] = {
+       sample_members
+       member_def(perf_event_header, type, T_UINT, "event type"),
+       member_def(comm_event, pid, T_UINT, "event pid"),
+       member_def(comm_event, tid, T_UINT, "event tid"),
+       member_def(comm_event, comm, T_STRING_INPLACE, "process name"),
+       { .name = NULL, },
+};
+
+static PyObject *pyrf_comm_event__repr(struct pyrf_event *pevent)
+{
+       return PyString_FromFormat("{ type: comm, pid: %u, tid: %u, comm: %s }",
+                                  pevent->event.comm.pid,
+                                  pevent->event.comm.tid,
+                                  pevent->event.comm.comm);
+}
+
+static PyTypeObject pyrf_comm_event__type = {
+       PyVarObject_HEAD_INIT(NULL, 0)
+       .tp_name        = "perf.comm_event",
+       .tp_basicsize   = sizeof(struct pyrf_event),
+       .tp_flags       = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+       .tp_doc         = pyrf_comm_event__doc,
+       .tp_members     = pyrf_comm_event__members,
+       .tp_repr        = (reprfunc)pyrf_comm_event__repr,
+};
+
+static char pyrf_throttle_event__doc[] = PyDoc_STR("perf throttle event object.");
+
+static PyMemberDef pyrf_throttle_event__members[] = {
+       sample_members
+       member_def(perf_event_header, type, T_UINT, "event type"),
+       member_def(throttle_event, time, T_ULONGLONG, "timestamp"),
+       member_def(throttle_event, id, T_ULONGLONG, "event id"),
+       member_def(throttle_event, stream_id, T_ULONGLONG, "event stream id"),
+       { .name = NULL, },
+};
+
+static PyObject *pyrf_throttle_event__repr(struct pyrf_event *pevent)
+{
+       struct throttle_event *te = (struct throttle_event *)(&pevent->event.header + 1);
+
+       return PyString_FromFormat("{ type: %sthrottle, time: %" PRIu64 ", id: %" PRIu64
+                                  ", stream_id: %" PRIu64 " }",
+                                  pevent->event.header.type == PERF_RECORD_THROTTLE ? "" : "un",
+                                  te->time, te->id, te->stream_id);
+}
+
+static PyTypeObject pyrf_throttle_event__type = {
+       PyVarObject_HEAD_INIT(NULL, 0)
+       .tp_name        = "perf.throttle_event",
+       .tp_basicsize   = sizeof(struct pyrf_event),
+       .tp_flags       = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+       .tp_doc         = pyrf_throttle_event__doc,
+       .tp_members     = pyrf_throttle_event__members,
+       .tp_repr        = (reprfunc)pyrf_throttle_event__repr,
+};
+
+static int pyrf_event__setup_types(void)
+{
+       int err;
+       pyrf_mmap_event__type.tp_new =
+       pyrf_task_event__type.tp_new =
+       pyrf_comm_event__type.tp_new =
+       pyrf_throttle_event__type.tp_new = PyType_GenericNew;
+       err = PyType_Ready(&pyrf_mmap_event__type);
+       if (err < 0)
+               goto out;
+       err = PyType_Ready(&pyrf_task_event__type);
+       if (err < 0)
+               goto out;
+       err = PyType_Ready(&pyrf_comm_event__type);
+       if (err < 0)
+               goto out;
+       err = PyType_Ready(&pyrf_throttle_event__type);
+       if (err < 0)
+               goto out;
+out:
+       return err;
+}
+
+static PyTypeObject *pyrf_event__type[] = {
+       [PERF_RECORD_MMAP]       = &pyrf_mmap_event__type,
+       [PERF_RECORD_LOST]       = &pyrf_mmap_event__type,
+       [PERF_RECORD_COMM]       = &pyrf_comm_event__type,
+       [PERF_RECORD_EXIT]       = &pyrf_task_event__type,
+       [PERF_RECORD_THROTTLE]   = &pyrf_throttle_event__type,
+       [PERF_RECORD_UNTHROTTLE] = &pyrf_throttle_event__type,
+       [PERF_RECORD_FORK]       = &pyrf_task_event__type,
+       [PERF_RECORD_READ]       = &pyrf_mmap_event__type,
+       [PERF_RECORD_SAMPLE]     = &pyrf_mmap_event__type,
+};
+
+static PyObject *pyrf_event__new(union perf_event *event)
+{
+       struct pyrf_event *pevent;
+       PyTypeObject *ptype;
+
+       if (event->header.type < PERF_RECORD_MMAP ||
+           event->header.type > PERF_RECORD_SAMPLE)
+               return NULL;
+
+       ptype = pyrf_event__type[event->header.type];
+       pevent = PyObject_New(struct pyrf_event, ptype);
+       if (pevent != NULL)
+               memcpy(&pevent->event, event, event->header.size);
+       return (PyObject *)pevent;
+}
+
+struct pyrf_cpu_map {
+       PyObject_HEAD
+
+       struct cpu_map *cpus;
+};
+
+static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus,
+                             PyObject *args, PyObject *kwargs)
+{
+       static char *kwlist[] = { "cpustr", NULL, NULL, };
+       char *cpustr = NULL;
+
+       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s",
+                                        kwlist, &cpustr))
+               return -1;
+
+       pcpus->cpus = cpu_map__new(cpustr);
+       if (pcpus->cpus == NULL)
+               return -1;
+       return 0;
+}
+
+static void pyrf_cpu_map__delete(struct pyrf_cpu_map *pcpus)
+{
+       cpu_map__delete(pcpus->cpus);
+       pcpus->ob_type->tp_free((PyObject*)pcpus);
+}
+
+static Py_ssize_t pyrf_cpu_map__length(PyObject *obj)
+{
+       struct pyrf_cpu_map *pcpus = (void *)obj;
+
+       return pcpus->cpus->nr;
+}
+
+static PyObject *pyrf_cpu_map__item(PyObject *obj, Py_ssize_t i)
+{
+       struct pyrf_cpu_map *pcpus = (void *)obj;
+
+       if (i >= pcpus->cpus->nr)
+               return NULL;
+
+       return Py_BuildValue("i", pcpus->cpus->map[i]);
+}
+
+static PySequenceMethods pyrf_cpu_map__sequence_methods = {
+       .sq_length = pyrf_cpu_map__length,
+       .sq_item   = pyrf_cpu_map__item,
+};
+
+static char pyrf_cpu_map__doc[] = PyDoc_STR("cpu map object.");
+
+static PyTypeObject pyrf_cpu_map__type = {
+       PyVarObject_HEAD_INIT(NULL, 0)
+       .tp_name        = "perf.cpu_map",
+       .tp_basicsize   = sizeof(struct pyrf_cpu_map),
+       .tp_dealloc     = (destructor)pyrf_cpu_map__delete,
+       .tp_flags       = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+       .tp_doc         = pyrf_cpu_map__doc,
+       .tp_as_sequence = &pyrf_cpu_map__sequence_methods,
+       .tp_init        = (initproc)pyrf_cpu_map__init,
+};
+
+static int pyrf_cpu_map__setup_types(void)
+{
+       pyrf_cpu_map__type.tp_new = PyType_GenericNew;
+       return PyType_Ready(&pyrf_cpu_map__type);
+}
+
+struct pyrf_thread_map {
+       PyObject_HEAD
+
+       struct thread_map *threads;
+};
+
+static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads,
+                                PyObject *args, PyObject *kwargs)
+{
+       static char *kwlist[] = { "pid", "tid", NULL, NULL, };
+       int pid = -1, tid = -1;
+
+       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii",
+                                        kwlist, &pid, &tid))
+               return -1;
+
+       pthreads->threads = thread_map__new(pid, tid);
+       if (pthreads->threads == NULL)
+               return -1;
+       return 0;
+}
+
+static void pyrf_thread_map__delete(struct pyrf_thread_map *pthreads)
+{
+       thread_map__delete(pthreads->threads);
+       pthreads->ob_type->tp_free((PyObject*)pthreads);
+}
+
+static Py_ssize_t pyrf_thread_map__length(PyObject *obj)
+{
+       struct pyrf_thread_map *pthreads = (void *)obj;
+
+       return pthreads->threads->nr;
+}
+
+static PyObject *pyrf_thread_map__item(PyObject *obj, Py_ssize_t i)
+{
+       struct pyrf_thread_map *pthreads = (void *)obj;
+
+       if (i >= pthreads->threads->nr)
+               return NULL;
+
+       return Py_BuildValue("i", pthreads->threads->map[i]);
+}
+
+static PySequenceMethods pyrf_thread_map__sequence_methods = {
+       .sq_length = pyrf_thread_map__length,
+       .sq_item   = pyrf_thread_map__item,
+};
+
+static char pyrf_thread_map__doc[] = PyDoc_STR("thread map object.");
+
+static PyTypeObject pyrf_thread_map__type = {
+       PyVarObject_HEAD_INIT(NULL, 0)
+       .tp_name        = "perf.thread_map",
+       .tp_basicsize   = sizeof(struct pyrf_thread_map),
+       .tp_dealloc     = (destructor)pyrf_thread_map__delete,
+       .tp_flags       = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+       .tp_doc         = pyrf_thread_map__doc,
+       .tp_as_sequence = &pyrf_thread_map__sequence_methods,
+       .tp_init        = (initproc)pyrf_thread_map__init,
+};
+
+static int pyrf_thread_map__setup_types(void)
+{
+       pyrf_thread_map__type.tp_new = PyType_GenericNew;
+       return PyType_Ready(&pyrf_thread_map__type);
+}
+
+struct pyrf_evsel {
+       PyObject_HEAD
+
+       struct perf_evsel evsel;
+};
+
+static int pyrf_evsel__init(struct pyrf_evsel *pevsel,
+                           PyObject *args, PyObject *kwargs)
+{
+       struct perf_event_attr attr = {
+               .type = PERF_TYPE_HARDWARE,
+               .config = PERF_COUNT_HW_CPU_CYCLES,
+               .sample_type = PERF_SAMPLE_PERIOD | PERF_SAMPLE_TID,
+       };
+       static char *kwlist[] = {
+               "type",
+               "config",
+               "sample_freq",
+               "sample_period",
+               "sample_type",
+               "read_format",
+               "disabled",
+               "inherit",
+               "pinned",
+               "exclusive",
+               "exclude_user",
+               "exclude_kernel",
+               "exclude_hv",
+               "exclude_idle",
+               "mmap",
+               "comm",
+               "freq",
+               "inherit_stat",
+               "enable_on_exec",
+               "task",
+               "watermark",
+               "precise_ip",
+               "mmap_data",
+               "sample_id_all",
+               "wakeup_events",
+               "bp_type",
+               "bp_addr",
+               "bp_len", NULL, NULL, };
+       u64 sample_period = 0;
+       u32 disabled = 0,
+           inherit = 0,
+           pinned = 0,
+           exclusive = 0,
+           exclude_user = 0,
+           exclude_kernel = 0,
+           exclude_hv = 0,
+           exclude_idle = 0,
+           mmap = 0,
+           comm = 0,
+           freq = 1,
+           inherit_stat = 0,
+           enable_on_exec = 0,
+           task = 0,
+           watermark = 0,
+           precise_ip = 0,
+           mmap_data = 0,
+           sample_id_all = 1;
+       int idx = 0;
+
+       if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+                                        "|iKiKKiiiiiiiiiiiiiiiiiiiiiKK", kwlist,
+                                        &attr.type, &attr.config, &attr.sample_freq,
+                                        &sample_period, &attr.sample_type,
+                                        &attr.read_format, &disabled, &inherit,
+                                        &pinned, &exclusive, &exclude_user,
+                                        &exclude_kernel, &exclude_hv, &exclude_idle,
+                                        &mmap, &comm, &freq, &inherit_stat,
+                                        &enable_on_exec, &task, &watermark,
+                                        &precise_ip, &mmap_data, &sample_id_all,
+                                        &attr.wakeup_events, &attr.bp_type,
+                                        &attr.bp_addr, &attr.bp_len, &idx))
+               return -1;
+
+       /* union... */
+       if (sample_period != 0) {
+               if (attr.sample_freq != 0)
+                       return -1; /* FIXME: throw right exception */
+               attr.sample_period = sample_period;
+       }
+
+       /* Bitfields */
+       attr.disabled       = disabled;
+       attr.inherit        = inherit;
+       attr.pinned         = pinned;
+       attr.exclusive      = exclusive;
+       attr.exclude_user   = exclude_user;
+       attr.exclude_kernel = exclude_kernel;
+       attr.exclude_hv     = exclude_hv;
+       attr.exclude_idle   = exclude_idle;
+       attr.mmap           = mmap;
+       attr.comm           = comm;
+       attr.freq           = freq;
+       attr.inherit_stat   = inherit_stat;
+       attr.enable_on_exec = enable_on_exec;
+       attr.task           = task;
+       attr.watermark      = watermark;
+       attr.precise_ip     = precise_ip;
+       attr.mmap_data      = mmap_data;
+       attr.sample_id_all  = sample_id_all;
+
+       perf_evsel__init(&pevsel->evsel, &attr, idx);
+       return 0;
+}
+
+static void pyrf_evsel__delete(struct pyrf_evsel *pevsel)
+{
+       perf_evsel__exit(&pevsel->evsel);
+       pevsel->ob_type->tp_free((PyObject*)pevsel);
+}
+
+static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel,
+                                 PyObject *args, PyObject *kwargs)
+{
+       struct perf_evsel *evsel = &pevsel->evsel;
+       struct cpu_map *cpus = NULL;
+       struct thread_map *threads = NULL;
+       PyObject *pcpus = NULL, *pthreads = NULL;
+       int group = 0, overwrite = 0;
+       static char *kwlist[] = {"cpus", "threads", "group", "overwrite", NULL, NULL};
+
+       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist,
+                                        &pcpus, &pthreads, &group, &overwrite))
+               return NULL;
+
+       if (pthreads != NULL)
+               threads = ((struct pyrf_thread_map *)pthreads)->threads;
+
+       if (pcpus != NULL)
+               cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
+
+       if (perf_evsel__open(evsel, cpus, threads, group, overwrite) < 0) {
+               PyErr_SetFromErrno(PyExc_OSError);
+               return NULL;
+       }
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyMethodDef pyrf_evsel__methods[] = {
+       {
+               .ml_name  = "open",
+               .ml_meth  = (PyCFunction)pyrf_evsel__open,
+               .ml_flags = METH_VARARGS | METH_KEYWORDS,
+               .ml_doc   = PyDoc_STR("open the event selector file descriptor table.")
+       },
+       { .ml_name = NULL, }
+};
+
+static char pyrf_evsel__doc[] = PyDoc_STR("perf event selector list object.");
+
+static PyTypeObject pyrf_evsel__type = {
+       PyVarObject_HEAD_INIT(NULL, 0)
+       .tp_name        = "perf.evsel",
+       .tp_basicsize   = sizeof(struct pyrf_evsel),
+       .tp_dealloc     = (destructor)pyrf_evsel__delete,
+       .tp_flags       = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+       .tp_doc         = pyrf_evsel__doc,
+       .tp_methods     = pyrf_evsel__methods,
+       .tp_init        = (initproc)pyrf_evsel__init,
+};
+
+static int pyrf_evsel__setup_types(void)
+{
+       pyrf_evsel__type.tp_new = PyType_GenericNew;
+       return PyType_Ready(&pyrf_evsel__type);
+}
+
+struct pyrf_evlist {
+       PyObject_HEAD
+
+       struct perf_evlist evlist;
+};
+
+static int pyrf_evlist__init(struct pyrf_evlist *pevlist,
+                            PyObject *args, PyObject *kwargs __used)
+{
+       PyObject *pcpus = NULL, *pthreads = NULL;
+       struct cpu_map *cpus;
+       struct thread_map *threads;
+
+       if (!PyArg_ParseTuple(args, "OO", &pcpus, &pthreads))
+               return -1;
+
+       threads = ((struct pyrf_thread_map *)pthreads)->threads;
+       cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
+       perf_evlist__init(&pevlist->evlist, cpus, threads);
+       return 0;
+}
+
+static void pyrf_evlist__delete(struct pyrf_evlist *pevlist)
+{
+       perf_evlist__exit(&pevlist->evlist);
+       pevlist->ob_type->tp_free((PyObject*)pevlist);
+}
+
+static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
+                                  PyObject *args, PyObject *kwargs)
+{
+       struct perf_evlist *evlist = &pevlist->evlist;
+       static char *kwlist[] = {"pages", "overwrite",
+                                 NULL, NULL};
+       int pages = 128, overwrite = false;
+
+       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii", kwlist,
+                                        &pages, &overwrite))
+               return NULL;
+
+       if (perf_evlist__mmap(evlist, pages, overwrite) < 0) {
+               PyErr_SetFromErrno(PyExc_OSError);
+               return NULL;
+       }
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist,
+                                  PyObject *args, PyObject *kwargs)
+{
+       struct perf_evlist *evlist = &pevlist->evlist;
+       static char *kwlist[] = {"timeout", NULL, NULL};
+       int timeout = -1, n;
+
+       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &timeout))
+               return NULL;
+
+       n = poll(evlist->pollfd, evlist->nr_fds, timeout);
+       if (n < 0) {
+               PyErr_SetFromErrno(PyExc_OSError);
+               return NULL;
+       }
+
+       return Py_BuildValue("i", n);
+}
+
+static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
+                                        PyObject *args __used, PyObject *kwargs __used)
+{
+       struct perf_evlist *evlist = &pevlist->evlist;
+        PyObject *list = PyList_New(0);
+       int i;
+
+       for (i = 0; i < evlist->nr_fds; ++i) {
+               PyObject *file;
+               FILE *fp = fdopen(evlist->pollfd[i].fd, "r");
+
+               if (fp == NULL)
+                       goto free_list;
+
+               file = PyFile_FromFile(fp, "perf", "r", NULL);
+               if (file == NULL)
+                       goto free_list;
+
+               if (PyList_Append(list, file) != 0) {
+                       Py_DECREF(file);
+                       goto free_list;
+               }
+                       
+               Py_DECREF(file);
+       }
+
+       return list;
+free_list:
+       return PyErr_NoMemory();
+}
+
+
+static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist,
+                                 PyObject *args, PyObject *kwargs __used)
+{
+       struct perf_evlist *evlist = &pevlist->evlist;
+       PyObject *pevsel;
+       struct perf_evsel *evsel;
+
+       if (!PyArg_ParseTuple(args, "O", &pevsel))
+               return NULL;
+
+       Py_INCREF(pevsel);
+       evsel = &((struct pyrf_evsel *)pevsel)->evsel;
+       evsel->idx = evlist->nr_entries;
+       perf_evlist__add(evlist, evsel);
+
+       return Py_BuildValue("i", evlist->nr_entries);
+}
+
+static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
+                                         PyObject *args, PyObject *kwargs)
+{
+       struct perf_evlist *evlist = &pevlist->evlist;
+       union perf_event *event;
+       int sample_id_all = 1, cpu;
+       static char *kwlist[] = {"sample_id_all", NULL, NULL};
+
+       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|i", kwlist,
+                                        &cpu, &sample_id_all))
+               return NULL;
+
+       event = perf_evlist__read_on_cpu(evlist, cpu);
+       if (event != NULL) {
+               struct perf_evsel *first;
+               PyObject *pyevent = pyrf_event__new(event);
+               struct pyrf_event *pevent = (struct pyrf_event *)pyevent;
+
+               if (pyevent == NULL)
+                       return PyErr_NoMemory();
+
+               first = list_entry(evlist->entries.next, struct perf_evsel, node);
+               perf_event__parse_sample(event, first->attr.sample_type, sample_id_all,
+                                        &pevent->sample);
+               return pyevent;
+       }
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyMethodDef pyrf_evlist__methods[] = {
+       {
+               .ml_name  = "mmap",
+               .ml_meth  = (PyCFunction)pyrf_evlist__mmap,
+               .ml_flags = METH_VARARGS | METH_KEYWORDS,
+               .ml_doc   = PyDoc_STR("mmap the file descriptor table.")
+       },
+       {
+               .ml_name  = "poll",
+               .ml_meth  = (PyCFunction)pyrf_evlist__poll,
+               .ml_flags = METH_VARARGS | METH_KEYWORDS,
+               .ml_doc   = PyDoc_STR("poll the file descriptor table.")
+       },
+       {
+               .ml_name  = "get_pollfd",
+               .ml_meth  = (PyCFunction)pyrf_evlist__get_pollfd,
+               .ml_flags = METH_VARARGS | METH_KEYWORDS,
+               .ml_doc   = PyDoc_STR("get the poll file descriptor table.")
+       },
+       {
+               .ml_name  = "add",
+               .ml_meth  = (PyCFunction)pyrf_evlist__add,
+               .ml_flags = METH_VARARGS | METH_KEYWORDS,
+               .ml_doc   = PyDoc_STR("adds an event selector to the list.")
+       },
+       {
+               .ml_name  = "read_on_cpu",
+               .ml_meth  = (PyCFunction)pyrf_evlist__read_on_cpu,
+               .ml_flags = METH_VARARGS | METH_KEYWORDS,
+               .ml_doc   = PyDoc_STR("reads an event.")
+       },
+       { .ml_name = NULL, }
+};
+
+static Py_ssize_t pyrf_evlist__length(PyObject *obj)
+{
+       struct pyrf_evlist *pevlist = (void *)obj;
+
+       return pevlist->evlist.nr_entries;
+}
+
+static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i)
+{
+       struct pyrf_evlist *pevlist = (void *)obj;
+       struct perf_evsel *pos;
+
+       if (i >= pevlist->evlist.nr_entries)
+               return NULL;
+
+       list_for_each_entry(pos, &pevlist->evlist.entries, node)
+               if (i-- == 0)
+                       break;
+
+       return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel));
+}
+
+static PySequenceMethods pyrf_evlist__sequence_methods = {
+       .sq_length = pyrf_evlist__length,
+       .sq_item   = pyrf_evlist__item,
+};
+
+static char pyrf_evlist__doc[] = PyDoc_STR("perf event selector list object.");
+
+static PyTypeObject pyrf_evlist__type = {
+       PyVarObject_HEAD_INIT(NULL, 0)
+       .tp_name        = "perf.evlist",
+       .tp_basicsize   = sizeof(struct pyrf_evlist),
+       .tp_dealloc     = (destructor)pyrf_evlist__delete,
+       .tp_flags       = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+       .tp_as_sequence = &pyrf_evlist__sequence_methods,
+       .tp_doc         = pyrf_evlist__doc,
+       .tp_methods     = pyrf_evlist__methods,
+       .tp_init        = (initproc)pyrf_evlist__init,
+};
+
+static int pyrf_evlist__setup_types(void)
+{
+       pyrf_evlist__type.tp_new = PyType_GenericNew;
+       return PyType_Ready(&pyrf_evlist__type);
+}
+
+static struct {
+       const char *name;
+       int         value;
+} perf__constants[] = {
+       { "TYPE_HARDWARE",   PERF_TYPE_HARDWARE },
+       { "TYPE_SOFTWARE",   PERF_TYPE_SOFTWARE },
+       { "TYPE_TRACEPOINT", PERF_TYPE_TRACEPOINT },
+       { "TYPE_HW_CACHE",   PERF_TYPE_HW_CACHE },
+       { "TYPE_RAW",        PERF_TYPE_RAW },
+       { "TYPE_BREAKPOINT", PERF_TYPE_BREAKPOINT },
+
+       { "COUNT_HW_CPU_CYCLES",          PERF_COUNT_HW_CPU_CYCLES },
+       { "COUNT_HW_INSTRUCTIONS",        PERF_COUNT_HW_INSTRUCTIONS },
+       { "COUNT_HW_CACHE_REFERENCES",    PERF_COUNT_HW_CACHE_REFERENCES },
+       { "COUNT_HW_CACHE_MISSES",        PERF_COUNT_HW_CACHE_MISSES },
+       { "COUNT_HW_BRANCH_INSTRUCTIONS", PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
+       { "COUNT_HW_BRANCH_MISSES",       PERF_COUNT_HW_BRANCH_MISSES },
+       { "COUNT_HW_BUS_CYCLES",          PERF_COUNT_HW_BUS_CYCLES },
+       { "COUNT_HW_CACHE_L1D",           PERF_COUNT_HW_CACHE_L1D },
+       { "COUNT_HW_CACHE_L1I",           PERF_COUNT_HW_CACHE_L1I },
+       { "COUNT_HW_CACHE_LL",            PERF_COUNT_HW_CACHE_LL },
+       { "COUNT_HW_CACHE_DTLB",          PERF_COUNT_HW_CACHE_DTLB },
+       { "COUNT_HW_CACHE_ITLB",          PERF_COUNT_HW_CACHE_ITLB },
+       { "COUNT_HW_CACHE_BPU",           PERF_COUNT_HW_CACHE_BPU },
+       { "COUNT_HW_CACHE_OP_READ",       PERF_COUNT_HW_CACHE_OP_READ },
+       { "COUNT_HW_CACHE_OP_WRITE",      PERF_COUNT_HW_CACHE_OP_WRITE },
+       { "COUNT_HW_CACHE_OP_PREFETCH",   PERF_COUNT_HW_CACHE_OP_PREFETCH },
+       { "COUNT_HW_CACHE_RESULT_ACCESS", PERF_COUNT_HW_CACHE_RESULT_ACCESS },
+       { "COUNT_HW_CACHE_RESULT_MISS",   PERF_COUNT_HW_CACHE_RESULT_MISS },
+
+       { "COUNT_SW_CPU_CLOCK",        PERF_COUNT_SW_CPU_CLOCK },
+       { "COUNT_SW_TASK_CLOCK",       PERF_COUNT_SW_TASK_CLOCK },
+       { "COUNT_SW_PAGE_FAULTS",      PERF_COUNT_SW_PAGE_FAULTS },
+       { "COUNT_SW_CONTEXT_SWITCHES", PERF_COUNT_SW_CONTEXT_SWITCHES },
+       { "COUNT_SW_CPU_MIGRATIONS",   PERF_COUNT_SW_CPU_MIGRATIONS },
+       { "COUNT_SW_PAGE_FAULTS_MIN",  PERF_COUNT_SW_PAGE_FAULTS_MIN },
+       { "COUNT_SW_PAGE_FAULTS_MAJ",  PERF_COUNT_SW_PAGE_FAULTS_MAJ },
+       { "COUNT_SW_ALIGNMENT_FAULTS", PERF_COUNT_SW_ALIGNMENT_FAULTS },
+       { "COUNT_SW_EMULATION_FAULTS", PERF_COUNT_SW_EMULATION_FAULTS },
+
+       { "SAMPLE_IP",        PERF_SAMPLE_IP },
+       { "SAMPLE_TID",       PERF_SAMPLE_TID },
+       { "SAMPLE_TIME",      PERF_SAMPLE_TIME },
+       { "SAMPLE_ADDR",      PERF_SAMPLE_ADDR },
+       { "SAMPLE_READ",      PERF_SAMPLE_READ },
+       { "SAMPLE_CALLCHAIN", PERF_SAMPLE_CALLCHAIN },
+       { "SAMPLE_ID",        PERF_SAMPLE_ID },
+       { "SAMPLE_CPU",       PERF_SAMPLE_CPU },
+       { "SAMPLE_PERIOD",    PERF_SAMPLE_PERIOD },
+       { "SAMPLE_STREAM_ID", PERF_SAMPLE_STREAM_ID },
+       { "SAMPLE_RAW",       PERF_SAMPLE_RAW },
+
+       { "FORMAT_TOTAL_TIME_ENABLED", PERF_FORMAT_TOTAL_TIME_ENABLED },
+       { "FORMAT_TOTAL_TIME_RUNNING", PERF_FORMAT_TOTAL_TIME_RUNNING },
+       { "FORMAT_ID",                 PERF_FORMAT_ID },
+       { "FORMAT_GROUP",              PERF_FORMAT_GROUP },
+
+       { "RECORD_MMAP",       PERF_RECORD_MMAP },
+       { "RECORD_LOST",       PERF_RECORD_LOST },
+       { "RECORD_COMM",       PERF_RECORD_COMM },
+       { "RECORD_EXIT",       PERF_RECORD_EXIT },
+       { "RECORD_THROTTLE",   PERF_RECORD_THROTTLE },
+       { "RECORD_UNTHROTTLE", PERF_RECORD_UNTHROTTLE },
+       { "RECORD_FORK",       PERF_RECORD_FORK },
+       { "RECORD_READ",       PERF_RECORD_READ },
+       { "RECORD_SAMPLE",     PERF_RECORD_SAMPLE },
+       { .name = NULL, },
+};
+
+static PyMethodDef perf__methods[] = {
+       { .ml_name = NULL, }
+};
+
+PyMODINIT_FUNC initperf(void)
+{
+       PyObject *obj;
+       int i;
+       PyObject *dict, *module = Py_InitModule("perf", perf__methods);
+
+       if (module == NULL ||
+           pyrf_event__setup_types() < 0 ||
+           pyrf_evlist__setup_types() < 0 ||
+           pyrf_evsel__setup_types() < 0 ||
+           pyrf_thread_map__setup_types() < 0 ||
+           pyrf_cpu_map__setup_types() < 0)
+               return;
+
+       Py_INCREF(&pyrf_evlist__type);
+       PyModule_AddObject(module, "evlist", (PyObject*)&pyrf_evlist__type);
+
+       Py_INCREF(&pyrf_evsel__type);
+       PyModule_AddObject(module, "evsel", (PyObject*)&pyrf_evsel__type);
+
+       Py_INCREF(&pyrf_thread_map__type);
+       PyModule_AddObject(module, "thread_map", (PyObject*)&pyrf_thread_map__type);
+
+       Py_INCREF(&pyrf_cpu_map__type);
+       PyModule_AddObject(module, "cpu_map", (PyObject*)&pyrf_cpu_map__type);
+
+       dict = PyModule_GetDict(module);
+       if (dict == NULL)
+               goto error;
+
+       for (i = 0; perf__constants[i].name != NULL; i++) {
+               obj = PyInt_FromLong(perf__constants[i].value);
+               if (obj == NULL)
+                       goto error;
+               PyDict_SetItemString(dict, perf__constants[i].name, obj);
+               Py_DECREF(obj);
+       }
+
+error:
+       if (PyErr_Occurred())
+               PyErr_SetString(PyExc_ImportError, "perf: Init failed!");
+}
index c6d9933..2040b85 100644 (file)
@@ -248,8 +248,7 @@ static void python_process_event(int cpu, void *data,
        context = PyCObject_FromVoidPtr(scripting_context, NULL);
 
        PyTuple_SetItem(t, n++, PyString_FromString(handler_name));
-       PyTuple_SetItem(t, n++,
-                       PyCObject_FromVoidPtr(scripting_context, NULL));
+       PyTuple_SetItem(t, n++, context);
 
        if (handler) {
                PyTuple_SetItem(t, n++, PyInt_FromLong(cpu));
index 105f00b..f26639f 100644 (file)
@@ -7,6 +7,8 @@
 #include <sys/types.h>
 #include <sys/mman.h>
 
+#include "evlist.h"
+#include "evsel.h"
 #include "session.h"
 #include "sort.h"
 #include "util.h"
@@ -19,7 +21,7 @@ static int perf_session__open(struct perf_session *self, bool force)
                self->fd_pipe = true;
                self->fd = STDIN_FILENO;
 
-               if (perf_header__read(self, self->fd) < 0)
+               if (perf_session__read_header(self, self->fd) < 0)
                        pr_err("incompatible file format");
 
                return 0;
@@ -51,7 +53,7 @@ static int perf_session__open(struct perf_session *self, bool force)
                goto out_close;
        }
 
-       if (perf_header__read(self, self->fd) < 0) {
+       if (perf_session__read_header(self, self->fd) < 0) {
                pr_err("incompatible file format");
                goto out_close;
        }
@@ -67,7 +69,7 @@ out_close:
 
 static void perf_session__id_header_size(struct perf_session *session)
 {
-       struct sample_data *data;
+       struct perf_sample *data;
        u64 sample_type = session->sample_type;
        u16 size = 0;
 
@@ -92,21 +94,10 @@ out:
        session->id_hdr_size = size;
 }
 
-void perf_session__set_sample_id_all(struct perf_session *session, bool value)
-{
-       session->sample_id_all = value;
-       perf_session__id_header_size(session);
-}
-
-void perf_session__set_sample_type(struct perf_session *session, u64 type)
-{
-       session->sample_type = type;
-}
-
 void perf_session__update_sample_type(struct perf_session *self)
 {
-       self->sample_type = perf_header__sample_type(&self->header);
-       self->sample_id_all = perf_header__sample_id_all(&self->header);
+       self->sample_type = perf_evlist__sample_type(self->evlist);
+       self->sample_id_all = perf_evlist__sample_id_all(self->evlist);
        perf_session__id_header_size(self);
 }
 
@@ -135,13 +126,9 @@ struct perf_session *perf_session__new(const char *filename, int mode,
        if (self == NULL)
                goto out;
 
-       if (perf_header__init(&self->header) < 0)
-               goto out_free;
-
        memcpy(self->filename, filename, len);
        self->threads = RB_ROOT;
        INIT_LIST_HEAD(&self->dead_threads);
-       self->hists_tree = RB_ROOT;
        self->last_match = NULL;
        /*
         * On 64bit we can mmap the data file in one go. No need for tiny mmap
@@ -162,17 +149,16 @@ struct perf_session *perf_session__new(const char *filename, int mode,
        if (mode == O_RDONLY) {
                if (perf_session__open(self, force) < 0)
                        goto out_delete;
+               perf_session__update_sample_type(self);
        } else if (mode == O_WRONLY) {
                /*
                 * In O_RDONLY mode this will be performed when reading the
-                * kernel MMAP event, in event__process_mmap().
+                * kernel MMAP event, in perf_event__process_mmap().
                 */
                if (perf_session__create_kernel_maps(self) < 0)
                        goto out_delete;
        }
 
-       perf_session__update_sample_type(self);
-
        if (ops && ops->ordering_requires_timestamps &&
            ops->ordered_samples && !self->sample_id_all) {
                dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
@@ -181,9 +167,6 @@ struct perf_session *perf_session__new(const char *filename, int mode,
 
 out:
        return self;
-out_free:
-       free(self);
-       return NULL;
 out_delete:
        perf_session__delete(self);
        return NULL;
@@ -214,7 +197,6 @@ static void perf_session__delete_threads(struct perf_session *self)
 
 void perf_session__delete(struct perf_session *self)
 {
-       perf_header__exit(&self->header);
        perf_session__destroy_kernel_maps(self);
        perf_session__delete_dead_threads(self);
        perf_session__delete_threads(self);
@@ -242,17 +224,16 @@ static bool symbol__match_parent_regex(struct symbol *sym)
        return 0;
 }
 
-struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
-                                                  struct thread *thread,
-                                                  struct ip_callchain *chain,
-                                                  struct symbol **parent)
+int perf_session__resolve_callchain(struct perf_session *self,
+                                   struct thread *thread,
+                                   struct ip_callchain *chain,
+                                   struct symbol **parent)
 {
        u8 cpumode = PERF_RECORD_MISC_USER;
        unsigned int i;
-       struct map_symbol *syms = calloc(chain->nr, sizeof(*syms));
+       int err;
 
-       if (!syms)
-               return NULL;
+       callchain_cursor_reset(&self->callchain_cursor);
 
        for (i = 0; i < chain->nr; i++) {
                u64 ip = chain->ips[i];
@@ -281,30 +262,33 @@ struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
                                *parent = al.sym;
                        if (!symbol_conf.use_callchain)
                                break;
-                       syms[i].map = al.map;
-                       syms[i].sym = al.sym;
                }
+
+               err = callchain_cursor_append(&self->callchain_cursor,
+                                             ip, al.map, al.sym);
+               if (err)
+                       return err;
        }
 
-       return syms;
+       return 0;
 }
 
-static int process_event_synth_stub(event_t *event __used,
+static int process_event_synth_stub(union perf_event *event __used,
                                    struct perf_session *session __used)
 {
        dump_printf(": unhandled!\n");
        return 0;
 }
 
-static int process_event_stub(event_t *event __used,
-                             struct sample_data *sample __used,
+static int process_event_stub(union perf_event *event __used,
+                             struct perf_sample *sample __used,
                              struct perf_session *session __used)
 {
        dump_printf(": unhandled!\n");
        return 0;
 }
 
-static int process_finished_round_stub(event_t *event __used,
+static int process_finished_round_stub(union perf_event *event __used,
                                       struct perf_session *session __used,
                                       struct perf_event_ops *ops __used)
 {
@@ -312,7 +296,7 @@ static int process_finished_round_stub(event_t *event __used,
        return 0;
 }
 
-static int process_finished_round(event_t *event,
+static int process_finished_round(union perf_event *event,
                                  struct perf_session *session,
                                  struct perf_event_ops *ops);
 
@@ -329,7 +313,7 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
        if (handler->exit == NULL)
                handler->exit = process_event_stub;
        if (handler->lost == NULL)
-               handler->lost = event__process_lost;
+               handler->lost = perf_event__process_lost;
        if (handler->read == NULL)
                handler->read = process_event_stub;
        if (handler->throttle == NULL)
@@ -363,98 +347,98 @@ void mem_bswap_64(void *src, int byte_size)
        }
 }
 
-static void event__all64_swap(event_t *self)
+static void perf_event__all64_swap(union perf_event *event)
 {
-       struct perf_event_header *hdr = &self->header;
-       mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr));
+       struct perf_event_header *hdr = &event->header;
+       mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr));
 }
 
-static void event__comm_swap(event_t *self)
+static void perf_event__comm_swap(union perf_event *event)
 {
-       self->comm.pid = bswap_32(self->comm.pid);
-       self->comm.tid = bswap_32(self->comm.tid);
+       event->comm.pid = bswap_32(event->comm.pid);
+       event->comm.tid = bswap_32(event->comm.tid);
 }
 
-static void event__mmap_swap(event_t *self)
+static void perf_event__mmap_swap(union perf_event *event)
 {
-       self->mmap.pid   = bswap_32(self->mmap.pid);
-       self->mmap.tid   = bswap_32(self->mmap.tid);
-       self->mmap.start = bswap_64(self->mmap.start);
-       self->mmap.len   = bswap_64(self->mmap.len);
-       self->mmap.pgoff = bswap_64(self->mmap.pgoff);
+       event->mmap.pid   = bswap_32(event->mmap.pid);
+       event->mmap.tid   = bswap_32(event->mmap.tid);
+       event->mmap.start = bswap_64(event->mmap.start);
+       event->mmap.len   = bswap_64(event->mmap.len);
+       event->mmap.pgoff = bswap_64(event->mmap.pgoff);
 }
 
-static void event__task_swap(event_t *self)
+static void perf_event__task_swap(union perf_event *event)
 {
-       self->fork.pid  = bswap_32(self->fork.pid);
-       self->fork.tid  = bswap_32(self->fork.tid);
-       self->fork.ppid = bswap_32(self->fork.ppid);
-       self->fork.ptid = bswap_32(self->fork.ptid);
-       self->fork.time = bswap_64(self->fork.time);
+       event->fork.pid  = bswap_32(event->fork.pid);
+       event->fork.tid  = bswap_32(event->fork.tid);
+       event->fork.ppid = bswap_32(event->fork.ppid);
+       event->fork.ptid = bswap_32(event->fork.ptid);
+       event->fork.time = bswap_64(event->fork.time);
 }
 
-static void event__read_swap(event_t *self)
+static void perf_event__read_swap(union perf_event *event)
 {
-       self->read.pid          = bswap_32(self->read.pid);
-       self->read.tid          = bswap_32(self->read.tid);
-       self->read.value        = bswap_64(self->read.value);
-       self->read.time_enabled = bswap_64(self->read.time_enabled);
-       self->read.time_running = bswap_64(self->read.time_running);
-       self->read.id           = bswap_64(self->read.id);
+       event->read.pid          = bswap_32(event->read.pid);
+       event->read.tid          = bswap_32(event->read.tid);
+       event->read.value        = bswap_64(event->read.value);
+       event->read.time_enabled = bswap_64(event->read.time_enabled);
+       event->read.time_running = bswap_64(event->read.time_running);
+       event->read.id           = bswap_64(event->read.id);
 }
 
-static void event__attr_swap(event_t *self)
+static void perf_event__attr_swap(union perf_event *event)
 {
        size_t size;
 
-       self->attr.attr.type            = bswap_32(self->attr.attr.type);
-       self->attr.attr.size            = bswap_32(self->attr.attr.size);
-       self->attr.attr.config          = bswap_64(self->attr.attr.config);
-       self->attr.attr.sample_period   = bswap_64(self->attr.attr.sample_period);
-       self->attr.attr.sample_type     = bswap_64(self->attr.attr.sample_type);
-       self->attr.attr.read_format     = bswap_64(self->attr.attr.read_format);
-       self->attr.attr.wakeup_events   = bswap_32(self->attr.attr.wakeup_events);
-       self->attr.attr.bp_type         = bswap_32(self->attr.attr.bp_type);
-       self->attr.attr.bp_addr         = bswap_64(self->attr.attr.bp_addr);
-       self->attr.attr.bp_len          = bswap_64(self->attr.attr.bp_len);
-
-       size = self->header.size;
-       size -= (void *)&self->attr.id - (void *)self;
-       mem_bswap_64(self->attr.id, size);
+       event->attr.attr.type           = bswap_32(event->attr.attr.type);
+       event->attr.attr.size           = bswap_32(event->attr.attr.size);
+       event->attr.attr.config         = bswap_64(event->attr.attr.config);
+       event->attr.attr.sample_period  = bswap_64(event->attr.attr.sample_period);
+       event->attr.attr.sample_type    = bswap_64(event->attr.attr.sample_type);
+       event->attr.attr.read_format    = bswap_64(event->attr.attr.read_format);
+       event->attr.attr.wakeup_events  = bswap_32(event->attr.attr.wakeup_events);
+       event->attr.attr.bp_type        = bswap_32(event->attr.attr.bp_type);
+       event->attr.attr.bp_addr        = bswap_64(event->attr.attr.bp_addr);
+       event->attr.attr.bp_len         = bswap_64(event->attr.attr.bp_len);
+
+       size = event->header.size;
+       size -= (void *)&event->attr.id - (void *)event;
+       mem_bswap_64(event->attr.id, size);
 }
 
-static void event__event_type_swap(event_t *self)
+static void perf_event__event_type_swap(union perf_event *event)
 {
-       self->event_type.event_type.event_id =
-               bswap_64(self->event_type.event_type.event_id);
+       event->event_type.event_type.event_id =
+               bswap_64(event->event_type.event_type.event_id);
 }
 
-static void event__tracing_data_swap(event_t *self)
+static void perf_event__tracing_data_swap(union perf_event *event)
 {
-       self->tracing_data.size = bswap_32(self->tracing_data.size);
+       event->tracing_data.size = bswap_32(event->tracing_data.size);
 }
 
-typedef void (*event__swap_op)(event_t *self);
-
-static event__swap_op event__swap_ops[] = {
-       [PERF_RECORD_MMAP]   event__mmap_swap,
-       [PERF_RECORD_COMM]   event__comm_swap,
-       [PERF_RECORD_FORK]   event__task_swap,
-       [PERF_RECORD_EXIT]   event__task_swap,
-       [PERF_RECORD_LOST]   event__all64_swap,
-       [PERF_RECORD_READ]   event__read_swap,
-       [PERF_RECORD_SAMPLE] event__all64_swap,
-       [PERF_RECORD_HEADER_ATTR]   event__attr_swap,
-       [PERF_RECORD_HEADER_EVENT_TYPE]   = event__event_type_swap,
-       [PERF_RECORD_HEADER_TRACING_DATA]   = event__tracing_data_swap,
-       [PERF_RECORD_HEADER_BUILD_ID]   = NULL,
-       [PERF_RECORD_HEADER_MAX]    = NULL,
+typedef void (*perf_event__swap_op)(union perf_event *event);
+
+static perf_event__swap_op perf_event__swap_ops[] = {
+       [PERF_RECORD_MMAP]                = perf_event__mmap_swap,
+       [PERF_RECORD_COMM]                = perf_event__comm_swap,
+       [PERF_RECORD_FORK]                = perf_event__task_swap,
+       [PERF_RECORD_EXIT]                = perf_event__task_swap,
+       [PERF_RECORD_LOST]                = perf_event__all64_swap,
+       [PERF_RECORD_READ]                = perf_event__read_swap,
+       [PERF_RECORD_SAMPLE]              = perf_event__all64_swap,
+       [PERF_RECORD_HEADER_ATTR]         = perf_event__attr_swap,
+       [PERF_RECORD_HEADER_EVENT_TYPE]   = perf_event__event_type_swap,
+       [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap,
+       [PERF_RECORD_HEADER_BUILD_ID]     = NULL,
+       [PERF_RECORD_HEADER_MAX]          = NULL,
 };
 
 struct sample_queue {
        u64                     timestamp;
        u64                     file_offset;
-       event_t                 *event;
+       union perf_event        *event;
        struct list_head        list;
 };
 
@@ -472,8 +456,8 @@ static void perf_session_free_sample_buffers(struct perf_session *session)
 }
 
 static int perf_session_deliver_event(struct perf_session *session,
-                                     event_t *event,
-                                     struct sample_data *sample,
+                                     union perf_event *event,
+                                     struct perf_sample *sample,
                                      struct perf_event_ops *ops,
                                      u64 file_offset);
 
@@ -483,7 +467,7 @@ static void flush_sample_queue(struct perf_session *s,
        struct ordered_samples *os = &s->ordered_samples;
        struct list_head *head = &os->samples;
        struct sample_queue *tmp, *iter;
-       struct sample_data sample;
+       struct perf_sample sample;
        u64 limit = os->next_flush;
        u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
 
@@ -494,7 +478,7 @@ static void flush_sample_queue(struct perf_session *s,
                if (iter->timestamp > limit)
                        break;
 
-               event__parse_sample(iter->event, s, &sample);
+               perf_session__parse_sample(s, iter->event, &sample);
                perf_session_deliver_event(s, iter->event, &sample, ops,
                                           iter->file_offset);
 
@@ -550,7 +534,7 @@ static void flush_sample_queue(struct perf_session *s,
  *      Flush every events below timestamp 7
  *      etc...
  */
-static int process_finished_round(event_t *event __used,
+static int process_finished_round(union perf_event *event __used,
                                  struct perf_session *session,
                                  struct perf_event_ops *ops)
 {
@@ -607,12 +591,12 @@ static void __queue_event(struct sample_queue *new, struct perf_session *s)
 
 #define MAX_SAMPLE_BUFFER      (64 * 1024 / sizeof(struct sample_queue))
 
-static int perf_session_queue_event(struct perf_session *s, event_t *event,
-                                   struct sample_data *data, u64 file_offset)
+static int perf_session_queue_event(struct perf_session *s, union perf_event *event,
+                                   struct perf_sample *sample, u64 file_offset)
 {
        struct ordered_samples *os = &s->ordered_samples;
        struct list_head *sc = &os->sample_cache;
-       u64 timestamp = data->time;
+       u64 timestamp = sample->time;
        struct sample_queue *new;
 
        if (!timestamp || timestamp == ~0ULL)
@@ -648,7 +632,7 @@ static int perf_session_queue_event(struct perf_session *s, event_t *event,
        return 0;
 }
 
-static void callchain__printf(struct sample_data *sample)
+static void callchain__printf(struct perf_sample *sample)
 {
        unsigned int i;
 
@@ -660,8 +644,8 @@ static void callchain__printf(struct sample_data *sample)
 }
 
 static void perf_session__print_tstamp(struct perf_session *session,
-                                      event_t *event,
-                                      struct sample_data *sample)
+                                      union perf_event *event,
+                                      struct perf_sample *sample)
 {
        if (event->header.type != PERF_RECORD_SAMPLE &&
            !session->sample_id_all) {
@@ -676,8 +660,8 @@ static void perf_session__print_tstamp(struct perf_session *session,
                printf("%" PRIu64 " ", sample->time);
 }
 
-static void dump_event(struct perf_session *session, event_t *event,
-                      u64 file_offset, struct sample_data *sample)
+static void dump_event(struct perf_session *session, union perf_event *event,
+                      u64 file_offset, struct perf_sample *sample)
 {
        if (!dump_trace)
                return;
@@ -691,11 +675,11 @@ static void dump_event(struct perf_session *session, event_t *event,
                perf_session__print_tstamp(session, event, sample);
 
        printf("%#" PRIx64 " [%#x]: PERF_RECORD_%s", file_offset,
-              event->header.size, event__get_event_name(event->header.type));
+              event->header.size, perf_event__name(event->header.type));
 }
 
-static void dump_sample(struct perf_session *session, event_t *event,
-                       struct sample_data *sample)
+static void dump_sample(struct perf_session *session, union perf_event *event,
+                       struct perf_sample *sample)
 {
        if (!dump_trace)
                return;
@@ -709,8 +693,8 @@ static void dump_sample(struct perf_session *session, event_t *event,
 }
 
 static int perf_session_deliver_event(struct perf_session *session,
-                                     event_t *event,
-                                     struct sample_data *sample,
+                                     union perf_event *event,
+                                     struct perf_sample *sample,
                                      struct perf_event_ops *ops,
                                      u64 file_offset)
 {
@@ -743,7 +727,7 @@ static int perf_session_deliver_event(struct perf_session *session,
 }
 
 static int perf_session__preprocess_sample(struct perf_session *session,
-                                          event_t *event, struct sample_data *sample)
+                                          union perf_event *event, struct perf_sample *sample)
 {
        if (event->header.type != PERF_RECORD_SAMPLE ||
            !(session->sample_type & PERF_SAMPLE_CALLCHAIN))
@@ -758,7 +742,7 @@ static int perf_session__preprocess_sample(struct perf_session *session,
        return 0;
 }
 
-static int perf_session__process_user_event(struct perf_session *session, event_t *event,
+static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
                                            struct perf_event_ops *ops, u64 file_offset)
 {
        dump_event(session, event, file_offset, NULL);
@@ -783,15 +767,16 @@ static int perf_session__process_user_event(struct perf_session *session, event_
 }
 
 static int perf_session__process_event(struct perf_session *session,
-                                      event_t *event,
+                                      union perf_event *event,
                                       struct perf_event_ops *ops,
                                       u64 file_offset)
 {
-       struct sample_data sample;
+       struct perf_sample sample;
        int ret;
 
-       if (session->header.needs_swap && event__swap_ops[event->header.type])
-               event__swap_ops[event->header.type](event);
+       if (session->header.needs_swap &&
+           perf_event__swap_ops[event->header.type])
+               perf_event__swap_ops[event->header.type](event);
 
        if (event->header.type >= PERF_RECORD_HEADER_MAX)
                return -EINVAL;
@@ -804,7 +789,7 @@ static int perf_session__process_event(struct perf_session *session,
        /*
         * For all kernel events we get the sample data
         */
-       event__parse_sample(event, session, &sample);
+       perf_session__parse_sample(session, event, &sample);
 
        /* Preprocess sample records - precheck callchains */
        if (perf_session__preprocess_sample(session, event, &sample))
@@ -843,7 +828,7 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se
 static void perf_session__warn_about_errors(const struct perf_session *session,
                                            const struct perf_event_ops *ops)
 {
-       if (ops->lost == event__process_lost &&
+       if (ops->lost == perf_event__process_lost &&
            session->hists.stats.total_lost != 0) {
                ui__warning("Processed %" PRIu64 " events and LOST %" PRIu64
                            "!\n\nCheck IO/CPU overload!\n\n",
@@ -875,7 +860,7 @@ volatile int session_done;
 static int __perf_session__process_pipe_events(struct perf_session *self,
                                               struct perf_event_ops *ops)
 {
-       event_t event;
+       union perf_event event;
        uint32_t size;
        int skip = 0;
        u64 head;
@@ -956,7 +941,7 @@ int __perf_session__process_events(struct perf_session *session,
        struct ui_progress *progress;
        size_t  page_size, mmap_size;
        char *buf, *mmaps[8];
-       event_t *event;
+       union perf_event *event;
        uint32_t size;
 
        perf_event_ops__fill_defaults(ops);
@@ -1001,7 +986,7 @@ remap:
        file_pos = file_offset + head;
 
 more:
-       event = (event_t *)(buf + head);
+       event = (union perf_event *)(buf + head);
 
        if (session->header.needs_swap)
                perf_event_header__bswap(&event->header);
@@ -1134,3 +1119,18 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
        size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits);
        return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits);
 }
+
+size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
+{
+       struct perf_evsel *pos;
+       size_t ret = fprintf(fp, "Aggregated stats:\n");
+
+       ret += hists__fprintf_nr_events(&session->hists, fp);
+
+       list_for_each_entry(pos, &session->evlist->entries, node) {
+               ret += fprintf(fp, "%s stats:\n", event_name(pos));
+               ret += hists__fprintf_nr_events(&pos->hists, fp);
+       }
+
+       return ret;
+}
index decd83f..b5b148b 100644 (file)
@@ -34,12 +34,12 @@ struct perf_session {
        struct thread           *last_match;
        struct machine          host_machine;
        struct rb_root          machines;
-       struct rb_root          hists_tree;
+       struct perf_evlist      *evlist;
        /*
-        * FIXME: should point to the first entry in hists_tree and
-        *        be a hists instance. Right now its only 'report'
-        *        that is using ->hists_tree while all the rest use
-        *        ->hists.
+        * FIXME: Need to split this up further, we need global
+        *        stats + per event stats. 'perf diff' also needs
+        *        to properly support multiple events in a single
+        *        perf.data file.
         */
        struct hists            hists;
        u64                     sample_type;
@@ -51,15 +51,17 @@ struct perf_session {
        int                     cwdlen;
        char                    *cwd;
        struct ordered_samples  ordered_samples;
-       char filename[0];
+       struct callchain_cursor callchain_cursor;
+       char                    filename[0];
 };
 
 struct perf_event_ops;
 
-typedef int (*event_op)(event_t *self, struct sample_data *sample,
+typedef int (*event_op)(union perf_event *self, struct perf_sample *sample,
                        struct perf_session *session);
-typedef int (*event_synth_op)(event_t *self, struct perf_session *session);
-typedef int (*event_op2)(event_t *self, struct perf_session *session,
+typedef int (*event_synth_op)(union perf_event *self,
+                             struct perf_session *session);
+typedef int (*event_op2)(union perf_event *self, struct perf_session *session,
                         struct perf_event_ops *ops);
 
 struct perf_event_ops {
@@ -94,10 +96,10 @@ int __perf_session__process_events(struct perf_session *self,
 int perf_session__process_events(struct perf_session *self,
                                 struct perf_event_ops *event_ops);
 
-struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
-                                                  struct thread *thread,
-                                                  struct ip_callchain *chain,
-                                                  struct symbol **parent);
+int perf_session__resolve_callchain(struct perf_session *self,
+                                   struct thread *thread,
+                                   struct ip_callchain *chain,
+                                   struct symbol **parent);
 
 bool perf_session__has_traces(struct perf_session *self, const char *msg);
 
@@ -110,8 +112,6 @@ void mem_bswap_64(void *src, int byte_size);
 int perf_session__create_kernel_maps(struct perf_session *self);
 
 void perf_session__update_sample_type(struct perf_session *self);
-void perf_session__set_sample_id_all(struct perf_session *session, bool value);
-void perf_session__set_sample_type(struct perf_session *session, u64 type);
 void perf_session__remove_thread(struct perf_session *self, struct thread *th);
 
 static inline
@@ -149,9 +149,14 @@ size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp);
 size_t perf_session__fprintf_dsos_buildid(struct perf_session *self,
                                          FILE *fp, bool with_hits);
 
-static inline
-size_t perf_session__fprintf_nr_events(struct perf_session *self, FILE *fp)
+size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
+
+static inline int perf_session__parse_sample(struct perf_session *session,
+                                            const union perf_event *event,
+                                            struct perf_sample *sample)
 {
-       return hists__fprintf_nr_events(&self->hists, fp);
+       return perf_event__parse_sample(event, session->sample_type,
+                                       session->sample_id_all, sample);
 }
+
 #endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py
new file mode 100644 (file)
index 0000000..e24ffad
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/python2
+
+from distutils.core import setup, Extension
+
+perf = Extension('perf',
+                 sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c',
+                            'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c',
+                            'util/util.c', 'util/xyarray.c', 'util/cgroup.c'],
+                 include_dirs = ['util/include'],
+                 extra_compile_args = ['-fno-strict-aliasing', '-Wno-write-strings'])
+
+setup(name='perf',
+      version='0.1',
+      description='Interface with the Linux profiling infrastructure',
+      author='Arnaldo Carvalho de Melo',
+      author_email='acme@redhat.com',
+      license='GPLv2',
+      url='http://perf.wiki.kernel.org',
+      ext_modules=[perf])
diff --git a/tools/perf/util/strfilter.c b/tools/perf/util/strfilter.c
new file mode 100644 (file)
index 0000000..834c8eb
--- /dev/null
@@ -0,0 +1,199 @@
+#include "util.h"
+#include "string.h"
+#include "strfilter.h"
+
+/* Operators */
+static const char *OP_and      = "&";  /* Logical AND */
+static const char *OP_or       = "|";  /* Logical OR */
+static const char *OP_not      = "!";  /* Logical NOT */
+
+#define is_operator(c) ((c) == '|' || (c) == '&' || (c) == '!')
+#define is_separator(c)        (is_operator(c) || (c) == '(' || (c) == ')')
+
+static void strfilter_node__delete(struct strfilter_node *self)
+{
+       if (self) {
+               if (self->p && !is_operator(*self->p))
+                       free((char *)self->p);
+               strfilter_node__delete(self->l);
+               strfilter_node__delete(self->r);
+               free(self);
+       }
+}
+
+void strfilter__delete(struct strfilter *self)
+{
+       if (self) {
+               strfilter_node__delete(self->root);
+               free(self);
+       }
+}
+
+static const char *get_token(const char *s, const char **e)
+{
+       const char *p;
+
+       while (isspace(*s))     /* Skip spaces */
+               s++;
+
+       if (*s == '\0') {
+               p = s;
+               goto end;
+       }
+
+       p = s + 1;
+       if (!is_separator(*s)) {
+               /* End search */
+retry:
+               while (*p && !is_separator(*p) && !isspace(*p))
+                       p++;
+               /* Escape and special case: '!' is also used in glob pattern */
+               if (*(p - 1) == '\\' || (*p == '!' && *(p - 1) == '[')) {
+                       p++;
+                       goto retry;
+               }
+       }
+end:
+       *e = p;
+       return s;
+}
+
+static struct strfilter_node *strfilter_node__alloc(const char *op,
+                                                   struct strfilter_node *l,
+                                                   struct strfilter_node *r)
+{
+       struct strfilter_node *ret = zalloc(sizeof(struct strfilter_node));
+
+       if (ret) {
+               ret->p = op;
+               ret->l = l;
+               ret->r = r;
+       }
+
+       return ret;
+}
+
+static struct strfilter_node *strfilter_node__new(const char *s,
+                                                 const char **ep)
+{
+       struct strfilter_node root, *cur, *last_op;
+       const char *e;
+
+       if (!s)
+               return NULL;
+
+       memset(&root, 0, sizeof(root));
+       last_op = cur = &root;
+
+       s = get_token(s, &e);
+       while (*s != '\0' && *s != ')') {
+               switch (*s) {
+               case '&':       /* Exchg last OP->r with AND */
+                       if (!cur->r || !last_op->r)
+                               goto error;
+                       cur = strfilter_node__alloc(OP_and, last_op->r, NULL);
+                       if (!cur)
+                               goto nomem;
+                       last_op->r = cur;
+                       last_op = cur;
+                       break;
+               case '|':       /* Exchg the root with OR */
+                       if (!cur->r || !root.r)
+                               goto error;
+                       cur = strfilter_node__alloc(OP_or, root.r, NULL);
+                       if (!cur)
+                               goto nomem;
+                       root.r = cur;
+                       last_op = cur;
+                       break;
+               case '!':       /* Add NOT as a leaf node */
+                       if (cur->r)
+                               goto error;
+                       cur->r = strfilter_node__alloc(OP_not, NULL, NULL);
+                       if (!cur->r)
+                               goto nomem;
+                       cur = cur->r;
+                       break;
+               case '(':       /* Recursively parses inside the parenthesis */
+                       if (cur->r)
+                               goto error;
+                       cur->r = strfilter_node__new(s + 1, &s);
+                       if (!s)
+                               goto nomem;
+                       if (!cur->r || *s != ')')
+                               goto error;
+                       e = s + 1;
+                       break;
+               default:
+                       if (cur->r)
+                               goto error;
+                       cur->r = strfilter_node__alloc(NULL, NULL, NULL);
+                       if (!cur->r)
+                               goto nomem;
+                       cur->r->p = strndup(s, e - s);
+                       if (!cur->r->p)
+                               goto nomem;
+               }
+               s = get_token(e, &e);
+       }
+       if (!cur->r)
+               goto error;
+       *ep = s;
+       return root.r;
+nomem:
+       s = NULL;
+error:
+       *ep = s;
+       strfilter_node__delete(root.r);
+       return NULL;
+}
+
+/*
+ * Parse filter rule and return new strfilter.
+ * Return NULL if fail, and *ep == NULL if memory allocation failed.
+ */
+struct strfilter *strfilter__new(const char *rules, const char **err)
+{
+       struct strfilter *ret = zalloc(sizeof(struct strfilter));
+       const char *ep = NULL;
+
+       if (ret)
+               ret->root = strfilter_node__new(rules, &ep);
+
+       if (!ret || !ret->root || *ep != '\0') {
+               if (err)
+                       *err = ep;
+               strfilter__delete(ret);
+               ret = NULL;
+       }
+
+       return ret;
+}
+
+static bool strfilter_node__compare(struct strfilter_node *self,
+                                   const char *str)
+{
+       if (!self || !self->p)
+               return false;
+
+       switch (*self->p) {
+       case '|':       /* OR */
+               return strfilter_node__compare(self->l, str) ||
+                       strfilter_node__compare(self->r, str);
+       case '&':       /* AND */
+               return strfilter_node__compare(self->l, str) &&
+                       strfilter_node__compare(self->r, str);
+       case '!':       /* NOT */
+               return !strfilter_node__compare(self->r, str);
+       default:
+               return strglobmatch(str, self->p);
+       }
+}
+
+/* Return true if STR matches the filter rules */
+bool strfilter__compare(struct strfilter *self, const char *str)
+{
+       if (!self)
+               return false;
+       return strfilter_node__compare(self->root, str);
+}
diff --git a/tools/perf/util/strfilter.h b/tools/perf/util/strfilter.h
new file mode 100644 (file)
index 0000000..00f58a7
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef __PERF_STRFILTER_H
+#define __PERF_STRFILTER_H
+/* General purpose glob matching filter */
+
+#include <linux/list.h>
+#include <stdbool.h>
+
+/* A node of string filter */
+struct strfilter_node {
+       struct strfilter_node *l;       /* Tree left branche (for &,|) */
+       struct strfilter_node *r;       /* Tree right branche (for !,&,|) */
+       const char *p;          /* Operator or rule */
+};
+
+/* String filter */
+struct strfilter {
+       struct strfilter_node *root;
+};
+
+/**
+ * strfilter__new - Create a new string filter
+ * @rules: Filter rule, which is a combination of glob expressions.
+ * @err: Pointer which points an error detected on @rules
+ *
+ * Parse @rules and return new strfilter. Return NULL if an error detected.
+ * In that case, *@err will indicate where it is detected, and *@err is NULL
+ * if a memory allocation is failed.
+ */
+struct strfilter *strfilter__new(const char *rules, const char **err);
+
+/**
+ * strfilter__compare - compare given string and a string filter
+ * @self: String filter
+ * @str: target string
+ *
+ * Compare @str and @self. Return true if the str match the rule
+ */
+bool strfilter__compare(struct strfilter *self, const char *str);
+
+/**
+ * strfilter__delete - delete a string filter
+ * @self: String filter to delete
+ *
+ * Delete @self.
+ */
+void strfilter__delete(struct strfilter *self);
+
+#endif
index fb737fe..96c8660 100644 (file)
@@ -456,9 +456,9 @@ void svg_legenda(void)
                return;
 
        svg_legenda_box(0,      "Running", "sample");
-       svg_legenda_box(100,    "Idle","rect.c1");
-       svg_legenda_box(200,    "Deeper Idle", "rect.c3");
-       svg_legenda_box(350,    "Deepest Idle", "rect.c6");
+       svg_legenda_box(100,    "Idle","c1");
+       svg_legenda_box(200,    "Deeper Idle", "c3");
+       svg_legenda_box(350,    "Deepest Idle", "c6");
        svg_legenda_box(550,    "Sleeping", "process2");
        svg_legenda_box(650,    "Waiting for cpu", "waiting");
        svg_legenda_box(800,    "Blocked on IO", "blocked");
index 7821d0e..00014e3 100644 (file)
@@ -207,7 +207,6 @@ struct dso *dso__new(const char *name)
                dso__set_short_name(self, self->name);
                for (i = 0; i < MAP__NR_TYPES; ++i)
                        self->symbols[i] = self->symbol_names[i] = RB_ROOT;
-               self->slen_calculated = 0;
                self->origin = DSO__ORIG_NOT_FOUND;
                self->loaded = 0;
                self->sorted_by_name = 0;
@@ -1525,8 +1524,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
                             symbol_conf.symfs, self->long_name);
                        break;
                case DSO__ORIG_GUEST_KMODULE:
-                       if (map->groups && map->groups->machine)
-                               root_dir = map->groups->machine->root_dir;
+                       if (map->groups && machine)
+                               root_dir = machine->root_dir;
                        else
                                root_dir = "";
                        snprintf(name, size, "%s%s%s", symbol_conf.symfs,
@@ -1836,7 +1835,7 @@ int dso__load_vmlinux(struct dso *self, struct map *map,
        int err = -1, fd;
        char symfs_vmlinux[PATH_MAX];
 
-       snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s/%s",
+       snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
                 symbol_conf.symfs, vmlinux);
        fd = open(symfs_vmlinux, O_RDONLY);
        if (fd < 0)
index 670cd1c..4d7ed09 100644 (file)
@@ -132,7 +132,6 @@ struct dso {
        struct rb_root   symbol_names[MAP__NR_TYPES];
        enum dso_kernel_type    kernel;
        u8               adjust_symbols:1;
-       u8               slen_calculated:1;
        u8               has_build_id:1;
        u8               hit:1;
        u8               annotate_warned:1;
index 00f4ead..d5d3b22 100644 (file)
@@ -7,61 +7,6 @@
 #include "util.h"
 #include "debug.h"
 
-/* Skip "." and ".." directories */
-static int filter(const struct dirent *dir)
-{
-       if (dir->d_name[0] == '.')
-               return 0;
-       else
-               return 1;
-}
-
-struct thread_map *thread_map__new_by_pid(pid_t pid)
-{
-       struct thread_map *threads;
-       char name[256];
-       int items;
-       struct dirent **namelist = NULL;
-       int i;
-
-       sprintf(name, "/proc/%d/task", pid);
-       items = scandir(name, &namelist, filter, NULL);
-       if (items <= 0)
-                return NULL;
-
-       threads = malloc(sizeof(*threads) + sizeof(pid_t) * items);
-       if (threads != NULL) {
-               for (i = 0; i < items; i++)
-                       threads->map[i] = atoi(namelist[i]->d_name);
-               threads->nr = items;
-       }
-
-       for (i=0; i<items; i++)
-               free(namelist[i]);
-       free(namelist);
-
-       return threads;
-}
-
-struct thread_map *thread_map__new_by_tid(pid_t tid)
-{
-       struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t));
-
-       if (threads != NULL) {
-               threads->map[0] = tid;
-               threads->nr     = 1;
-       }
-
-       return threads;
-}
-
-struct thread_map *thread_map__new(pid_t pid, pid_t tid)
-{
-       if (pid != -1)
-               return thread_map__new_by_pid(pid);
-       return thread_map__new_by_tid(tid);
-}
-
 static struct thread *thread__new(pid_t pid)
 {
        struct thread *self = zalloc(sizeof(*self));
index d757410..e5f2401 100644 (file)
@@ -18,24 +18,10 @@ struct thread {
        int                     comm_len;
 };
 
-struct thread_map {
-       int nr;
-       int map[];
-};
-
 struct perf_session;
 
 void thread__delete(struct thread *self);
 
-struct thread_map *thread_map__new_by_pid(pid_t pid);
-struct thread_map *thread_map__new_by_tid(pid_t tid);
-struct thread_map *thread_map__new(pid_t pid, pid_t tid);
-
-static inline void thread_map__delete(struct thread_map *threads)
-{
-       free(threads);
-}
-
 int thread__set_comm(struct thread *self, const char *comm);
 int thread__comm_len(struct thread *self);
 struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
new file mode 100644 (file)
index 0000000..a5df131
--- /dev/null
@@ -0,0 +1,64 @@
+#include <dirent.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "thread_map.h"
+
+/* Skip "." and ".." directories */
+static int filter(const struct dirent *dir)
+{
+       if (dir->d_name[0] == '.')
+               return 0;
+       else
+               return 1;
+}
+
+struct thread_map *thread_map__new_by_pid(pid_t pid)
+{
+       struct thread_map *threads;
+       char name[256];
+       int items;
+       struct dirent **namelist = NULL;
+       int i;
+
+       sprintf(name, "/proc/%d/task", pid);
+       items = scandir(name, &namelist, filter, NULL);
+       if (items <= 0)
+                return NULL;
+
+       threads = malloc(sizeof(*threads) + sizeof(pid_t) * items);
+       if (threads != NULL) {
+               for (i = 0; i < items; i++)
+                       threads->map[i] = atoi(namelist[i]->d_name);
+               threads->nr = items;
+       }
+
+       for (i=0; i<items; i++)
+               free(namelist[i]);
+       free(namelist);
+
+       return threads;
+}
+
+struct thread_map *thread_map__new_by_tid(pid_t tid)
+{
+       struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t));
+
+       if (threads != NULL) {
+               threads->map[0] = tid;
+               threads->nr     = 1;
+       }
+
+       return threads;
+}
+
+struct thread_map *thread_map__new(pid_t pid, pid_t tid)
+{
+       if (pid != -1)
+               return thread_map__new_by_pid(pid);
+       return thread_map__new_by_tid(tid);
+}
+
+void thread_map__delete(struct thread_map *threads)
+{
+       free(threads);
+}
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
new file mode 100644 (file)
index 0000000..3cb9073
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __PERF_THREAD_MAP_H
+#define __PERF_THREAD_MAP_H
+
+#include <sys/types.h>
+
+struct thread_map {
+       int nr;
+       int map[];
+};
+
+struct thread_map *thread_map__new_by_pid(pid_t pid);
+struct thread_map *thread_map__new_by_tid(pid_t tid);
+struct thread_map *thread_map__new(pid_t pid, pid_t tid);
+void thread_map__delete(struct thread_map *threads);
+#endif /* __PERF_THREAD_MAP_H */
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
new file mode 100644 (file)
index 0000000..75cfe4d
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
+ *
+ * Refactored from builtin-top.c, see that files for further copyright notes.
+ *
+ * Released under the GPL v2. (and only v2, not any later version)
+ */
+
+#include "cpumap.h"
+#include "event.h"
+#include "evlist.h"
+#include "evsel.h"
+#include "parse-events.h"
+#include "symbol.h"
+#include "top.h"
+#include <inttypes.h>
+
+/*
+ * Ordering weight: count-1 * count-2 * ... / count-n
+ */
+static double sym_weight(const struct sym_entry *sym, struct perf_top *top)
+{
+       double weight = sym->snap_count;
+       int counter;
+
+       if (!top->display_weighted)
+               return weight;
+
+       for (counter = 1; counter < top->evlist->nr_entries - 1; counter++)
+               weight *= sym->count[counter];
+
+       weight /= (sym->count[counter] + 1);
+
+       return weight;
+}
+
+static void perf_top__remove_active_sym(struct perf_top *top, struct sym_entry *syme)
+{
+       pthread_mutex_lock(&top->active_symbols_lock);
+       list_del_init(&syme->node);
+       pthread_mutex_unlock(&top->active_symbols_lock);
+}
+
+static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
+{
+       struct rb_node **p = &tree->rb_node;
+       struct rb_node *parent = NULL;
+       struct sym_entry *iter;
+
+       while (*p != NULL) {
+               parent = *p;
+               iter = rb_entry(parent, struct sym_entry, rb_node);
+
+               if (se->weight > iter->weight)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
+       }
+
+       rb_link_node(&se->rb_node, parent, p);
+       rb_insert_color(&se->rb_node, tree);
+}
+
+#define SNPRINTF(buf, size, fmt, args...) \
+({ \
+       size_t r = snprintf(buf, size, fmt, ## args); \
+       r > size ?  size : r; \
+})
+
+size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
+{
+       struct perf_evsel *counter;
+       float samples_per_sec = top->samples / top->delay_secs;
+       float ksamples_per_sec = top->kernel_samples / top->delay_secs;
+       float esamples_percent = (100.0 * top->exact_samples) / top->samples;
+       size_t ret = 0;
+
+       if (!perf_guest) {
+               ret = SNPRINTF(bf, size,
+                              "   PerfTop:%8.0f irqs/sec  kernel:%4.1f%%"
+                              "  exact: %4.1f%% [", samples_per_sec,
+                              100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) /
+                                       samples_per_sec)),
+                               esamples_percent);
+       } else {
+               float us_samples_per_sec = top->us_samples / top->delay_secs;
+               float guest_kernel_samples_per_sec = top->guest_kernel_samples / top->delay_secs;
+               float guest_us_samples_per_sec = top->guest_us_samples / top->delay_secs;
+
+               ret = SNPRINTF(bf, size,
+                              "   PerfTop:%8.0f irqs/sec  kernel:%4.1f%% us:%4.1f%%"
+                              " guest kernel:%4.1f%% guest us:%4.1f%%"
+                              " exact: %4.1f%% [", samples_per_sec,
+                              100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) /
+                                                samples_per_sec)),
+                              100.0 - (100.0 * ((samples_per_sec - us_samples_per_sec) /
+                                                samples_per_sec)),
+                              100.0 - (100.0 * ((samples_per_sec -
+                                                 guest_kernel_samples_per_sec) /
+                                                samples_per_sec)),
+                              100.0 - (100.0 * ((samples_per_sec -
+                                                 guest_us_samples_per_sec) /
+                                                samples_per_sec)),
+                              esamples_percent);
+       }
+
+       if (top->evlist->nr_entries == 1 || !top->display_weighted) {
+               struct perf_evsel *first;
+               first = list_entry(top->evlist->entries.next, struct perf_evsel, node);
+               ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ",
+                               (uint64_t)first->attr.sample_period,
+                               top->freq ? "Hz" : "");
+       }
+
+       if (!top->display_weighted) {
+               ret += SNPRINTF(bf + ret, size - ret, "%s",
+                               event_name(top->sym_evsel));
+       } else {
+               /*
+                * Don't let events eat all the space. Leaving 30 bytes
+                * for the rest should be enough.
+                */
+               size_t last_pos = size - 30;
+
+               list_for_each_entry(counter, &top->evlist->entries, node) {
+                       ret += SNPRINTF(bf + ret, size - ret, "%s%s",
+                                       counter->idx ? "/" : "",
+                                       event_name(counter));
+                       if (ret > last_pos) {
+                               sprintf(bf + last_pos - 3, "..");
+                               ret = last_pos - 1;
+                               break;
+                       }
+               }
+       }
+
+       ret += SNPRINTF(bf + ret, size - ret, "], ");
+
+       if (top->target_pid != -1)
+               ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %d",
+                               top->target_pid);
+       else if (top->target_tid != -1)
+               ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %d",
+                               top->target_tid);
+       else
+               ret += SNPRINTF(bf + ret, size - ret, " (all");
+
+       if (top->cpu_list)
+               ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)",
+                               top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list);
+       else {
+               if (top->target_tid != -1)
+                       ret += SNPRINTF(bf + ret, size - ret, ")");
+               else
+                       ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)",
+                                       top->evlist->cpus->nr,
+                                       top->evlist->cpus->nr > 1 ? "s" : "");
+       }
+
+       return ret;
+}
+
+void perf_top__reset_sample_counters(struct perf_top *top)
+{
+       top->samples = top->us_samples = top->kernel_samples =
+       top->exact_samples = top->guest_kernel_samples =
+       top->guest_us_samples = 0;
+}
+
+float perf_top__decay_samples(struct perf_top *top, struct rb_root *root)
+{
+       struct sym_entry *syme, *n;
+       float sum_ksamples = 0.0;
+       int snap = !top->display_weighted ? top->sym_counter : 0, j;
+
+       /* Sort the active symbols */
+       pthread_mutex_lock(&top->active_symbols_lock);
+       syme = list_entry(top->active_symbols.next, struct sym_entry, node);
+       pthread_mutex_unlock(&top->active_symbols_lock);
+
+       top->rb_entries = 0;
+       list_for_each_entry_safe_from(syme, n, &top->active_symbols, node) {
+               syme->snap_count = syme->count[snap];
+               if (syme->snap_count != 0) {
+
+                       if ((top->hide_user_symbols &&
+                            syme->origin == PERF_RECORD_MISC_USER) ||
+                           (top->hide_kernel_symbols &&
+                            syme->origin == PERF_RECORD_MISC_KERNEL)) {
+                               perf_top__remove_active_sym(top, syme);
+                               continue;
+                       }
+                       syme->weight = sym_weight(syme, top);
+
+                       if ((int)syme->snap_count >= top->count_filter) {
+                               rb_insert_active_sym(root, syme);
+                               ++top->rb_entries;
+                       }
+                       sum_ksamples += syme->snap_count;
+
+                       for (j = 0; j < top->evlist->nr_entries; j++)
+                               syme->count[j] = top->zero ? 0 : syme->count[j] * 7 / 8;
+               } else
+                       perf_top__remove_active_sym(top, syme);
+       }
+
+       return sum_ksamples;
+}
+
+/*
+ * Find the longest symbol name that will be displayed
+ */
+void perf_top__find_widths(struct perf_top *top, struct rb_root *root,
+                          int *dso_width, int *dso_short_width, int *sym_width)
+{
+       struct rb_node *nd;
+       int printed = 0;
+
+       *sym_width = *dso_width = *dso_short_width = 0;
+
+       for (nd = rb_first(root); nd; nd = rb_next(nd)) {
+               struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node);
+               struct symbol *sym = sym_entry__symbol(syme);
+
+               if (++printed > top->print_entries ||
+                   (int)syme->snap_count < top->count_filter)
+                       continue;
+
+               if (syme->map->dso->long_name_len > *dso_width)
+                       *dso_width = syme->map->dso->long_name_len;
+
+               if (syme->map->dso->short_name_len > *dso_short_width)
+                       *dso_short_width = syme->map->dso->short_name_len;
+
+               if (sym->namelen > *sym_width)
+                       *sym_width = sym->namelen;
+       }
+}
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
new file mode 100644 (file)
index 0000000..96d1cb7
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef __PERF_TOP_H
+#define __PERF_TOP_H 1
+
+#include "types.h"
+#include "../perf.h"
+#include <stddef.h>
+#include <pthread.h>
+#include <linux/list.h>
+#include <linux/rbtree.h>
+
+struct perf_evlist;
+struct perf_evsel;
+
+struct sym_entry {
+       struct rb_node          rb_node;
+       struct list_head        node;
+       unsigned long           snap_count;
+       double                  weight;
+       int                     skip;
+       u8                      origin;
+       struct map              *map;
+       unsigned long           count[0];
+};
+
+static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
+{
+       return ((void *)self) + symbol_conf.priv_size;
+}
+
+struct perf_top {
+       struct perf_evlist *evlist;
+       /*
+        * Symbols will be added here in perf_event__process_sample and will
+        * get out after decayed.
+        */
+       struct list_head   active_symbols;
+       pthread_mutex_t    active_symbols_lock;
+       pthread_cond_t     active_symbols_cond;
+       u64                samples;
+       u64                kernel_samples, us_samples;
+       u64                exact_samples;
+       u64                guest_us_samples, guest_kernel_samples;
+       int                print_entries, count_filter, delay_secs;
+       int                display_weighted, freq, rb_entries, sym_counter;
+       pid_t              target_pid, target_tid;
+       bool               hide_kernel_symbols, hide_user_symbols, zero;
+       const char         *cpu_list;
+       struct sym_entry   *sym_filter_entry;
+       struct perf_evsel  *sym_evsel;
+};
+
+size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
+void perf_top__reset_sample_counters(struct perf_top *top);
+float perf_top__decay_samples(struct perf_top *top, struct rb_root *root);
+void perf_top__find_widths(struct perf_top *top, struct rb_root *root,
+                          int *dso_width, int *dso_short_width, int *sym_width);
+
+#ifdef NO_NEWT_SUPPORT
+static inline int perf_top__tui_browser(struct perf_top *top __used)
+{
+       return 0;
+}
+#else
+int perf_top__tui_browser(struct perf_top *top);
+#endif
+#endif /* __PERF_TOP_H */
index 73a0222..d8e622d 100644 (file)
@@ -153,7 +153,7 @@ void parse_proc_kallsyms(char *file, unsigned int size __unused)
        char *next = NULL;
        char *addr_str;
        char ch;
-       int ret;
+       int ret __used;
        int i;
 
        line = strtok_r(file, "\n", &next);
index 8bc010e..611219f 100644 (file)
@@ -1,4 +1,5 @@
 #include "libslang.h"
+#include "ui.h"
 #include <linux/compiler.h>
 #include <linux/list.h>
 #include <linux/rbtree.h>
@@ -156,6 +157,20 @@ void ui_browser__add_exit_keys(struct ui_browser *self, int keys[])
        }
 }
 
+void __ui_browser__show_title(struct ui_browser *browser, const char *title)
+{
+       SLsmg_gotorc(0, 0);
+       ui_browser__set_color(browser, NEWT_COLORSET_ROOT);
+       slsmg_write_nstring(title, browser->width);
+}
+
+void ui_browser__show_title(struct ui_browser *browser, const char *title)
+{
+       pthread_mutex_lock(&ui__lock);
+       __ui_browser__show_title(browser, title);
+       pthread_mutex_unlock(&ui__lock);
+}
+
 int ui_browser__show(struct ui_browser *self, const char *title,
                     const char *helpline, ...)
 {
@@ -178,9 +193,8 @@ int ui_browser__show(struct ui_browser *self, const char *title,
        if (self->sb == NULL)
                return -1;
 
-       SLsmg_gotorc(0, 0);
-       ui_browser__set_color(self, NEWT_COLORSET_ROOT);
-       slsmg_write_nstring(title, self->width);
+       pthread_mutex_lock(&ui__lock);
+       __ui_browser__show_title(self, title);
 
        ui_browser__add_exit_keys(self, keys);
        newtFormAddComponent(self->form, self->sb);
@@ -188,25 +202,30 @@ int ui_browser__show(struct ui_browser *self, const char *title,
        va_start(ap, helpline);
        ui_helpline__vpush(helpline, ap);
        va_end(ap);
+       pthread_mutex_unlock(&ui__lock);
        return 0;
 }
 
 void ui_browser__hide(struct ui_browser *self)
 {
+       pthread_mutex_lock(&ui__lock);
        newtFormDestroy(self->form);
        self->form = NULL;
        ui_helpline__pop();
+       pthread_mutex_unlock(&ui__lock);
 }
 
 int ui_browser__refresh(struct ui_browser *self)
 {
        int row;
 
+       pthread_mutex_lock(&ui__lock);
        newtScrollbarSet(self->sb, self->index, self->nr_entries - 1);
        row = self->refresh(self);
        ui_browser__set_color(self, HE_COLORSET_NORMAL);
        SLsmg_fill_region(self->y + row, self->x,
                          self->height - row, self->width, ' ');
+       pthread_mutex_unlock(&ui__lock);
 
        return 0;
 }
index 0dc7e4d..fc63dda 100644 (file)
@@ -24,7 +24,6 @@ struct ui_browser {
        u32           nr_entries;
 };
 
-
 void ui_browser__set_color(struct ui_browser *self, int color);
 void ui_browser__set_percent_color(struct ui_browser *self,
                                   double percent, bool current);
@@ -35,6 +34,8 @@ void ui_browser__reset_index(struct ui_browser *self);
 void ui_browser__gotorc(struct ui_browser *self, int y, int x);
 void ui_browser__add_exit_key(struct ui_browser *self, int key);
 void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]);
+void __ui_browser__show_title(struct ui_browser *browser, const char *title);
+void ui_browser__show_title(struct ui_browser *browser, const char *title);
 int ui_browser__show(struct ui_browser *self, const char *title,
                     const char *helpline, ...);
 void ui_browser__hide(struct ui_browser *self);
index 82b78f9..8c17a87 100644 (file)
@@ -1,9 +1,12 @@
 #include "../browser.h"
 #include "../helpline.h"
 #include "../libslang.h"
+#include "../../annotate.h"
 #include "../../hist.h"
 #include "../../sort.h"
 #include "../../symbol.h"
+#include "../../annotate.h"
+#include <pthread.h>
 
 static void ui__error_window(const char *fmt, ...)
 {
@@ -42,8 +45,6 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
                struct objdump_line_rb_node *olrb = objdump_line__rb(ol);
                ui_browser__set_percent_color(self, olrb->percent, current_entry);
                slsmg_printf(" %7.2f ", olrb->percent);
-               if (!current_entry)
-                       ui_browser__set_color(self, HE_COLORSET_CODE);
        } else {
                ui_browser__set_percent_color(self, 0, current_entry);
                slsmg_write_nstring(" ", 9);
@@ -55,35 +56,40 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
                slsmg_write_nstring(" ", width - 18);
        else
                slsmg_write_nstring(ol->line, width - 18);
+
+       if (!current_entry)
+               ui_browser__set_color(self, HE_COLORSET_CODE);
 }
 
 static double objdump_line__calc_percent(struct objdump_line *self,
-                                        struct list_head *head,
-                                        struct symbol *sym)
+                                        struct symbol *sym, int evidx)
 {
        double percent = 0.0;
 
        if (self->offset != -1) {
                int len = sym->end - sym->start;
                unsigned int hits = 0;
-               struct sym_priv *priv = symbol__priv(sym);
-               struct sym_ext *sym_ext = priv->ext;
-               struct sym_hist *h = priv->hist;
+               struct annotation *notes = symbol__annotation(sym);
+               struct source_line *src_line = notes->src->lines;
+               struct sym_hist *h = annotation__histogram(notes, evidx);
                s64 offset = self->offset;
-               struct objdump_line *next = objdump__get_next_ip_line(head, self);
-
+               struct objdump_line *next;
 
+               next = objdump__get_next_ip_line(&notes->src->source, self);
                while (offset < (s64)len &&
                       (next == NULL || offset < next->offset)) {
-                       if (sym_ext) {
-                               percent += sym_ext[offset].percent;
+                       if (src_line) {
+                               percent += src_line[offset].percent;
                        } else
-                               hits += h->ip[offset];
+                               hits += h->addr[offset];
 
                        ++offset;
                }
-
-               if (sym_ext == NULL && h->sum)
+               /*
+                * If the percentage wasn't already calculated in
+                * symbol__get_source_line, do it now:
+                */
+               if (src_line == NULL && h->sum)
                        percent = 100.0 * hits / h->sum;
        }
 
@@ -133,103 +139,161 @@ static void annotate_browser__set_top(struct annotate_browser *self,
        self->curr_hot = nd;
 }
 
-static int annotate_browser__run(struct annotate_browser *self)
+static void annotate_browser__calc_percent(struct annotate_browser *browser,
+                                          int evidx)
 {
-       struct rb_node *nd;
-       struct hist_entry *he = self->b.priv;
-       int key;
+       struct symbol *sym = browser->b.priv;
+       struct annotation *notes = symbol__annotation(sym);
+       struct objdump_line *pos;
 
-       if (ui_browser__show(&self->b, he->ms.sym->name,
-                            "<-, -> or ESC: exit, TAB/shift+TAB: cycle thru samples") < 0)
-               return -1;
+       browser->entries = RB_ROOT;
+
+       pthread_mutex_lock(&notes->lock);
+
+       list_for_each_entry(pos, &notes->src->source, node) {
+               struct objdump_line_rb_node *rbpos = objdump_line__rb(pos);
+               rbpos->percent = objdump_line__calc_percent(pos, sym, evidx);
+               if (rbpos->percent < 0.01) {
+                       RB_CLEAR_NODE(&rbpos->rb_node);
+                       continue;
+               }
+               objdump__insert_line(&browser->entries, rbpos);
+       }
+       pthread_mutex_unlock(&notes->lock);
+
+       browser->curr_hot = rb_last(&browser->entries);
+}
+
+static int annotate_browser__run(struct annotate_browser *self, int evidx,
+                                int refresh)
+{
+       struct rb_node *nd = NULL;
+       struct symbol *sym = self->b.priv;
        /*
-        * To allow builtin-annotate to cycle thru multiple symbols by
+        * RIGHT To allow builtin-annotate to cycle thru multiple symbols by
         * examining the exit key for this function.
         */
-       ui_browser__add_exit_key(&self->b, NEWT_KEY_RIGHT);
+       int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB,
+                           NEWT_KEY_RIGHT, 0 };
+       int key;
+
+       if (ui_browser__show(&self->b, sym->name,
+                            "<-, -> or ESC: exit, TAB/shift+TAB: "
+                            "cycle hottest lines, H: Hottest") < 0)
+               return -1;
+
+       ui_browser__add_exit_keys(&self->b, exit_keys);
+       annotate_browser__calc_percent(self, evidx);
+
+       if (self->curr_hot)
+               annotate_browser__set_top(self, self->curr_hot);
 
        nd = self->curr_hot;
-       if (nd) {
-               int tabs[] = { NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0 };
-               ui_browser__add_exit_keys(&self->b, tabs);
-       }
+
+       if (refresh != 0)
+               newtFormSetTimer(self->b.form, refresh);
 
        while (1) {
                key = ui_browser__run(&self->b);
 
+               if (refresh != 0) {
+                       annotate_browser__calc_percent(self, evidx);
+                       /*
+                        * Current line focus got out of the list of most active
+                        * lines, NULL it so that if TAB|UNTAB is pressed, we
+                        * move to curr_hot (current hottest line).
+                        */
+                       if (nd != NULL && RB_EMPTY_NODE(nd))
+                               nd = NULL;
+               }
+
                switch (key) {
+               case -1:
+                       /*
+                        * FIXME we need to check if it was
+                        * es.reason == NEWT_EXIT_TIMER
+                        */
+                       if (refresh != 0)
+                               symbol__annotate_decay_histogram(sym, evidx);
+                       continue;
                case NEWT_KEY_TAB:
-                       nd = rb_prev(nd);
-                       if (nd == NULL)
-                               nd = rb_last(&self->entries);
-                       annotate_browser__set_top(self, nd);
+                       if (nd != NULL) {
+                               nd = rb_prev(nd);
+                               if (nd == NULL)
+                                       nd = rb_last(&self->entries);
+                       } else
+                               nd = self->curr_hot;
                        break;
                case NEWT_KEY_UNTAB:
-                       nd = rb_next(nd);
-                       if (nd == NULL)
-                               nd = rb_first(&self->entries);
-                       annotate_browser__set_top(self, nd);
+                       if (nd != NULL)
+                               nd = rb_next(nd);
+                               if (nd == NULL)
+                                       nd = rb_first(&self->entries);
+                       else
+                               nd = self->curr_hot;
+                       break;
+               case 'H':
+                       nd = self->curr_hot;
                        break;
                default:
                        goto out;
                }
+
+               if (nd != NULL)
+                       annotate_browser__set_top(self, nd);
        }
 out:
        ui_browser__hide(&self->b);
        return key;
 }
 
-int hist_entry__tui_annotate(struct hist_entry *self)
+int hist_entry__tui_annotate(struct hist_entry *he, int evidx)
+{
+       return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, 0);
+}
+
+int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
+                        int refresh)
 {
        struct objdump_line *pos, *n;
-       struct objdump_line_rb_node *rbpos;
-       LIST_HEAD(head);
+       struct annotation *notes = symbol__annotation(sym);
        struct annotate_browser browser = {
                .b = {
-                       .entries = &head,
+                       .entries = &notes->src->source,
                        .refresh = ui_browser__list_head_refresh,
                        .seek    = ui_browser__list_head_seek,
                        .write   = annotate_browser__write,
-                       .priv    = self,
+                       .priv    = sym,
                },
        };
        int ret;
 
-       if (self->ms.sym == NULL)
+       if (sym == NULL)
                return -1;
 
-       if (self->ms.map->dso->annotate_warned)
+       if (map->dso->annotate_warned)
                return -1;
 
-       if (hist_entry__annotate(self, &head, sizeof(*rbpos)) < 0) {
+       if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) {
                ui__error_window(ui_helpline__last_msg);
                return -1;
        }
 
        ui_helpline__push("Press <- or ESC to exit");
 
-       list_for_each_entry(pos, &head, node) {
+       list_for_each_entry(pos, &notes->src->source, node) {
+               struct objdump_line_rb_node *rbpos;
                size_t line_len = strlen(pos->line);
+
                if (browser.b.width < line_len)
                        browser.b.width = line_len;
                rbpos = objdump_line__rb(pos);
                rbpos->idx = browser.b.nr_entries++;
-               rbpos->percent = objdump_line__calc_percent(pos, &head, self->ms.sym);
-               if (rbpos->percent < 0.01)
-                       continue;
-               objdump__insert_line(&browser.entries, rbpos);
        }
 
-       /*
-        * Position the browser at the hottest line.
-        */
-       browser.curr_hot = rb_last(&browser.entries);
-       if (browser.curr_hot)
-               annotate_browser__set_top(&browser, browser.curr_hot);
-
        browser.b.width += 18; /* Percentage */
-       ret = annotate_browser__run(&browser);
-       list_for_each_entry_safe(pos, n, &head, node) {
+       ret = annotate_browser__run(&browser, evidx, refresh);
+       list_for_each_entry_safe(pos, n, &notes->src->source, node) {
                list_del(&pos->node);
                objdump_line__free(pos);
        }
index 60c463c..798efdc 100644 (file)
@@ -7,6 +7,8 @@
 #include <newt.h>
 #include <linux/rbtree.h>
 
+#include "../../evsel.h"
+#include "../../evlist.h"
 #include "../../hist.h"
 #include "../../pstack.h"
 #include "../../sort.h"
@@ -292,7 +294,8 @@ static int hist_browser__run(struct hist_browser *self, const char *title)
 {
        int key;
        int exit_keys[] = { 'a', '?', 'h', 'C', 'd', 'D', 'E', 't',
-                           NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT, 0, };
+                           NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT,
+                           NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0, };
 
        self->b.entries = &self->hists->entries;
        self->b.nr_entries = self->hists->nr_entries;
@@ -377,7 +380,7 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
        while (node) {
                struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
                struct rb_node *next = rb_next(node);
-               u64 cumul = cumul_hits(child);
+               u64 cumul = callchain_cumul_hits(child);
                struct callchain_list *chain;
                char folded_sign = ' ';
                int first = true;
@@ -638,6 +641,9 @@ static void ui_browser__hists_seek(struct ui_browser *self,
        struct rb_node *nd;
        bool first = true;
 
+       if (self->nr_entries == 0)
+               return;
+
        switch (whence) {
        case SEEK_SET:
                nd = hists__filter_entries(rb_first(self->entries));
@@ -797,8 +803,11 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size,
        return printed;
 }
 
-int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
+static int perf_evsel__hists_browse(struct perf_evsel *evsel,
+                                   const char *helpline, const char *ev_name,
+                                   bool left_exits)
 {
+       struct hists *self = &evsel->hists;
        struct hist_browser *browser = hist_browser__new(self);
        struct pstack *fstack;
        const struct thread *thread_filter = NULL;
@@ -818,8 +827,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
        hists__browser_title(self, msg, sizeof(msg), ev_name,
                             dso_filter, thread_filter);
        while (1) {
-               const struct thread *thread;
-               const struct dso *dso;
+               const struct thread *thread = NULL;
+               const struct dso *dso = NULL;
                char *options[16];
                int nr_options = 0, choice = 0, i,
                    annotate = -2, zoom_dso = -2, zoom_thread = -2,
@@ -827,8 +836,10 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
 
                key = hist_browser__run(browser, msg);
 
-               thread = hist_browser__selected_thread(browser);
-               dso = browser->selection->map ? browser->selection->map->dso : NULL;
+               if (browser->he_selection != NULL) {
+                       thread = hist_browser__selected_thread(browser);
+                       dso = browser->selection->map ? browser->selection->map->dso : NULL;
+               }
 
                switch (key) {
                case NEWT_KEY_TAB:
@@ -839,7 +850,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
                         */
                        goto out_free_stack;
                case 'a':
-                       if (browser->selection->map == NULL &&
+                       if (browser->selection == NULL ||
+                           browser->selection->map == NULL ||
                            browser->selection->map->dso->annotate_warned)
                                continue;
                        goto do_annotate;
@@ -858,6 +870,7 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
                                        "E         Expand all callchains\n"
                                        "d         Zoom into current DSO\n"
                                        "t         Zoom into current Thread\n"
+                                       "TAB/UNTAB Switch events\n"
                                        "q/CTRL+C  Exit browser");
                        continue;
                case NEWT_KEY_ENTER:
@@ -867,8 +880,14 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
                case NEWT_KEY_LEFT: {
                        const void *top;
 
-                       if (pstack__empty(fstack))
+                       if (pstack__empty(fstack)) {
+                               /*
+                                * Go back to the perf_evsel_menu__run or other user
+                                */
+                               if (left_exits)
+                                       goto out_free_stack;
                                continue;
+                       }
                        top = pstack__pop(fstack);
                        if (top == &dso_filter)
                                goto zoom_out_dso;
@@ -877,14 +896,16 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
                        continue;
                }
                case NEWT_KEY_ESCAPE:
-                       if (!ui__dialog_yesno("Do you really want to exit?"))
+                       if (!left_exits &&
+                           !ui__dialog_yesno("Do you really want to exit?"))
                                continue;
                        /* Fall thru */
                default:
                        goto out_free_stack;
                }
 
-               if (browser->selection->sym != NULL &&
+               if (browser->selection != NULL &&
+                   browser->selection->sym != NULL &&
                    !browser->selection->map->dso->annotate_warned &&
                    asprintf(&options[nr_options], "Annotate %s",
                             browser->selection->sym->name) > 0)
@@ -903,7 +924,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
                             (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
                        zoom_dso = nr_options++;
 
-               if (browser->selection->map != NULL &&
+               if (browser->selection != NULL &&
+                   browser->selection->map != NULL &&
                    asprintf(&options[nr_options], "Browse map details") > 0)
                        browse_map = nr_options++;
 
@@ -923,19 +945,11 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
                if (choice == annotate) {
                        struct hist_entry *he;
 do_annotate:
-                       if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) {
-                               browser->selection->map->dso->annotate_warned = 1;
-                               ui_helpline__puts("No vmlinux file found, can't "
-                                                "annotate with just a "
-                                                "kallsyms file");
-                               continue;
-                       }
-
                        he = hist_browser__selected_entry(browser);
                        if (he == NULL)
                                continue;
 
-                       hist_entry__tui_annotate(he);
+                       hist_entry__tui_annotate(he, evsel->idx);
                } else if (choice == browse_map)
                        map__browse(browser->selection->map);
                else if (choice == zoom_dso) {
@@ -984,30 +998,141 @@ out:
        return key;
 }
 
-int hists__tui_browse_tree(struct rb_root *self, const char *help)
+struct perf_evsel_menu {
+       struct ui_browser b;
+       struct perf_evsel *selection;
+};
+
+static void perf_evsel_menu__write(struct ui_browser *browser,
+                                  void *entry, int row)
+{
+       struct perf_evsel_menu *menu = container_of(browser,
+                                                   struct perf_evsel_menu, b);
+       struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
+       bool current_entry = ui_browser__is_current_entry(browser, row);
+       unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
+       const char *ev_name = event_name(evsel);
+       char bf[256], unit;
+
+       ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
+                                                      HE_COLORSET_NORMAL);
+
+       nr_events = convert_unit(nr_events, &unit);
+       snprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
+                unit, unit == ' ' ? "" : " ", ev_name);
+       slsmg_write_nstring(bf, browser->width);
+
+       if (current_entry)
+               menu->selection = evsel;
+}
+
+static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help)
 {
-       struct rb_node *first = rb_first(self), *nd = first, *next;
-       int key = 0;
+       int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, };
+       struct perf_evlist *evlist = menu->b.priv;
+       struct perf_evsel *pos;
+       const char *ev_name, *title = "Available samples";
+       int key;
+
+       if (ui_browser__show(&menu->b, title,
+                            "ESC: exit, ENTER|->: Browse histograms") < 0)
+               return -1;
+
+       ui_browser__add_exit_keys(&menu->b, exit_keys);
 
-       while (nd) {
-               struct hists *hists = rb_entry(nd, struct hists, rb_node);
-               const char *ev_name = __event_name(hists->type, hists->config);
+       while (1) {
+               key = ui_browser__run(&menu->b);
 
-               key = hists__browse(hists, help, ev_name);
                switch (key) {
-               case NEWT_KEY_TAB:
-                       next = rb_next(nd);
-                       if (next)
-                               nd = next;
+               case NEWT_KEY_RIGHT:
+               case NEWT_KEY_ENTER:
+                       if (!menu->selection)
+                               continue;
+                       pos = menu->selection;
+browse_hists:
+                       ev_name = event_name(pos);
+                       key = perf_evsel__hists_browse(pos, help, ev_name, true);
+                       ui_browser__show_title(&menu->b, title);
                        break;
-               case NEWT_KEY_UNTAB:
-                       if (nd == first)
+               case NEWT_KEY_LEFT:
+                       continue;
+               case NEWT_KEY_ESCAPE:
+                       if (!ui__dialog_yesno("Do you really want to exit?"))
                                continue;
-                       nd = rb_prev(nd);
+                       /* Fall thru */
+               default:
+                       goto out;
+               }
+
+               switch (key) {
+               case NEWT_KEY_TAB:
+                       if (pos->node.next == &evlist->entries)
+                               pos = list_entry(evlist->entries.next, struct perf_evsel, node);
+                       else
+                               pos = list_entry(pos->node.next, struct perf_evsel, node);
+                       goto browse_hists;
+               case NEWT_KEY_UNTAB:
+                       if (pos->node.prev == &evlist->entries)
+                               pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
+                       else
+                               pos = list_entry(pos->node.prev, struct perf_evsel, node);
+                       goto browse_hists;
+               case 'q':
+               case CTRL('c'):
+                       goto out;
                default:
-                       return key;
+                       break;
                }
        }
 
+out:
+       ui_browser__hide(&menu->b);
        return key;
 }
+
+static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
+                                          const char *help)
+{
+       struct perf_evsel *pos;
+       struct perf_evsel_menu menu = {
+               .b = {
+                       .entries    = &evlist->entries,
+                       .refresh    = ui_browser__list_head_refresh,
+                       .seek       = ui_browser__list_head_seek,
+                       .write      = perf_evsel_menu__write,
+                       .nr_entries = evlist->nr_entries,
+                       .priv       = evlist,
+               },
+       };
+
+       ui_helpline__push("Press ESC to exit");
+
+       list_for_each_entry(pos, &evlist->entries, node) {
+               const char *ev_name = event_name(pos);
+               size_t line_len = strlen(ev_name) + 7;
+
+               if (menu.b.width < line_len)
+                       menu.b.width = line_len;
+               /*
+                * Cache the evsel name, tracepoints have a _high_ cost per
+                * event_name() call.
+                */
+               if (pos->name == NULL)
+                       pos->name = strdup(ev_name);
+       }
+
+       return perf_evsel_menu__run(&menu, help);
+}
+
+int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help)
+{
+
+       if (evlist->nr_entries == 1) {
+               struct perf_evsel *first = list_entry(evlist->entries.next,
+                                                     struct perf_evsel, node);
+               const char *ev_name = event_name(first);
+               return perf_evsel__hists_browse(first, help, ev_name, false);
+       }
+
+       return __perf_evlist__tui_browse_hists(evlist, help);
+}
index e515836..8462bff 100644 (file)
@@ -41,7 +41,7 @@ static int ui_entry__read(const char *title, char *bf, size_t size, int width)
 out_free_form:
        newtPopWindow();
        newtFormDestroy(form);
-       return 0;
+       return err;
 }
 
 struct map_browser {
diff --git a/tools/perf/util/ui/browsers/top.c b/tools/perf/util/ui/browsers/top.c
new file mode 100644 (file)
index 0000000..5a06538
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
+ *
+ * Parts came from builtin-{top,stat,record}.c, see those files for further
+ * copyright notes.
+ *
+ * Released under the GPL v2. (and only v2, not any later version)
+ */
+#include "../browser.h"
+#include "../../annotate.h"
+#include "../helpline.h"
+#include "../libslang.h"
+#include "../util.h"
+#include "../../evlist.h"
+#include "../../hist.h"
+#include "../../sort.h"
+#include "../../symbol.h"
+#include "../../top.h"
+
+struct perf_top_browser {
+       struct ui_browser b;
+       struct rb_root    root;
+       struct sym_entry  *selection;
+       float             sum_ksamples;
+       int               dso_width;
+       int               dso_short_width;
+       int               sym_width;
+};
+
+static void perf_top_browser__write(struct ui_browser *browser, void *entry, int row)
+{
+       struct perf_top_browser *top_browser = container_of(browser, struct perf_top_browser, b);
+       struct sym_entry *syme = rb_entry(entry, struct sym_entry, rb_node);
+       bool current_entry = ui_browser__is_current_entry(browser, row);
+       struct symbol *symbol = sym_entry__symbol(syme);
+       struct perf_top *top = browser->priv;
+       int width = browser->width;
+       double pcnt;
+
+       pcnt = 100.0 - (100.0 * ((top_browser->sum_ksamples - syme->snap_count) /
+                                top_browser->sum_ksamples));
+       ui_browser__set_percent_color(browser, pcnt, current_entry);
+
+       if (top->evlist->nr_entries == 1 || !top->display_weighted) {
+               slsmg_printf("%20.2f ", syme->weight);
+               width -= 24;
+       } else {
+               slsmg_printf("%9.1f %10ld ", syme->weight, syme->snap_count);
+               width -= 23;
+       }
+
+       slsmg_printf("%4.1f%%", pcnt);
+       width -= 7;
+
+       if (verbose) {
+               slsmg_printf(" %016" PRIx64, symbol->start);
+               width -= 17;
+       }
+
+       slsmg_printf(" %-*.*s ", top_browser->sym_width, top_browser->sym_width,
+                    symbol->name);
+       width -= top_browser->sym_width;
+       slsmg_write_nstring(width >= syme->map->dso->long_name_len ?
+                               syme->map->dso->long_name :
+                               syme->map->dso->short_name, width);
+
+       if (current_entry)
+               top_browser->selection = syme;
+}
+
+static void perf_top_browser__update_rb_tree(struct perf_top_browser *browser)
+{
+       struct perf_top *top = browser->b.priv;
+       u64 top_idx = browser->b.top_idx;
+
+       browser->root = RB_ROOT;
+       browser->b.top = NULL;
+       browser->sum_ksamples = perf_top__decay_samples(top, &browser->root);
+       /*
+        * No active symbols
+        */
+       if (top->rb_entries == 0)
+               return;
+
+       perf_top__find_widths(top, &browser->root, &browser->dso_width,
+                             &browser->dso_short_width,
+                              &browser->sym_width);
+       if (browser->sym_width + browser->dso_width > browser->b.width - 29) {
+               browser->dso_width = browser->dso_short_width;
+               if (browser->sym_width + browser->dso_width > browser->b.width - 29)
+                       browser->sym_width = browser->b.width - browser->dso_width - 29;
+       }
+
+       /*
+        * Adjust the ui_browser indexes since the entries in the browser->root
+        * rb_tree may have changed, then seek it from start, so that we get a
+        * possible new top of the screen.
+        */
+       browser->b.nr_entries = top->rb_entries;
+
+       if (top_idx >= browser->b.nr_entries) {
+               if (browser->b.height >= browser->b.nr_entries)
+                       top_idx = browser->b.nr_entries - browser->b.height;
+               else
+                       top_idx = 0;
+       }
+
+       if (browser->b.index >= top_idx + browser->b.height)
+               browser->b.index = top_idx + browser->b.index - browser->b.top_idx;
+
+       if (browser->b.index >= browser->b.nr_entries)
+               browser->b.index = browser->b.nr_entries - 1;
+
+       browser->b.top_idx = top_idx;
+       browser->b.seek(&browser->b, top_idx, SEEK_SET);
+}
+
+static void perf_top_browser__annotate(struct perf_top_browser *browser)
+{
+       struct sym_entry *syme = browser->selection;
+       struct symbol *sym = sym_entry__symbol(syme);
+       struct annotation *notes = symbol__annotation(sym);
+       struct perf_top *top = browser->b.priv;
+
+       if (notes->src != NULL)
+               goto do_annotation;
+
+       pthread_mutex_lock(&notes->lock);
+
+       top->sym_filter_entry = NULL;
+
+       if (symbol__alloc_hist(sym, top->evlist->nr_entries) < 0) {
+               pr_err("Not enough memory for annotating '%s' symbol!\n",
+                      sym->name);
+               pthread_mutex_unlock(&notes->lock);
+               return;
+       }
+
+       top->sym_filter_entry = syme;
+
+       pthread_mutex_unlock(&notes->lock);
+do_annotation:
+       symbol__tui_annotate(sym, syme->map, 0, top->delay_secs * 1000);
+}
+
+static int perf_top_browser__run(struct perf_top_browser *browser)
+{
+       int key;
+       char title[160];
+       struct perf_top *top = browser->b.priv;
+       int delay_msecs = top->delay_secs * 1000;
+       int exit_keys[] = { 'a', NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, };
+
+       perf_top_browser__update_rb_tree(browser);
+        perf_top__header_snprintf(top, title, sizeof(title));
+        perf_top__reset_sample_counters(top);
+
+       if (ui_browser__show(&browser->b, title,
+                            "ESC: exit, ENTER|->|a: Live Annotate") < 0)
+               return -1;
+
+       newtFormSetTimer(browser->b.form, delay_msecs);
+       ui_browser__add_exit_keys(&browser->b, exit_keys);
+
+       while (1) {
+               key = ui_browser__run(&browser->b);
+
+               switch (key) {
+               case -1:
+                       /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */
+                       perf_top_browser__update_rb_tree(browser);
+                       perf_top__header_snprintf(top, title, sizeof(title));
+                       perf_top__reset_sample_counters(top);
+                       ui_browser__set_color(&browser->b, NEWT_COLORSET_ROOT);
+                       SLsmg_gotorc(0, 0);
+                       slsmg_write_nstring(title, browser->b.width);
+                       break;
+               case 'a':
+               case NEWT_KEY_RIGHT:
+               case NEWT_KEY_ENTER:
+                       if (browser->selection)
+                               perf_top_browser__annotate(browser);
+                       break;
+               case NEWT_KEY_LEFT:
+                       continue;
+               case NEWT_KEY_ESCAPE:
+                       if (!ui__dialog_yesno("Do you really want to exit?"))
+                               continue;
+                       /* Fall thru */
+               default:
+                       goto out;
+               }
+       }
+out:
+       ui_browser__hide(&browser->b);
+       return key;
+}
+
+int perf_top__tui_browser(struct perf_top *top)
+{
+       struct perf_top_browser browser = {
+               .b = {
+                       .entries = &browser.root,
+                       .refresh = ui_browser__rb_tree_refresh,
+                       .seek    = ui_browser__rb_tree_seek,
+                       .write   = perf_top_browser__write,
+                       .priv    = top,
+               },
+       };
+
+       ui_helpline__push("Press <- or ESC to exit");
+       return perf_top_browser__run(&browser);
+}
index 8d79daa..f36d2ff 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "../debug.h"
 #include "helpline.h"
+#include "ui.h"
 
 void ui_helpline__pop(void)
 {
@@ -55,7 +56,8 @@ int ui_helpline__show_help(const char *format, va_list ap)
        int ret;
        static int backlog;
 
-        ret = vsnprintf(ui_helpline__last_msg + backlog,
+       pthread_mutex_lock(&ui__lock);
+       ret = vsnprintf(ui_helpline__last_msg + backlog,
                        sizeof(ui_helpline__last_msg) - backlog, format, ap);
        backlog += ret;
 
@@ -64,6 +66,7 @@ int ui_helpline__show_help(const char *format, va_list ap)
                newtRefresh();
                backlog = 0;
        }
+       pthread_mutex_unlock(&ui__lock);
 
        return ret;
 }
index 5623da8..2b63e1c 100644 (file)
 
 #if SLANG_VERSION < 20104
 #define slsmg_printf(msg, args...) \
-       SLsmg_printf((char *)msg, ##args)
+       SLsmg_printf((char *)(msg), ##args)
 #define slsmg_write_nstring(msg, len) \
-       SLsmg_write_nstring((char *)msg, len)
+       SLsmg_write_nstring((char *)(msg), len)
 #define sltt_set_color(obj, name, fg, bg) \
-       SLtt_set_color(obj,(char *)name, (char *)fg, (char *)bg)
+       SLtt_set_color(obj,(char *)(name), (char *)(fg), (char *)(bg))
 #else
 #define slsmg_printf SLsmg_printf
 #define slsmg_write_nstring SLsmg_write_nstring
index 6620850..ee46d67 100644 (file)
@@ -6,6 +6,9 @@
 #include "../debug.h"
 #include "browser.h"
 #include "helpline.h"
+#include "ui.h"
+
+pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
 
 static void newt_suspend(void *d __used)
 {
@@ -14,11 +17,12 @@ static void newt_suspend(void *d __used)
        newtResume();
 }
 
-void setup_browser(void)
+void setup_browser(bool fallback_to_pager)
 {
        if (!isatty(1) || !use_browser || dump_trace) {
                use_browser = 0;
-               setup_pager();
+               if (fallback_to_pager)
+                       setup_pager();
                return;
        }
 
diff --git a/tools/perf/util/ui/ui.h b/tools/perf/util/ui/ui.h
new file mode 100644 (file)
index 0000000..d264e05
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _PERF_UI_H_
+#define _PERF_UI_H_ 1
+
+#include <pthread.h>
+
+extern pthread_mutex_t ui__lock;
+
+#endif /* _PERF_UI_H_ */
index 7b5a892..fdf1fc8 100644 (file)
@@ -9,6 +9,7 @@
 #include "../debug.h"
 #include "browser.h"
 #include "helpline.h"
+#include "ui.h"
 #include "util.h"
 
 static void newt_form__set_exit_keys(newtComponent self)
@@ -118,10 +119,12 @@ void ui__warning(const char *format, ...)
        va_list args;
 
        va_start(args, format);
-       if (use_browser > 0)
+       if (use_browser > 0) {
+               pthread_mutex_lock(&ui__lock);
                newtWinMessagev((char *)warning_str, (char *)ok,
                                (char *)format, args);
-       else
+               pthread_mutex_unlock(&ui__lock);
+       } else
                vfprintf(stderr, format, args);
        va_end(args);
 }
index e833f26..fc78428 100644 (file)
@@ -70,9 +70,7 @@
 #include <sys/poll.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
-#ifndef NO_SYS_SELECT_H
 #include <sys/select.h>
-#endif
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
 #include "types.h"
 #include <sys/ttydefaults.h>
 
-#ifndef NO_ICONV
-#include <iconv.h>
-#endif
-
 extern const char *graph_line;
 extern const char *graph_dotted_line;
 extern char buildid_dir[];
@@ -236,26 +230,6 @@ static inline int sane_case(int x, int high)
        return x;
 }
 
-#ifndef DIR_HAS_BSD_GROUP_SEMANTICS
-# define FORCE_DIR_SET_GID S_ISGID
-#else
-# define FORCE_DIR_SET_GID 0
-#endif
-
-#ifdef NO_NSEC
-#undef USE_NSEC
-#define ST_CTIME_NSEC(st) 0
-#define ST_MTIME_NSEC(st) 0
-#else
-#ifdef USE_ST_TIMESPEC
-#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctimespec.tv_nsec))
-#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtimespec.tv_nsec))
-#else
-#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctim.tv_nsec))
-#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtim.tv_nsec))
-#endif
-#endif
-
 int mkdir_p(char *path, mode_t mode);
 int copyfile(const char *from, const char *to);
 
index 4c6983d..362a0cb 100644 (file)
@@ -72,7 +72,7 @@ int need_reinitialize;
 
 int num_cpus;
 
-typedef struct per_cpu_counters {
+struct counters {
        unsigned long long tsc;         /* per thread */
        unsigned long long aperf;       /* per thread */
        unsigned long long mperf;       /* per thread */
@@ -88,13 +88,13 @@ typedef struct per_cpu_counters {
        int pkg;
        int core;
        int cpu;
-       struct per_cpu_counters *next;
-} PCC;
+       struct counters *next;
+};
 
-PCC *pcc_even;
-PCC *pcc_odd;
-PCC *pcc_delta;
-PCC *pcc_average;
+struct counters *cnt_even;
+struct counters *cnt_odd;
+struct counters *cnt_delta;
+struct counters *cnt_average;
 struct timeval tv_even;
 struct timeval tv_odd;
 struct timeval tv_delta;
@@ -125,7 +125,7 @@ unsigned long long get_msr(int cpu, off_t offset)
        return msr;
 }
 
-void print_header()
+void print_header(void)
 {
        if (show_pkg)
                fprintf(stderr, "pkg ");
@@ -160,39 +160,39 @@ void print_header()
        putc('\n', stderr);
 }
 
-void dump_pcc(PCC *pcc)
+void dump_cnt(struct counters *cnt)
 {
-       fprintf(stderr, "package: %d ", pcc->pkg);
-       fprintf(stderr, "core:: %d ", pcc->core);
-       fprintf(stderr, "CPU: %d ", pcc->cpu);
-       fprintf(stderr, "TSC: %016llX\n", pcc->tsc);
-       fprintf(stderr, "c3: %016llX\n", pcc->c3);
-       fprintf(stderr, "c6: %016llX\n", pcc->c6);
-       fprintf(stderr, "c7: %016llX\n", pcc->c7);
-       fprintf(stderr, "aperf: %016llX\n", pcc->aperf);
-       fprintf(stderr, "pc2: %016llX\n", pcc->pc2);
-       fprintf(stderr, "pc3: %016llX\n", pcc->pc3);
-       fprintf(stderr, "pc6: %016llX\n", pcc->pc6);
-       fprintf(stderr, "pc7: %016llX\n", pcc->pc7);
-       fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, pcc->extra_msr);
+       fprintf(stderr, "package: %d ", cnt->pkg);
+       fprintf(stderr, "core:: %d ", cnt->core);
+       fprintf(stderr, "CPU: %d ", cnt->cpu);
+       fprintf(stderr, "TSC: %016llX\n", cnt->tsc);
+       fprintf(stderr, "c3: %016llX\n", cnt->c3);
+       fprintf(stderr, "c6: %016llX\n", cnt->c6);
+       fprintf(stderr, "c7: %016llX\n", cnt->c7);
+       fprintf(stderr, "aperf: %016llX\n", cnt->aperf);
+       fprintf(stderr, "pc2: %016llX\n", cnt->pc2);
+       fprintf(stderr, "pc3: %016llX\n", cnt->pc3);
+       fprintf(stderr, "pc6: %016llX\n", cnt->pc6);
+       fprintf(stderr, "pc7: %016llX\n", cnt->pc7);
+       fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, cnt->extra_msr);
 }
 
-void dump_list(PCC *pcc)
+void dump_list(struct counters *cnt)
 {
-       printf("dump_list 0x%p\n", pcc);
+       printf("dump_list 0x%p\n", cnt);
 
-       for (; pcc; pcc = pcc->next)
-               dump_pcc(pcc);
+       for (; cnt; cnt = cnt->next)
+               dump_cnt(cnt);
 }
 
-void print_pcc(PCC *p)
+void print_cnt(struct counters *p)
 {
        double interval_float;
 
        interval_float = tv_delta.tv_sec + tv_delta.tv_usec/1000000.0;
 
        /* topology columns, print blanks on 1st (average) line */
-       if (p == pcc_average) {
+       if (p == cnt_average) {
                if (show_pkg)
                        fprintf(stderr, "    ");
                if (show_core)
@@ -262,24 +262,24 @@ void print_pcc(PCC *p)
        putc('\n', stderr);
 }
 
-void print_counters(PCC *cnt)
+void print_counters(struct counters *counters)
 {
-       PCC *pcc;
+       struct counters *cnt;
 
        print_header();
 
        if (num_cpus > 1)
-               print_pcc(pcc_average);
+               print_cnt(cnt_average);
 
-       for (pcc = cnt; pcc != NULL; pcc = pcc->next)
-               print_pcc(pcc);
+       for (cnt = counters; cnt != NULL; cnt = cnt->next)
+               print_cnt(cnt);
 
 }
 
 #define SUBTRACT_COUNTER(after, before, delta) (delta = (after - before), (before > after))
 
-
-int compute_delta(PCC *after, PCC *before, PCC *delta)
+int compute_delta(struct counters *after,
+       struct counters *before, struct counters *delta)
 {
        int errors = 0;
        int perf_err = 0;
@@ -391,20 +391,20 @@ int compute_delta(PCC *after, PCC *before, PCC *delta)
                delta->extra_msr = after->extra_msr;
                if (errors) {
                        fprintf(stderr, "ERROR cpu%d before:\n", before->cpu);
-                       dump_pcc(before);
+                       dump_cnt(before);
                        fprintf(stderr, "ERROR cpu%d after:\n", before->cpu);
-                       dump_pcc(after);
+                       dump_cnt(after);
                        errors = 0;
                }
        }
        return 0;
 }
 
-void compute_average(PCC *delta, PCC *avg)
+void compute_average(struct counters *delta, struct counters *avg)
 {
-       PCC *sum;
+       struct counters *sum;
 
-       sum = calloc(1, sizeof(PCC));
+       sum = calloc(1, sizeof(struct counters));
        if (sum == NULL) {
                perror("calloc sum");
                exit(1);
@@ -438,35 +438,34 @@ void compute_average(PCC *delta, PCC *avg)
        free(sum);
 }
 
-void get_counters(PCC *pcc)
+void get_counters(struct counters *cnt)
 {
-       for ( ; pcc; pcc = pcc->next) {
-               pcc->tsc = get_msr(pcc->cpu, MSR_TSC);
+       for ( ; cnt; cnt = cnt->next) {
+               cnt->tsc = get_msr(cnt->cpu, MSR_TSC);
                if (do_nhm_cstates)
-                       pcc->c3 = get_msr(pcc->cpu, MSR_CORE_C3_RESIDENCY);
+                       cnt->c3 = get_msr(cnt->cpu, MSR_CORE_C3_RESIDENCY);
                if (do_nhm_cstates)
-                       pcc->c6 = get_msr(pcc->cpu, MSR_CORE_C6_RESIDENCY);
+                       cnt->c6 = get_msr(cnt->cpu, MSR_CORE_C6_RESIDENCY);
                if (do_snb_cstates)
-                       pcc->c7 = get_msr(pcc->cpu, MSR_CORE_C7_RESIDENCY);
+                       cnt->c7 = get_msr(cnt->cpu, MSR_CORE_C7_RESIDENCY);
                if (has_aperf)
-                       pcc->aperf = get_msr(pcc->cpu, MSR_APERF);
+                       cnt->aperf = get_msr(cnt->cpu, MSR_APERF);
                if (has_aperf)
-                       pcc->mperf = get_msr(pcc->cpu, MSR_MPERF);
+                       cnt->mperf = get_msr(cnt->cpu, MSR_MPERF);
                if (do_snb_cstates)
-                       pcc->pc2 = get_msr(pcc->cpu, MSR_PKG_C2_RESIDENCY);
+                       cnt->pc2 = get_msr(cnt->cpu, MSR_PKG_C2_RESIDENCY);
                if (do_nhm_cstates)
-                       pcc->pc3 = get_msr(pcc->cpu, MSR_PKG_C3_RESIDENCY);
+                       cnt->pc3 = get_msr(cnt->cpu, MSR_PKG_C3_RESIDENCY);
                if (do_nhm_cstates)
-                       pcc->pc6 = get_msr(pcc->cpu, MSR_PKG_C6_RESIDENCY);
+                       cnt->pc6 = get_msr(cnt->cpu, MSR_PKG_C6_RESIDENCY);
                if (do_snb_cstates)
-                       pcc->pc7 = get_msr(pcc->cpu, MSR_PKG_C7_RESIDENCY);
+                       cnt->pc7 = get_msr(cnt->cpu, MSR_PKG_C7_RESIDENCY);
                if (extra_msr_offset)
-                       pcc->extra_msr = get_msr(pcc->cpu, extra_msr_offset);
+                       cnt->extra_msr = get_msr(cnt->cpu, extra_msr_offset);
        }
 }
 
-
-void print_nehalem_info()
+void print_nehalem_info(void)
 {
        unsigned long long msr;
        unsigned int ratio;
@@ -514,38 +513,38 @@ void print_nehalem_info()
 
 }
 
-void free_counter_list(PCC *list)
+void free_counter_list(struct counters *list)
 {
-       PCC *p;
+       struct counters *p;
 
        for (p = list; p; ) {
-               PCC *free_me;
+               struct counters *free_me;
 
                free_me = p;
                p = p->next;
                free(free_me);
        }
-       return;
 }
 
 void free_all_counters(void)
 {
-       free_counter_list(pcc_even);
-       pcc_even = NULL;
+       free_counter_list(cnt_even);
+       cnt_even = NULL;
 
-       free_counter_list(pcc_odd);
-       pcc_odd = NULL;
+       free_counter_list(cnt_odd);
+       cnt_odd = NULL;
 
-       free_counter_list(pcc_delta);
-       pcc_delta = NULL;
+       free_counter_list(cnt_delta);
+       cnt_delta = NULL;
 
-       free_counter_list(pcc_average);
-       pcc_average = NULL;
+       free_counter_list(cnt_average);
+       cnt_average = NULL;
 }
 
-void insert_cpu_counters(PCC **list, PCC *new)
+void insert_counters(struct counters **list,
+       struct counters *new)
 {
-       PCC *prev;
+       struct counters *prev;
 
        /*
         * list was empty
@@ -594,18 +593,16 @@ void insert_cpu_counters(PCC **list, PCC *new)
         */
        new->next = prev->next;
        prev->next = new;
-
-       return;
 }
 
-void alloc_new_cpu_counters(int pkg, int core, int cpu)
+void alloc_new_counters(int pkg, int core, int cpu)
 {
-       PCC *new;
+       struct counters *new;
 
        if (verbose > 1)
                printf("pkg%d core%d, cpu%d\n", pkg, core, cpu);
 
-       new = (PCC *)calloc(1, sizeof(PCC));
+       new = (struct counters *)calloc(1, sizeof(struct counters));
        if (new == NULL) {
                perror("calloc");
                exit(1);
@@ -613,9 +610,10 @@ void alloc_new_cpu_counters(int pkg, int core, int cpu)
        new->pkg = pkg;
        new->core = core;
        new->cpu = cpu;
-       insert_cpu_counters(&pcc_odd, new);
+       insert_counters(&cnt_odd, new);
 
-       new = (PCC *)calloc(1, sizeof(PCC));
+       new = (struct counters *)calloc(1,
+               sizeof(struct counters));
        if (new == NULL) {
                perror("calloc");
                exit(1);
@@ -623,9 +621,9 @@ void alloc_new_cpu_counters(int pkg, int core, int cpu)
        new->pkg = pkg;
        new->core = core;
        new->cpu = cpu;
-       insert_cpu_counters(&pcc_even, new);
+       insert_counters(&cnt_even, new);
 
-       new = (PCC *)calloc(1, sizeof(PCC));
+       new = (struct counters *)calloc(1, sizeof(struct counters));
        if (new == NULL) {
                perror("calloc");
                exit(1);
@@ -633,9 +631,9 @@ void alloc_new_cpu_counters(int pkg, int core, int cpu)
        new->pkg = pkg;
        new->core = core;
        new->cpu = cpu;
-       insert_cpu_counters(&pcc_delta, new);
+       insert_counters(&cnt_delta, new);
 
-       new = (PCC *)calloc(1, sizeof(PCC));
+       new = (struct counters *)calloc(1, sizeof(struct counters));
        if (new == NULL) {
                perror("calloc");
                exit(1);
@@ -643,7 +641,7 @@ void alloc_new_cpu_counters(int pkg, int core, int cpu)
        new->pkg = pkg;
        new->core = core;
        new->cpu = cpu;
-       pcc_average = new;
+       cnt_average = new;
 }
 
 int get_physical_package_id(int cpu)
@@ -719,7 +717,7 @@ void re_initialize(void)
 {
        printf("turbostat: topology changed, re-initializing.\n");
        free_all_counters();
-       num_cpus = for_all_cpus(alloc_new_cpu_counters);
+       num_cpus = for_all_cpus(alloc_new_counters);
        need_reinitialize = 0;
        printf("num_cpus is now %d\n", num_cpus);
 }
@@ -728,7 +726,7 @@ void dummy(int pkg, int core, int cpu) { return; }
 /*
  * check to see if a cpu came on-line
  */
-void verify_num_cpus()
+void verify_num_cpus(void)
 {
        int new_num_cpus;
 
@@ -740,14 +738,12 @@ void verify_num_cpus()
                                num_cpus, new_num_cpus);
                need_reinitialize = 1;
        }
-
-       return;
 }
 
 void turbostat_loop()
 {
 restart:
-       get_counters(pcc_even);
+       get_counters(cnt_even);
        gettimeofday(&tv_even, (struct timezone *)NULL);
 
        while (1) {
@@ -757,24 +753,24 @@ restart:
                        goto restart;
                }
                sleep(interval_sec);
-               get_counters(pcc_odd);
+               get_counters(cnt_odd);
                gettimeofday(&tv_odd, (struct timezone *)NULL);
 
-               compute_delta(pcc_odd, pcc_even, pcc_delta);
+               compute_delta(cnt_odd, cnt_even, cnt_delta);
                timersub(&tv_odd, &tv_even, &tv_delta);
-               compute_average(pcc_delta, pcc_average);
-               print_counters(pcc_delta);
+               compute_average(cnt_delta, cnt_average);
+               print_counters(cnt_delta);
                if (need_reinitialize) {
                        re_initialize();
                        goto restart;
                }
                sleep(interval_sec);
-               get_counters(pcc_even);
+               get_counters(cnt_even);
                gettimeofday(&tv_even, (struct timezone *)NULL);
-               compute_delta(pcc_even, pcc_odd, pcc_delta);
+               compute_delta(cnt_even, cnt_odd, cnt_delta);
                timersub(&tv_even, &tv_odd, &tv_delta);
-               compute_average(pcc_delta, pcc_average);
-               print_counters(pcc_delta);
+               compute_average(cnt_delta, cnt_average);
+               print_counters(cnt_delta);
        }
 }
 
@@ -892,7 +888,7 @@ void check_cpuid()
         * this check is valid for both Intel and AMD
         */
        asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000007));
-       has_invariant_tsc = edx && (1 << 8);
+       has_invariant_tsc = edx & (1 << 8);
 
        if (!has_invariant_tsc) {
                fprintf(stderr, "No invariant TSC\n");
@@ -905,7 +901,7 @@ void check_cpuid()
         */
 
        asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x6));
-       has_aperf = ecx && (1 << 0);
+       has_aperf = ecx & (1 << 0);
        if (!has_aperf) {
                fprintf(stderr, "No APERF MSR\n");
                exit(1);
@@ -952,7 +948,7 @@ void turbostat_init()
        check_dev_msr();
        check_super_user();
 
-       num_cpus = for_all_cpus(alloc_new_cpu_counters);
+       num_cpus = for_all_cpus(alloc_new_counters);
 
        if (verbose)
                print_nehalem_info();
@@ -962,7 +958,7 @@ int fork_it(char **argv)
 {
        int retval;
        pid_t child_pid;
-       get_counters(pcc_even);
+       get_counters(cnt_even);
        gettimeofday(&tv_even, (struct timezone *)NULL);
 
        child_pid = fork();
@@ -985,14 +981,14 @@ int fork_it(char **argv)
                        exit(1);
                }
        }
-       get_counters(pcc_odd);
+       get_counters(cnt_odd);
        gettimeofday(&tv_odd, (struct timezone *)NULL);
-       retval = compute_delta(pcc_odd, pcc_even, pcc_delta);
+       retval = compute_delta(cnt_odd, cnt_even, cnt_delta);
 
        timersub(&tv_odd, &tv_even, &tv_delta);
-       compute_average(pcc_delta, pcc_average);
+       compute_average(cnt_delta, cnt_average);
        if (!retval)
-               print_counters(pcc_delta);
+               print_counters(cnt_delta);
 
        fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0);;
 
index e1c62ee..ba7c63a 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/perl -w
 #
-# Copywrite 2010 - Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
+# Copyright 2010 - Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
 # Licensed under the terms of the GNU GPL License version 2
 #